forked from MeloNX/MeloNX
Add Software Keyboard, Edit maxSets and more
This commit is contained in:
parent
c3ade6f5cd
commit
eb4a4593ea
@ -67,6 +67,7 @@
|
|||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
4E7023A52D5A98E2002C7183 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
|
||||||
4E80A98D2CD6F54500029585 /* MeloNX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MeloNX.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
4E80A98D2CD6F54500029585 /* MeloNX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MeloNX.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
4E80A99D2CD6F54700029585 /* MeloNXTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MeloNXTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
4E80A99D2CD6F54700029585 /* MeloNXTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MeloNXTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
4E80A9A72CD6F54700029585 /* MeloNXUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MeloNXUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
4E80A9A72CD6F54700029585 /* MeloNXUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MeloNXUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
@ -96,7 +97,7 @@
|
|||||||
"Dependencies/Dynamic Libraries/Ryujinx.Headless.SDL2.dylib" = (
|
"Dependencies/Dynamic Libraries/Ryujinx.Headless.SDL2.dylib" = (
|
||||||
CodeSignOnCopy,
|
CodeSignOnCopy,
|
||||||
);
|
);
|
||||||
"Dependencies/Dynamic Libraries/SoftwareKeyboard.framework" = (
|
"Dependencies/Dynamic Libraries/RyujinxKeyboard.framework" = (
|
||||||
CodeSignOnCopy,
|
CodeSignOnCopy,
|
||||||
RemoveHeadersOnCopy,
|
RemoveHeadersOnCopy,
|
||||||
);
|
);
|
||||||
@ -157,7 +158,7 @@
|
|||||||
"Dependencies/Dynamic Libraries/libavutil.dylib",
|
"Dependencies/Dynamic Libraries/libavutil.dylib",
|
||||||
"Dependencies/Dynamic Libraries/libMoltenVK.dylib",
|
"Dependencies/Dynamic Libraries/libMoltenVK.dylib",
|
||||||
"Dependencies/Dynamic Libraries/Ryujinx.Headless.SDL2.dylib",
|
"Dependencies/Dynamic Libraries/Ryujinx.Headless.SDL2.dylib",
|
||||||
"Dependencies/Dynamic Libraries/SoftwareKeyboard.framework",
|
"Dependencies/Dynamic Libraries/RyujinxKeyboard.framework",
|
||||||
Dependencies/XCFrameworks/libavcodec.xcframework,
|
Dependencies/XCFrameworks/libavcodec.xcframework,
|
||||||
Dependencies/XCFrameworks/libavfilter.xcframework,
|
Dependencies/XCFrameworks/libavfilter.xcframework,
|
||||||
Dependencies/XCFrameworks/libavformat.xcframework,
|
Dependencies/XCFrameworks/libavformat.xcframework,
|
||||||
@ -232,6 +233,7 @@
|
|||||||
4E80AA192CD700F500029585 /* Frameworks */ = {
|
4E80AA192CD700F500029585 /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
4E7023A52D5A98E2002C7183 /* UIKit.framework */,
|
||||||
4E80AA622CD7122800029585 /* GameController.framework */,
|
4E80AA622CD7122800029585 /* GameController.framework */,
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
@ -634,6 +636,10 @@
|
|||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
);
|
);
|
||||||
GCC_OPTIMIZATION_LEVEL = fast;
|
GCC_OPTIMIZATION_LEVEL = fast;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@ -677,6 +683,10 @@
|
|||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 0.0.8;
|
MARKETING_VERSION = 0.0.8;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
||||||
@ -713,6 +723,10 @@
|
|||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
);
|
);
|
||||||
GCC_OPTIMIZATION_LEVEL = fast;
|
GCC_OPTIMIZATION_LEVEL = fast;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@ -756,6 +770,10 @@
|
|||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 0.0.8;
|
MARKETING_VERSION = 0.0.8;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
||||||
|
Binary file not shown.
@ -12,12 +12,12 @@
|
|||||||
<key>Ryujinx.xcscheme_^#shared#^_</key>
|
<key>Ryujinx.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>2</integer>
|
<integer>1</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>com.Stossy11.MeloNX.RyujinxAg.xcscheme_^#shared#^_</key>
|
<key>com.Stossy11.MeloNX.RyujinxAg.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>1</integer>
|
<integer>2</integer>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
<key>SuppressBuildableAutocreation</key>
|
<key>SuppressBuildableAutocreation</key>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
// Created by Stossy11 on 3/11/2024.
|
// Created by Stossy11 on 3/11/2024.
|
||||||
//
|
//
|
||||||
|
|
||||||
#define DRM 1
|
#define DRM 0
|
||||||
#define CS_DEBUGGED 0x10000000
|
#define CS_DEBUGGED 0x10000000
|
||||||
|
|
||||||
#ifndef RyujinxHeader
|
#ifndef RyujinxHeader
|
||||||
|
@ -61,8 +61,8 @@ struct ContentView: View {
|
|||||||
// Metal Private API isn't needed and causes more stutters
|
// Metal Private API isn't needed and causes more stutters
|
||||||
MoltenVKSettings(string: "MVK_USE_METAL_PRIVATE_API", value: "1"),
|
MoltenVKSettings(string: "MVK_USE_METAL_PRIVATE_API", value: "1"),
|
||||||
MoltenVKSettings(string: "MVK_CONFIG_USE_METAL_PRIVATE_API", value: "1"),
|
MoltenVKSettings(string: "MVK_CONFIG_USE_METAL_PRIVATE_API", value: "1"),
|
||||||
MoltenVKSettings(string: "MVK_DEBUG", value: "1"),
|
MoltenVKSettings(string: "MVK_DEBUG", value: "0"),
|
||||||
MoltenVKSettings(string: "MVK_CONFIG_LOG_LEVEL", value: "2"),
|
// MoltenVKSettings(string: "MVK_CONFIG_LOG_LEVEL", value: "0"),
|
||||||
// MVK_CONFIG_LOG_LEVEL
|
// MVK_CONFIG_LOG_LEVEL
|
||||||
//MVK_DEBUG
|
//MVK_DEBUG
|
||||||
// Uses more ram but makes performance higher, may add an option in settings to change or enable / disable this value (default 64 or 192 depending on what i decide)
|
// Uses more ram but makes performance higher, may add an option in settings to change or enable / disable this value (default 64 or 192 depending on what i decide)
|
||||||
@ -116,6 +116,8 @@ struct ContentView: View {
|
|||||||
.onAppear() {
|
.onAppear() {
|
||||||
quits = false
|
quits = false
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
initControllerObservers() // This initializes the Controller Observers that refreshes the controller list when a new controller connecvts.
|
initControllerObservers() // This initializes the Controller Observers that refreshes the controller list when a new controller connecvts.
|
||||||
}
|
}
|
||||||
.onOpenURL() { url in
|
.onOpenURL() { url in
|
||||||
|
@ -195,7 +195,11 @@ struct GameLibraryView: View {
|
|||||||
|
|
||||||
Button {
|
Button {
|
||||||
let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
|
let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
|
||||||
let sharedurl = documentsUrl.absoluteString.replacingOccurrences(of: "file://", with: "shareddocuments://")
|
var sharedurl = documentsUrl.absoluteString.replacingOccurrences(of: "file://", with: "shareddocuments://")
|
||||||
|
if ProcessInfo.processInfo.isiOSAppOnMac {
|
||||||
|
sharedurl = documentsUrl.absoluteString
|
||||||
|
}
|
||||||
|
print(sharedurl)
|
||||||
let furl = URL(string: sharedurl)!
|
let furl = URL(string: sharedurl)!
|
||||||
if UIApplication.shared.canOpenURL(furl) {
|
if UIApplication.shared.canOpenURL(furl) {
|
||||||
UIApplication.shared.open(furl, options: [:])
|
UIApplication.shared.open(furl, options: [:])
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
//
|
||||||
|
// RyujinxKeyboard.h
|
||||||
|
// RyujinxKeyboard
|
||||||
|
//
|
||||||
|
// Created by Stossy11 on 11/02/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
//! Project version number for RyujinxKeyboard.
|
||||||
|
FOUNDATION_EXPORT double RyujinxKeyboardVersionNumber;
|
||||||
|
|
||||||
|
//! Project version string for RyujinxKeyboard.
|
||||||
|
FOUNDATION_EXPORT const unsigned char RyujinxKeyboardVersionString[];
|
||||||
|
|
||||||
|
// In this header, you should import all the public headers of your framework using statements like #import <RyujinxKeyboard/PublicHeader.h>
|
||||||
|
|
||||||
|
|
Binary file not shown.
@ -0,0 +1,6 @@
|
|||||||
|
framework module RyujinxKeyboard {
|
||||||
|
umbrella header "RyujinxKeyboard.h"
|
||||||
|
export *
|
||||||
|
|
||||||
|
module * { export * }
|
||||||
|
}
|
Binary file not shown.
@ -0,0 +1,124 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>files</key>
|
||||||
|
<dict>
|
||||||
|
<key>Headers/RyujinxKeyboard.h</key>
|
||||||
|
<data>
|
||||||
|
5P7GN4g050n199pV6/+SpfMBgJc=
|
||||||
|
</data>
|
||||||
|
<key>Info.plist</key>
|
||||||
|
<data>
|
||||||
|
hYdI/ktAKwjBSfaJpt6Yc8UKLCY=
|
||||||
|
</data>
|
||||||
|
<key>Modules/module.modulemap</key>
|
||||||
|
<data>
|
||||||
|
0kFAMoTn+4Q1J/dM6uMLe3EhbL0=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>files2</key>
|
||||||
|
<dict>
|
||||||
|
<key>Headers/RyujinxKeyboard.h</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
/yGmHq9NdBF/ruesISIj7vml0ySgoJkrFOcrw0vaIxQ=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>Modules/module.modulemap</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
K+ZyxKhTI4bMVZuHBIspvd2PFqvCOlVUFYmwF96O5NQ=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>rules</key>
|
||||||
|
<dict>
|
||||||
|
<key>^.*</key>
|
||||||
|
<true/>
|
||||||
|
<key>^.*\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>optional</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1000</real>
|
||||||
|
</dict>
|
||||||
|
<key>^.*\.lproj/locversion.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1100</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Base\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1010</real>
|
||||||
|
</dict>
|
||||||
|
<key>^version.plist$</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
<key>rules2</key>
|
||||||
|
<dict>
|
||||||
|
<key>.*\.dSYM($|/)</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>11</real>
|
||||||
|
</dict>
|
||||||
|
<key>^(.*/)?\.DS_Store$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>2000</real>
|
||||||
|
</dict>
|
||||||
|
<key>^.*</key>
|
||||||
|
<true/>
|
||||||
|
<key>^.*\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>optional</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1000</real>
|
||||||
|
</dict>
|
||||||
|
<key>^.*\.lproj/locversion.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1100</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Base\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1010</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Info\.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
<key>^PkgInfo$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
<key>^embedded\.provisionprofile$</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
<key>^version\.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
@ -1,18 +0,0 @@
|
|||||||
//
|
|
||||||
// SoftwareKeyboard.h
|
|
||||||
// SoftwareKeyboard
|
|
||||||
//
|
|
||||||
// Created by Stossy11 on 19/12/2024.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
//! Project version number for SoftwareKeyboard.
|
|
||||||
FOUNDATION_EXPORT double SoftwareKeyboardVersionNumber;
|
|
||||||
|
|
||||||
//! Project version string for SoftwareKeyboard.
|
|
||||||
FOUNDATION_EXPORT const unsigned char SoftwareKeyboardVersionString[];
|
|
||||||
|
|
||||||
// In this header, you should import all the public headers of your framework using statements like #import <SoftwareKeyboard/PublicHeader.h>
|
|
||||||
|
|
||||||
|
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -1,38 +0,0 @@
|
|||||||
// swift-interface-format-version: 1.0
|
|
||||||
// swift-compiler-version: Apple Swift version 6.0.3 effective-5.10 (swiftlang-6.0.3.1.4 clang-1600.0.30)
|
|
||||||
// swift-module-flags: -target arm64-apple-ios14.0 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -Onone -enable-experimental-feature OpaqueTypeErasure -enable-bare-slash-regex -module-name SoftwareKeyboard
|
|
||||||
@_exported import SoftwareKeyboard
|
|
||||||
import Swift
|
|
||||||
import UIKit
|
|
||||||
import _Concurrency
|
|
||||||
import _StringProcessing
|
|
||||||
import _SwiftConcurrencyShims
|
|
||||||
@objc public enum KeyboardMode : Swift.UInt32 {
|
|
||||||
case `default` = 0
|
|
||||||
case numeric = 1
|
|
||||||
case ascii = 2
|
|
||||||
case fullLatin = 3
|
|
||||||
case alphabet = 4
|
|
||||||
case simplifiedChinese = 5
|
|
||||||
case traditionalChinese = 6
|
|
||||||
case korean = 7
|
|
||||||
case languageSet2 = 8
|
|
||||||
case languageSet2Latin = 9
|
|
||||||
public init?(rawValue: Swift.UInt32)
|
|
||||||
public typealias RawValue = Swift.UInt32
|
|
||||||
public var rawValue: Swift.UInt32 {
|
|
||||||
get
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public struct SoftwareKeyboardUiArgs {
|
|
||||||
public var keyboardMode: SoftwareKeyboard.KeyboardMode
|
|
||||||
public var headerText: Swift.String
|
|
||||||
public var subtitleText: Swift.String
|
|
||||||
public var submitText: Swift.String
|
|
||||||
public var stringLengthMin: Swift.Int32
|
|
||||||
public var stringLengthMax: Swift.Int32
|
|
||||||
public var initialText: Swift.String?
|
|
||||||
}
|
|
||||||
extension SoftwareKeyboard.KeyboardMode : Swift.Equatable {}
|
|
||||||
extension SoftwareKeyboard.KeyboardMode : Swift.Hashable {}
|
|
||||||
extension SoftwareKeyboard.KeyboardMode : Swift.RawRepresentable {}
|
|
Binary file not shown.
@ -1,38 +0,0 @@
|
|||||||
// swift-interface-format-version: 1.0
|
|
||||||
// swift-compiler-version: Apple Swift version 6.0.3 effective-5.10 (swiftlang-6.0.3.1.4 clang-1600.0.30)
|
|
||||||
// swift-module-flags: -target arm64-apple-ios14.0 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -Onone -enable-experimental-feature OpaqueTypeErasure -enable-bare-slash-regex -module-name SoftwareKeyboard
|
|
||||||
@_exported import SoftwareKeyboard
|
|
||||||
import Swift
|
|
||||||
import UIKit
|
|
||||||
import _Concurrency
|
|
||||||
import _StringProcessing
|
|
||||||
import _SwiftConcurrencyShims
|
|
||||||
@objc public enum KeyboardMode : Swift.UInt32 {
|
|
||||||
case `default` = 0
|
|
||||||
case numeric = 1
|
|
||||||
case ascii = 2
|
|
||||||
case fullLatin = 3
|
|
||||||
case alphabet = 4
|
|
||||||
case simplifiedChinese = 5
|
|
||||||
case traditionalChinese = 6
|
|
||||||
case korean = 7
|
|
||||||
case languageSet2 = 8
|
|
||||||
case languageSet2Latin = 9
|
|
||||||
public init?(rawValue: Swift.UInt32)
|
|
||||||
public typealias RawValue = Swift.UInt32
|
|
||||||
public var rawValue: Swift.UInt32 {
|
|
||||||
get
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public struct SoftwareKeyboardUiArgs {
|
|
||||||
public var keyboardMode: SoftwareKeyboard.KeyboardMode
|
|
||||||
public var headerText: Swift.String
|
|
||||||
public var subtitleText: Swift.String
|
|
||||||
public var submitText: Swift.String
|
|
||||||
public var stringLengthMin: Swift.Int32
|
|
||||||
public var stringLengthMax: Swift.Int32
|
|
||||||
public var initialText: Swift.String?
|
|
||||||
}
|
|
||||||
extension SoftwareKeyboard.KeyboardMode : Swift.Equatable {}
|
|
||||||
extension SoftwareKeyboard.KeyboardMode : Swift.Hashable {}
|
|
||||||
extension SoftwareKeyboard.KeyboardMode : Swift.RawRepresentable {}
|
|
Binary file not shown.
@ -1,6 +0,0 @@
|
|||||||
framework module SoftwareKeyboard {
|
|
||||||
umbrella header "SoftwareKeyboard.h"
|
|
||||||
export *
|
|
||||||
|
|
||||||
module * { export * }
|
|
||||||
}
|
|
Binary file not shown.
@ -21,7 +21,7 @@ struct MeloNXApp: App {
|
|||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
WindowGroup {
|
WindowGroup {
|
||||||
ZStack {
|
ZStack {
|
||||||
if showed {
|
if showed || DRM != 1 {
|
||||||
ContentView()
|
ContentView()
|
||||||
} else {
|
} else {
|
||||||
Group {
|
Group {
|
||||||
@ -137,10 +137,12 @@ struct MeloNXApp: App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func showDMCAAlert() -> UIAlertController? {
|
func showDMCAAlert() -> UIAlertController? {
|
||||||
if let mainWindow = UIApplication.shared.windows.last {
|
if let mainWindow = UIApplication.shared.windows.first {
|
||||||
let alertController = UIAlertController(title: "Unauthorized Copy Notice", message: "This app was illegally leaked. Please report the download on the MeloNX Discord. In the meantime, check out Pomelo! \n -Stossy11", preferredStyle: .alert)
|
let alertController = UIAlertController(title: "Unauthorized Copy Notice", message: "This app was illegally leaked. Please report the download on the MeloNX Discord. In the meantime, check out Pomelo! \n -Stossy11", preferredStyle: .alert)
|
||||||
|
|
||||||
mainWindow.rootViewController!.present(alertController, animated: true, completion: nil)
|
DispatchQueue.main.async {
|
||||||
|
mainWindow.rootViewController!.present(alertController, animated: true, completion: nil)
|
||||||
|
}
|
||||||
|
|
||||||
return alertController
|
return alertController
|
||||||
} else {
|
} else {
|
||||||
|
@ -98,43 +98,10 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
return okPressed;
|
return okPressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DisplayInputDialog(SoftwareKeyboardUiArgs args, out string userText)
|
public void DisplayInputDialog(SoftwareKeyboardUiArgs args, Action<string> onTextEntered)
|
||||||
{
|
{
|
||||||
ManualResetEvent dialogCloseEvent = new(false);
|
onTextEntered?.Invoke("MeloNX");
|
||||||
|
return;
|
||||||
bool okPressed = false;
|
|
||||||
bool error = false;
|
|
||||||
string inputText = args.InitialText ?? "";
|
|
||||||
|
|
||||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var response = await SwkbdAppletDialog.ShowInputDialog(LocaleManager.Instance[LocaleKeys.SoftwareKeyboard], args);
|
|
||||||
|
|
||||||
if (response.Result == UserResult.Ok)
|
|
||||||
{
|
|
||||||
inputText = response.Input;
|
|
||||||
okPressed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
error = true;
|
|
||||||
|
|
||||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogSoftwareKeyboardErrorExceptionMessage, ex));
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
dialogCloseEvent.Set();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
dialogCloseEvent.WaitOne();
|
|
||||||
|
|
||||||
userText = error ? null : inputText;
|
|
||||||
|
|
||||||
return error || okPressed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ExecuteProgram(Switch device, ProgramSpecifyKind kind, ulong value)
|
public void ExecuteProgram(Switch device, ProgramSpecifyKind kind, ulong value)
|
||||||
|
@ -6,7 +6,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
class DescriptorSetManager : IDisposable
|
class DescriptorSetManager : IDisposable
|
||||||
{
|
{
|
||||||
public const uint MaxSets = 16;
|
public const uint MaxSets = 32;
|
||||||
|
|
||||||
public class DescriptorPoolHolder : IDisposable
|
public class DescriptorPoolHolder : IDisposable
|
||||||
{
|
{
|
||||||
|
@ -14,6 +14,8 @@ using System.IO;
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Applets
|
namespace Ryujinx.HLE.HOS.Applets
|
||||||
{
|
{
|
||||||
@ -51,10 +53,10 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
|
|
||||||
private byte[] _transferMemory;
|
private byte[] _transferMemory;
|
||||||
|
|
||||||
private string _textValue = "";
|
public string _textValue = "";
|
||||||
private int _cursorBegin = 0;
|
private int _cursorBegin = 0;
|
||||||
private Encoding _encoding = Encoding.Unicode;
|
private Encoding _encoding = Encoding.Unicode;
|
||||||
private KeyboardResult _lastResult = KeyboardResult.NotSet;
|
public KeyboardResult _lastResult = KeyboardResult.NotSet;
|
||||||
|
|
||||||
private IDynamicTextInputHandler _dynamicTextInputHandler = null;
|
private IDynamicTextInputHandler _dynamicTextInputHandler = null;
|
||||||
private SoftwareKeyboardRenderer _keyboardRenderer = null;
|
private SoftwareKeyboardRenderer _keyboardRenderer = null;
|
||||||
@ -180,9 +182,6 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
return _keyboardRenderer?.DrawTo(destination, position) ?? false;
|
return _keyboardRenderer?.DrawTo(destination, position) ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport("SoftwareKeyboard.framework/SoftwareKeyboard", EntryPoint = "displayInputDialog", CallingConvention = CallingConvention.Cdecl)]
|
|
||||||
public static extern void DisplayInputDialog(ref SoftwareKeyboardUiArgs args, out IntPtr userInput);
|
|
||||||
|
|
||||||
|
|
||||||
private void ExecuteForegroundKeyboard()
|
private void ExecuteForegroundKeyboard()
|
||||||
{
|
{
|
||||||
@ -223,26 +222,8 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
InitialText = initialText,
|
InitialText = initialText,
|
||||||
};
|
};
|
||||||
|
|
||||||
IntPtr userInputPtr;
|
_textValue = DefaultInputText;
|
||||||
|
_lastResult = KeyboardResult.Cancel;
|
||||||
DisplayInputDialog(ref args, out userInputPtr);
|
|
||||||
if (userInputPtr != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
// Convert the IntPtr to a string
|
|
||||||
string userInput = Marshal.PtrToStringAnsi(userInputPtr);
|
|
||||||
|
|
||||||
_textValue = userInput ?? DefaultInputText;
|
|
||||||
_lastResult = KeyboardResult.Accept;
|
|
||||||
|
|
||||||
Console.WriteLine($"User input: {userInput}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Console.WriteLine("No input was received or input was canceled.");
|
|
||||||
|
|
||||||
_textValue = DefaultInputText;
|
|
||||||
_lastResult = KeyboardResult.Cancel;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -259,37 +240,40 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
StringLengthMax = _keyboardForegroundConfig.StringLengthMax,
|
StringLengthMax = _keyboardForegroundConfig.StringLengthMax,
|
||||||
InitialText = initialText,
|
InitialText = initialText,
|
||||||
};
|
};
|
||||||
|
_device.UiHandler.DisplayInputDialog(args, inputText =>
|
||||||
|
{
|
||||||
|
Console.WriteLine($"User entered: {inputText}");
|
||||||
|
|
||||||
|
_textValue = inputText ?? initialText ?? DefaultInputText;
|
||||||
|
_lastResult = !string.IsNullOrEmpty(inputText) ? KeyboardResult.Accept : KeyboardResult.Cancel;
|
||||||
|
|
||||||
_lastResult = _device.UiHandler.DisplayInputDialog(args, out _textValue) ? KeyboardResult.Accept : KeyboardResult.Cancel;
|
while (_textValue.Length < _keyboardForegroundConfig.StringLengthMin)
|
||||||
_textValue ??= initialText ?? DefaultInputText;
|
{
|
||||||
}
|
_textValue = string.Join(" ", _textValue, _textValue);
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure the text meets the minimum length requirement
|
// Truncate the text if it exceeds the maximum length
|
||||||
while (_textValue.Length < _keyboardForegroundConfig.StringLengthMin)
|
if (_textValue.Length > _keyboardForegroundConfig.StringLengthMax)
|
||||||
{
|
{
|
||||||
_textValue = string.Join(" ", _textValue, _textValue);
|
_textValue = _textValue[.._keyboardForegroundConfig.StringLengthMax];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Truncate the text if it exceeds the maximum length
|
// Handle text validation if required
|
||||||
if (_textValue.Length > _keyboardForegroundConfig.StringLengthMax)
|
if (_keyboardForegroundConfig.CheckText)
|
||||||
{
|
{
|
||||||
_textValue = _textValue[.._keyboardForegroundConfig.StringLengthMax];
|
// Submit text for validation
|
||||||
}
|
_foregroundState = SoftwareKeyboardState.ValidationPending;
|
||||||
|
PushForegroundResponse(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Submit text as complete
|
||||||
|
_foregroundState = SoftwareKeyboardState.Complete;
|
||||||
|
PushForegroundResponse(false);
|
||||||
|
|
||||||
// Handle text validation if required
|
AppletStateChanged?.Invoke(this, null);
|
||||||
if (_keyboardForegroundConfig.CheckText)
|
}
|
||||||
{
|
});
|
||||||
// Submit text for validation
|
|
||||||
_foregroundState = SoftwareKeyboardState.ValidationPending;
|
|
||||||
PushForegroundResponse(true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Submit text as complete
|
|
||||||
_foregroundState = SoftwareKeyboardState.Complete;
|
|
||||||
PushForegroundResponse(false);
|
|
||||||
|
|
||||||
AppletStateChanged?.Invoke(this, null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using Ryujinx.HLE.HOS.Applets;
|
using Ryujinx.HLE.HOS.Applets;
|
||||||
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Ui
|
namespace Ryujinx.HLE.Ui
|
||||||
{
|
{
|
||||||
@ -10,7 +11,7 @@ namespace Ryujinx.HLE.Ui
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="userText">Text that the user entered. Set to `null` on internal errors</param>
|
/// <param name="userText">Text that the user entered. Set to `null` on internal errors</param>
|
||||||
/// <returns>True when OK is pressed, False otherwise. Also returns True on internal errors</returns>
|
/// <returns>True when OK is pressed, False otherwise. Also returns True on internal errors</returns>
|
||||||
bool DisplayInputDialog(SoftwareKeyboardUiArgs args, out string userText);
|
public void DisplayInputDialog(SoftwareKeyboardUiArgs args, Action<string> onTextEntered);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Displays a Message Dialog box to the user and blocks until it is closed.
|
/// Displays a Message Dialog box to the user and blocks until it is closed.
|
||||||
|
42
src/Ryujinx.Headless.SDL2/Keyboard-iOS.cs
Normal file
42
src/Ryujinx.Headless.SDL2/Keyboard-iOS.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Ryujinx.Ui.Common.Helper;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Ryujinx.Headless.SDL2
|
||||||
|
{
|
||||||
|
public static class AlertHelper
|
||||||
|
{
|
||||||
|
[DllImport("RyujinxKeyboard.framework/RyujinxKeyboard", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void showKeyboardAlert(string title, string message, string placeholder);
|
||||||
|
|
||||||
|
[DllImport("RyujinxKeyboard.framework/RyujinxKeyboard", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
private static extern IntPtr getKeyboardInput();
|
||||||
|
|
||||||
|
[DllImport("RyujinxKeyboard.framework/RyujinxKeyboard", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
private static extern void clearKeyboardInput();
|
||||||
|
|
||||||
|
public static void ShowAlertWithTextInput(string title, string message, string placeholder, Action<string> onTextEntered)
|
||||||
|
{
|
||||||
|
showKeyboardAlert(title, message, placeholder);
|
||||||
|
|
||||||
|
ThreadPool.QueueUserWorkItem(_ =>
|
||||||
|
{
|
||||||
|
string result = null;
|
||||||
|
while (result == null)
|
||||||
|
{
|
||||||
|
Thread.Sleep(100);
|
||||||
|
|
||||||
|
IntPtr inputPtr = getKeyboardInput();
|
||||||
|
if (inputPtr != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
result = Marshal.PtrToStringAnsi(inputPtr);
|
||||||
|
clearKeyboardInput();
|
||||||
|
|
||||||
|
onTextEntered?.Invoke(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -460,12 +460,19 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
Exit();
|
Exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DisplayInputDialog(SoftwareKeyboardUiArgs args, out string userText)
|
public void DisplayInputDialog(SoftwareKeyboardUiArgs args, Action<string> onTextEntered)
|
||||||
{
|
{
|
||||||
// SDL2 doesn't support input dialogs
|
// SDL2 doesn't support input dialogs
|
||||||
userText = "Ryujinx";
|
// Trying to use Objective-C on iDevices
|
||||||
|
if (OperatingSystem.IsIOS())
|
||||||
return true;
|
{
|
||||||
|
AlertHelper.ShowAlertWithTextInput(args.HeaderText, args.SubtitleText, args.GuideText, (inputText) =>
|
||||||
|
{
|
||||||
|
onTextEntered?.Invoke(inputText);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
onTextEntered?.Invoke("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DisplayMessageDialog(string title, string message)
|
public bool DisplayMessageDialog(string title, string message)
|
||||||
|
@ -81,57 +81,10 @@ namespace Ryujinx.Ui.Applet
|
|||||||
return okPressed;
|
return okPressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DisplayInputDialog(SoftwareKeyboardUiArgs args, out string userText)
|
public void DisplayInputDialog(SoftwareKeyboardUiArgs args, Action<string> onTextEntered)
|
||||||
{
|
{
|
||||||
ManualResetEvent dialogCloseEvent = new(false);
|
onTextEntered?.Invoke("MeloNX");
|
||||||
|
return;
|
||||||
bool okPressed = false;
|
|
||||||
bool error = false;
|
|
||||||
string inputText = args.InitialText ?? "";
|
|
||||||
|
|
||||||
Application.Invoke(delegate
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var swkbdDialog = new SwkbdAppletDialog(_parent)
|
|
||||||
{
|
|
||||||
Title = "Software Keyboard",
|
|
||||||
Text = args.HeaderText,
|
|
||||||
SecondaryText = args.SubtitleText,
|
|
||||||
};
|
|
||||||
|
|
||||||
swkbdDialog.InputEntry.Text = inputText;
|
|
||||||
swkbdDialog.InputEntry.PlaceholderText = args.GuideText;
|
|
||||||
swkbdDialog.OkButton.Label = args.SubmitText;
|
|
||||||
|
|
||||||
swkbdDialog.SetInputLengthValidation(args.StringLengthMin, args.StringLengthMax);
|
|
||||||
swkbdDialog.SetInputValidation(args.KeyboardMode);
|
|
||||||
|
|
||||||
if (swkbdDialog.Run() == (int)ResponseType.Ok)
|
|
||||||
{
|
|
||||||
inputText = swkbdDialog.InputEntry.Text;
|
|
||||||
okPressed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
swkbdDialog.Dispose();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
error = true;
|
|
||||||
|
|
||||||
GtkDialog.CreateErrorDialog($"Error displaying Software Keyboard: {ex}");
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
dialogCloseEvent.Set();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
dialogCloseEvent.WaitOne();
|
|
||||||
|
|
||||||
userText = error ? null : inputText;
|
|
||||||
|
|
||||||
return error || okPressed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ExecuteProgram(HLE.Switch device, ProgramSpecifyKind kind, ulong value)
|
public void ExecuteProgram(HLE.Switch device, ProgramSpecifyKind kind, ulong value)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user