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 */
|
||||
|
||||
/* 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; };
|
||||
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; };
|
||||
@ -96,7 +97,7 @@
|
||||
"Dependencies/Dynamic Libraries/Ryujinx.Headless.SDL2.dylib" = (
|
||||
CodeSignOnCopy,
|
||||
);
|
||||
"Dependencies/Dynamic Libraries/SoftwareKeyboard.framework" = (
|
||||
"Dependencies/Dynamic Libraries/RyujinxKeyboard.framework" = (
|
||||
CodeSignOnCopy,
|
||||
RemoveHeadersOnCopy,
|
||||
);
|
||||
@ -157,7 +158,7 @@
|
||||
"Dependencies/Dynamic Libraries/libavutil.dylib",
|
||||
"Dependencies/Dynamic Libraries/libMoltenVK.dylib",
|
||||
"Dependencies/Dynamic Libraries/Ryujinx.Headless.SDL2.dylib",
|
||||
"Dependencies/Dynamic Libraries/SoftwareKeyboard.framework",
|
||||
"Dependencies/Dynamic Libraries/RyujinxKeyboard.framework",
|
||||
Dependencies/XCFrameworks/libavcodec.xcframework,
|
||||
Dependencies/XCFrameworks/libavfilter.xcframework,
|
||||
Dependencies/XCFrameworks/libavformat.xcframework,
|
||||
@ -232,6 +233,7 @@
|
||||
4E80AA192CD700F500029585 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4E7023A52D5A98E2002C7183 /* UIKit.framework */,
|
||||
4E80AA622CD7122800029585 /* GameController.framework */,
|
||||
);
|
||||
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",
|
||||
);
|
||||
GCC_OPTIMIZATION_LEVEL = fast;
|
||||
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",
|
||||
);
|
||||
MARKETING_VERSION = 0.0.8;
|
||||
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",
|
||||
);
|
||||
GCC_OPTIMIZATION_LEVEL = fast;
|
||||
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",
|
||||
);
|
||||
MARKETING_VERSION = 0.0.8;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
||||
|
Binary file not shown.
@ -12,12 +12,12 @@
|
||||
<key>Ryujinx.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>2</integer>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<key>com.Stossy11.MeloNX.RyujinxAg.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>1</integer>
|
||||
<integer>2</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
|
@ -5,7 +5,7 @@
|
||||
// Created by Stossy11 on 3/11/2024.
|
||||
//
|
||||
|
||||
#define DRM 1
|
||||
#define DRM 0
|
||||
#define CS_DEBUGGED 0x10000000
|
||||
|
||||
#ifndef RyujinxHeader
|
||||
|
@ -61,8 +61,8 @@ struct ContentView: View {
|
||||
// Metal Private API isn't needed and causes more stutters
|
||||
MoltenVKSettings(string: "MVK_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_CONFIG_LOG_LEVEL", value: "2"),
|
||||
MoltenVKSettings(string: "MVK_DEBUG", value: "0"),
|
||||
// MoltenVKSettings(string: "MVK_CONFIG_LOG_LEVEL", value: "0"),
|
||||
// MVK_CONFIG_LOG_LEVEL
|
||||
//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)
|
||||
@ -116,6 +116,8 @@ struct ContentView: View {
|
||||
.onAppear() {
|
||||
quits = false
|
||||
|
||||
|
||||
|
||||
initControllerObservers() // This initializes the Controller Observers that refreshes the controller list when a new controller connecvts.
|
||||
}
|
||||
.onOpenURL() { url in
|
||||
|
@ -195,7 +195,11 @@ struct GameLibraryView: View {
|
||||
|
||||
Button {
|
||||
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)!
|
||||
if UIApplication.shared.canOpenURL(furl) {
|
||||
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 {
|
||||
WindowGroup {
|
||||
ZStack {
|
||||
if showed {
|
||||
if showed || DRM != 1 {
|
||||
ContentView()
|
||||
} else {
|
||||
Group {
|
||||
@ -137,10 +137,12 @@ struct MeloNXApp: App {
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
mainWindow.rootViewController!.present(alertController, animated: true, completion: nil)
|
||||
DispatchQueue.main.async {
|
||||
mainWindow.rootViewController!.present(alertController, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
return alertController
|
||||
} else {
|
||||
|
@ -98,43 +98,10 @@ namespace Ryujinx.Ava.UI.Applet
|
||||
return okPressed;
|
||||
}
|
||||
|
||||
public bool DisplayInputDialog(SoftwareKeyboardUiArgs args, out string userText)
|
||||
public void DisplayInputDialog(SoftwareKeyboardUiArgs args, Action<string> onTextEntered)
|
||||
{
|
||||
ManualResetEvent dialogCloseEvent = new(false);
|
||||
|
||||
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;
|
||||
onTextEntered?.Invoke("MeloNX");
|
||||
return;
|
||||
}
|
||||
|
||||
public void ExecuteProgram(Switch device, ProgramSpecifyKind kind, ulong value)
|
||||
|
@ -6,7 +6,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
class DescriptorSetManager : IDisposable
|
||||
{
|
||||
public const uint MaxSets = 16;
|
||||
public const uint MaxSets = 32;
|
||||
|
||||
public class DescriptorPoolHolder : IDisposable
|
||||
{
|
||||
|
@ -14,6 +14,8 @@ using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
@ -51,10 +53,10 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
|
||||
private byte[] _transferMemory;
|
||||
|
||||
private string _textValue = "";
|
||||
public string _textValue = "";
|
||||
private int _cursorBegin = 0;
|
||||
private Encoding _encoding = Encoding.Unicode;
|
||||
private KeyboardResult _lastResult = KeyboardResult.NotSet;
|
||||
public KeyboardResult _lastResult = KeyboardResult.NotSet;
|
||||
|
||||
private IDynamicTextInputHandler _dynamicTextInputHandler = null;
|
||||
private SoftwareKeyboardRenderer _keyboardRenderer = null;
|
||||
@ -180,9 +182,6 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
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()
|
||||
{
|
||||
@ -223,26 +222,8 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
InitialText = initialText,
|
||||
};
|
||||
|
||||
IntPtr userInputPtr;
|
||||
|
||||
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;
|
||||
}
|
||||
_textValue = DefaultInputText;
|
||||
_lastResult = KeyboardResult.Cancel;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -259,37 +240,40 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
StringLengthMax = _keyboardForegroundConfig.StringLengthMax,
|
||||
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;
|
||||
_textValue ??= initialText ?? DefaultInputText;
|
||||
}
|
||||
while (_textValue.Length < _keyboardForegroundConfig.StringLengthMin)
|
||||
{
|
||||
_textValue = string.Join(" ", _textValue, _textValue);
|
||||
}
|
||||
|
||||
// Ensure the text meets the minimum length requirement
|
||||
while (_textValue.Length < _keyboardForegroundConfig.StringLengthMin)
|
||||
{
|
||||
_textValue = string.Join(" ", _textValue, _textValue);
|
||||
}
|
||||
// Truncate the text if it exceeds the maximum length
|
||||
if (_textValue.Length > _keyboardForegroundConfig.StringLengthMax)
|
||||
{
|
||||
_textValue = _textValue[.._keyboardForegroundConfig.StringLengthMax];
|
||||
}
|
||||
|
||||
// Truncate the text if it exceeds the maximum length
|
||||
if (_textValue.Length > _keyboardForegroundConfig.StringLengthMax)
|
||||
{
|
||||
_textValue = _textValue[.._keyboardForegroundConfig.StringLengthMax];
|
||||
}
|
||||
// Handle text validation if required
|
||||
if (_keyboardForegroundConfig.CheckText)
|
||||
{
|
||||
// Submit text for validation
|
||||
_foregroundState = SoftwareKeyboardState.ValidationPending;
|
||||
PushForegroundResponse(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Submit text as complete
|
||||
_foregroundState = SoftwareKeyboardState.Complete;
|
||||
PushForegroundResponse(false);
|
||||
|
||||
// Handle text validation if required
|
||||
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);
|
||||
AppletStateChanged?.Invoke(this, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
using Ryujinx.HLE.HOS.Applets;
|
||||
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.Ui
|
||||
{
|
||||
@ -10,7 +11,7 @@ namespace Ryujinx.HLE.Ui
|
||||
/// </summary>
|
||||
/// <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>
|
||||
bool DisplayInputDialog(SoftwareKeyboardUiArgs args, out string userText);
|
||||
public void DisplayInputDialog(SoftwareKeyboardUiArgs args, Action<string> onTextEntered);
|
||||
|
||||
/// <summary>
|
||||
/// 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();
|
||||
}
|
||||
|
||||
public bool DisplayInputDialog(SoftwareKeyboardUiArgs args, out string userText)
|
||||
public void DisplayInputDialog(SoftwareKeyboardUiArgs args, Action<string> onTextEntered)
|
||||
{
|
||||
// SDL2 doesn't support input dialogs
|
||||
userText = "Ryujinx";
|
||||
|
||||
return true;
|
||||
// Trying to use Objective-C on iDevices
|
||||
if (OperatingSystem.IsIOS())
|
||||
{
|
||||
AlertHelper.ShowAlertWithTextInput(args.HeaderText, args.SubtitleText, args.GuideText, (inputText) =>
|
||||
{
|
||||
onTextEntered?.Invoke(inputText);
|
||||
});
|
||||
} else {
|
||||
onTextEntered?.Invoke("");
|
||||
}
|
||||
}
|
||||
|
||||
public bool DisplayMessageDialog(string title, string message)
|
||||
|
@ -81,57 +81,10 @@ namespace Ryujinx.Ui.Applet
|
||||
return okPressed;
|
||||
}
|
||||
|
||||
public bool DisplayInputDialog(SoftwareKeyboardUiArgs args, out string userText)
|
||||
public void DisplayInputDialog(SoftwareKeyboardUiArgs args, Action<string> onTextEntered)
|
||||
{
|
||||
ManualResetEvent dialogCloseEvent = new(false);
|
||||
|
||||
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;
|
||||
onTextEntered?.Invoke("MeloNX");
|
||||
return;
|
||||
}
|
||||
|
||||
public void ExecuteProgram(HLE.Switch device, ProgramSpecifyKind kind, ulong value)
|
||||
|
Loading…
x
Reference in New Issue
Block a user