forked from MeloNX/MeloNX
android - update ui handler to call back into java
This commit is contained in:
parent
b7deaefff7
commit
e2f584a7ff
@ -2,6 +2,7 @@ using LibHac.Tools.Fs;
|
|||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.HLE;
|
using Ryujinx.HLE;
|
||||||
using Ryujinx.HLE.HOS.Applets;
|
using Ryujinx.HLE.HOS.Applets;
|
||||||
|
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
|
||||||
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
||||||
using Ryujinx.HLE.UI;
|
using Ryujinx.HLE.UI;
|
||||||
using System;
|
using System;
|
||||||
@ -15,20 +16,13 @@ namespace LibRyujinx.Android
|
|||||||
{
|
{
|
||||||
internal class AndroidUIHandler : IHostUIHandler, IDisposable
|
internal class AndroidUIHandler : IHostUIHandler, IDisposable
|
||||||
{
|
{
|
||||||
public ManualResetEvent _waitEvent;
|
|
||||||
public ManualResetEvent _responseEvent;
|
|
||||||
private bool _isDisposed;
|
private bool _isDisposed;
|
||||||
private bool _isOkPressed;
|
private bool _isOkPressed;
|
||||||
private long _input;
|
private string? _input;
|
||||||
|
private ManualResetEvent _resetEvent = new ManualResetEvent(false);
|
||||||
|
|
||||||
public IHostUITheme HostUITheme => throw new NotImplementedException();
|
public IHostUITheme HostUITheme => throw new NotImplementedException();
|
||||||
|
|
||||||
public AndroidUIHandler()
|
|
||||||
{
|
|
||||||
_waitEvent = new ManualResetEvent(false);
|
|
||||||
_responseEvent = new ManualResetEvent(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IDynamicTextInputHandler CreateDynamicTextInputHandler()
|
public IDynamicTextInputHandler CreateDynamicTextInputHandler()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
@ -36,47 +30,51 @@ namespace LibRyujinx.Android
|
|||||||
|
|
||||||
public bool DisplayErrorAppletDialog(string title, string message, string[] buttonsText)
|
public bool DisplayErrorAppletDialog(string title, string message, string[] buttonsText)
|
||||||
{
|
{
|
||||||
LibRyujinx.setUiHandlerTitle(LibRyujinx.storeString(title ?? ""));
|
Interop.UpdateUiHandler(title ?? "",
|
||||||
LibRyujinx.setUiHandlerMessage(LibRyujinx.storeString(message ?? ""));
|
message ?? "",
|
||||||
LibRyujinx.setUiHandlerType(1);
|
"",
|
||||||
|
1,
|
||||||
_responseEvent.Reset();
|
0,
|
||||||
Set();
|
0,
|
||||||
_responseEvent.WaitOne();
|
KeyboardMode.Default,
|
||||||
|
"",
|
||||||
|
"");
|
||||||
|
|
||||||
return _isOkPressed;
|
return _isOkPressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DisplayInputDialog(SoftwareKeyboardUIArgs args, out string userText)
|
public bool DisplayInputDialog(SoftwareKeyboardUIArgs args, out string userText)
|
||||||
{
|
{
|
||||||
LibRyujinx.setUiHandlerTitle(LibRyujinx.storeString("Software Keyboard"));
|
_input = null;
|
||||||
LibRyujinx.setUiHandlerMessage(LibRyujinx.storeString(args.HeaderText ?? ""));
|
_resetEvent.Reset();
|
||||||
LibRyujinx.setUiHandlerWatermark(LibRyujinx.storeString(args.GuideText ?? ""));
|
Interop.UpdateUiHandler("Software Keyboard",
|
||||||
LibRyujinx.setUiHandlerSubtitle(LibRyujinx.storeString(args.SubtitleText ?? ""));
|
args.HeaderText ?? "",
|
||||||
LibRyujinx.setUiHandlerInitialText(LibRyujinx.storeString(args.InitialText ?? ""));
|
args.GuideText ?? "",
|
||||||
LibRyujinx.setUiHandlerMinLength(args.StringLengthMin);
|
2,
|
||||||
LibRyujinx.setUiHandlerMaxLength(args.StringLengthMax);
|
args.StringLengthMin,
|
||||||
LibRyujinx.setUiHandlerType(2);
|
args.StringLengthMax,
|
||||||
LibRyujinx.setUiHandlerKeyboardMode((int)args.KeyboardMode);
|
args.KeyboardMode,
|
||||||
|
args.SubtitleText ?? "",
|
||||||
|
args.InitialText ?? "");
|
||||||
|
|
||||||
_responseEvent.Reset();
|
_resetEvent.WaitOne();
|
||||||
Set();
|
|
||||||
_responseEvent.WaitOne();
|
|
||||||
|
|
||||||
userText = _input != -1 ? LibRyujinx.GetStoredString(_input) : "";
|
userText = _input ?? "";
|
||||||
|
|
||||||
return _isOkPressed;
|
return _isOkPressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DisplayMessageDialog(string title, string message)
|
public bool DisplayMessageDialog(string title, string message)
|
||||||
{
|
{
|
||||||
LibRyujinx.setUiHandlerTitle(LibRyujinx.storeString(title ?? ""));
|
Interop.UpdateUiHandler(title ?? "",
|
||||||
LibRyujinx.setUiHandlerMessage(LibRyujinx.storeString(message ?? ""));
|
message ?? "",
|
||||||
LibRyujinx.setUiHandlerType(1);
|
"",
|
||||||
|
1,
|
||||||
_responseEvent.Reset();
|
0,
|
||||||
Set();
|
0,
|
||||||
_responseEvent.WaitOne();
|
KeyboardMode.Default,
|
||||||
|
"",
|
||||||
|
"");
|
||||||
|
|
||||||
return _isOkPressed;
|
return _isOkPressed;
|
||||||
}
|
}
|
||||||
@ -99,38 +97,18 @@ namespace LibRyujinx.Android
|
|||||||
// throw new NotImplementedException();
|
// throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Wait()
|
internal void SetResponse(bool isOkPressed, string input)
|
||||||
{
|
|
||||||
if (_isDisposed)
|
|
||||||
return;
|
|
||||||
_waitEvent.Reset();
|
|
||||||
_waitEvent.WaitOne();
|
|
||||||
_waitEvent.Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void Set()
|
|
||||||
{
|
|
||||||
if (_isDisposed)
|
|
||||||
return;
|
|
||||||
_waitEvent.Set();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void SetResponse(bool isOkPressed, long input)
|
|
||||||
{
|
{
|
||||||
if (_isDisposed)
|
if (_isDisposed)
|
||||||
return;
|
return;
|
||||||
_isOkPressed = isOkPressed;
|
_isOkPressed = isOkPressed;
|
||||||
_input = input;
|
_input = input;
|
||||||
_responseEvent.Set();
|
_resetEvent.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_isDisposed = true;
|
_isDisposed = true;
|
||||||
_waitEvent.Set();
|
|
||||||
_waitEvent.Set();
|
|
||||||
_responseEvent.Dispose();
|
|
||||||
_waitEvent.Dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
190
src/LibRyujinx/Android/Interop.cs
Normal file
190
src/LibRyujinx/Android/Interop.cs
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
using LibRyujinx.Jni;
|
||||||
|
using LibRyujinx.Jni.Identifiers;
|
||||||
|
using LibRyujinx.Jni.Pointers;
|
||||||
|
using LibRyujinx.Jni.Primitives;
|
||||||
|
using LibRyujinx.Jni.References;
|
||||||
|
using LibRyujinx.Jni.Values;
|
||||||
|
using Rxmxnx.PInvoke;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Common.Memory;
|
||||||
|
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace LibRyujinx.Android
|
||||||
|
{
|
||||||
|
internal unsafe static class Interop
|
||||||
|
{
|
||||||
|
internal const string BaseClassName = "org/ryujinx/android/RyujinxNative";
|
||||||
|
private static JGlobalRef? _classId;
|
||||||
|
private static ConcurrentDictionary<(string method, string descriptor), JMethodId> _methodCache = new ConcurrentDictionary<(string method, string descriptor), JMethodId>();
|
||||||
|
private static (string name, string descriptor)[] _methods = new[]
|
||||||
|
{
|
||||||
|
("test", "()V"),
|
||||||
|
("updateUiHandler", "(JJJIIIIJJ)V")
|
||||||
|
};
|
||||||
|
|
||||||
|
internal static void Initialize(JEnvRef jniEnv)
|
||||||
|
{
|
||||||
|
var vm = JniHelper.GetVirtualMachine(jniEnv);
|
||||||
|
if (_classId == null)
|
||||||
|
{
|
||||||
|
var className = new ReadOnlySpan<Byte>(Encoding.UTF8.GetBytes(BaseClassName));
|
||||||
|
using (IReadOnlyFixedMemory<Byte>.IDisposable cName = className.GetUnsafeValPtr()
|
||||||
|
.GetUnsafeFixedContext(className.Length))
|
||||||
|
{
|
||||||
|
_classId = JniHelper.GetGlobalClass(jniEnv, cName);
|
||||||
|
if (_classId == null)
|
||||||
|
{
|
||||||
|
Logger.Info?.Print(LogClass.Application, $"Class Id {BaseClassName} not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var x in _methods)
|
||||||
|
{
|
||||||
|
CacheMethod(jniEnv, x.name, x.descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
JniEnv._jvm = vm;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CacheMethod(JEnvRef jEnv, string name, string descriptor)
|
||||||
|
{
|
||||||
|
if (!_methodCache.TryGetValue((name, descriptor), out var method))
|
||||||
|
{
|
||||||
|
var methodName = new ReadOnlySpan<Byte>(Encoding.UTF8.GetBytes(name));
|
||||||
|
var descriptorId = new ReadOnlySpan<Byte>(Encoding.UTF8.GetBytes(descriptor));
|
||||||
|
using (IReadOnlyFixedMemory<Byte>.IDisposable mName = methodName.GetUnsafeValPtr()
|
||||||
|
.GetUnsafeFixedContext(methodName.Length))
|
||||||
|
using (IReadOnlyFixedMemory<Byte>.IDisposable dName = descriptorId.GetUnsafeValPtr()
|
||||||
|
.GetUnsafeFixedContext(descriptorId.Length))
|
||||||
|
{
|
||||||
|
var methodId = JniHelper.GetStaticMethodId(jEnv, (JClassLocalRef)(_classId.Value.Value), mName, dName);
|
||||||
|
if (methodId == null)
|
||||||
|
{
|
||||||
|
Logger.Warning?.Print(LogClass.Application, $"Java Method Id {name} not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
method = methodId.Value;
|
||||||
|
_methodCache[(name, descriptor)] = method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CallMethod(string name, string descriptor, params JValue[] values)
|
||||||
|
{
|
||||||
|
using var env = JniEnv.Create();
|
||||||
|
if (_methodCache.TryGetValue((name, descriptor), out var method))
|
||||||
|
{
|
||||||
|
if (descriptor.EndsWith("V"))
|
||||||
|
{
|
||||||
|
JniHelper.CallStaticVoidMethod(env.Env, (JClassLocalRef)(_classId.Value.Value), method, values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Test()
|
||||||
|
{
|
||||||
|
CallMethod("test", "()V");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UpdateUiHandler(string newTitle,
|
||||||
|
string newMessage,
|
||||||
|
string newWatermark,
|
||||||
|
int newType,
|
||||||
|
int min,
|
||||||
|
int max,
|
||||||
|
KeyboardMode nMode,
|
||||||
|
string newSubtitle,
|
||||||
|
string newInitialText)
|
||||||
|
{
|
||||||
|
using var titlePointer = new TempNativeString(newTitle);
|
||||||
|
using var messagePointer = new TempNativeString(newMessage);
|
||||||
|
using var watermarkPointer = new TempNativeString(newWatermark);
|
||||||
|
using var subtitlePointer = new TempNativeString(newSubtitle);
|
||||||
|
using var newInitialPointer = new TempNativeString(newInitialText);
|
||||||
|
CallMethod("updateUiHandler", "(JJJIIIIJJ)V", new JValue[]
|
||||||
|
{
|
||||||
|
JValue.Create(titlePointer.AsBytes()),
|
||||||
|
JValue.Create(messagePointer.AsBytes()),
|
||||||
|
JValue.Create(watermarkPointer.AsBytes()),
|
||||||
|
JValue.Create(newType.AsBytes()),
|
||||||
|
JValue.Create(min.AsBytes()),
|
||||||
|
JValue.Create(max.AsBytes()),
|
||||||
|
JValue.Create(nMode.AsBytes()),
|
||||||
|
JValue.Create(subtitlePointer.AsBytes()),
|
||||||
|
JValue.Create(newInitialPointer.AsBytes())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TempNativeString : IDisposable
|
||||||
|
{
|
||||||
|
private JLong _jPointer;
|
||||||
|
|
||||||
|
public TempNativeString(string value)
|
||||||
|
{
|
||||||
|
Pointer = Marshal.StringToHGlobalAuto(value);
|
||||||
|
JPointer = (JLong)Pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public nint Pointer { get; private set; }
|
||||||
|
public JLong JPointer { get => _jPointer; private set => _jPointer = value; }
|
||||||
|
|
||||||
|
public Span<byte> AsBytes()
|
||||||
|
{
|
||||||
|
return _jPointer.AsBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (Pointer != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(Pointer);
|
||||||
|
}
|
||||||
|
Pointer = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class JniEnv : IDisposable
|
||||||
|
{
|
||||||
|
internal static JavaVMRef? _jvm;
|
||||||
|
private readonly JEnvRef _env;
|
||||||
|
private readonly bool _newAttach;
|
||||||
|
|
||||||
|
public JEnvRef Env => _env;
|
||||||
|
|
||||||
|
private JniEnv(JEnvRef env, bool newAttach)
|
||||||
|
{
|
||||||
|
_env = env;
|
||||||
|
_newAttach = newAttach;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if(_newAttach)
|
||||||
|
{
|
||||||
|
JniHelper.Detach(_jvm!.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JniEnv? Create()
|
||||||
|
{
|
||||||
|
bool newAttach = false;
|
||||||
|
ReadOnlySpan<Byte> threadName = "JvmCall"u8;
|
||||||
|
var env = _jvm == null ? default : JniHelper.Attach(_jvm.Value, threadName.GetUnsafeValPtr().GetUnsafeFixedContext(threadName.Length),
|
||||||
|
out newAttach);
|
||||||
|
|
||||||
|
return env != null ? new JniEnv(env.Value, newAttach) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
|
using LibRyujinx.Android;
|
||||||
using LibRyujinx.Jni.Pointers;
|
using LibRyujinx.Jni.Pointers;
|
||||||
using LibRyujinx.Jni.References;
|
|
||||||
using Ryujinx.Audio.Backends.OpenAL;
|
using Ryujinx.Audio.Backends.OpenAL;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
@ -14,9 +14,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace LibRyujinx
|
namespace LibRyujinx
|
||||||
@ -29,56 +27,6 @@ namespace LibRyujinx
|
|||||||
|
|
||||||
public static VulkanLoader? VulkanLoader { get; private set; }
|
public static VulkanLoader? VulkanLoader { get; private set; }
|
||||||
|
|
||||||
[DllImport("libryujinxjni")]
|
|
||||||
private extern static IntPtr getStringPointer(JEnvRef jEnv, JStringLocalRef s);
|
|
||||||
|
|
||||||
[DllImport("libryujinxjni")]
|
|
||||||
private extern static JStringLocalRef createString(JEnvRef jEnv, IntPtr ch);
|
|
||||||
|
|
||||||
[DllImport("libryujinxjni")]
|
|
||||||
internal extern static long storeString(string ch);
|
|
||||||
|
|
||||||
[DllImport("libryujinxjni")]
|
|
||||||
internal extern static IntPtr getString(long id);
|
|
||||||
|
|
||||||
[DllImport("libryujinxjni")]
|
|
||||||
internal extern static long setUiHandlerTitle(long title);
|
|
||||||
|
|
||||||
[DllImport("libryujinxjni")]
|
|
||||||
internal extern static long setUiHandlerMessage(long message);
|
|
||||||
[DllImport("libryujinxjni")]
|
|
||||||
internal extern static long setUiHandlerWatermark(long watermark);
|
|
||||||
[DllImport("libryujinxjni")]
|
|
||||||
internal extern static long setUiHandlerInitialText(long text);
|
|
||||||
[DllImport("libryujinxjni")]
|
|
||||||
internal extern static long setUiHandlerSubtitle(long text);
|
|
||||||
|
|
||||||
[DllImport("libryujinxjni")]
|
|
||||||
internal extern static long setUiHandlerType(int type);
|
|
||||||
|
|
||||||
[DllImport("libryujinxjni")]
|
|
||||||
internal extern static long setUiHandlerKeyboardMode(int mode);
|
|
||||||
|
|
||||||
[DllImport("libryujinxjni")]
|
|
||||||
internal extern static long setUiHandlerMinLength(int lenght);
|
|
||||||
|
|
||||||
[DllImport("libryujinxjni")]
|
|
||||||
internal extern static long setUiHandlerMaxLength(int lenght);
|
|
||||||
|
|
||||||
internal static string GetStoredString(long id)
|
|
||||||
{
|
|
||||||
var pointer = getString(id);
|
|
||||||
if (pointer != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
var str = Marshal.PtrToStringAnsi(pointer) ?? "";
|
|
||||||
|
|
||||||
Marshal.FreeHGlobal(pointer);
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport("libryujinxjni")]
|
[DllImport("libryujinxjni")]
|
||||||
internal extern static void setRenderingThread();
|
internal extern static void setRenderingThread();
|
||||||
|
|
||||||
@ -97,7 +45,7 @@ namespace LibRyujinx
|
|||||||
public delegate IntPtr JniCreateSurface(IntPtr native_surface, IntPtr instance);
|
public delegate IntPtr JniCreateSurface(IntPtr native_surface, IntPtr instance);
|
||||||
|
|
||||||
[UnmanagedCallersOnly(EntryPoint = "javaInitialize")]
|
[UnmanagedCallersOnly(EntryPoint = "javaInitialize")]
|
||||||
public static bool JniInitialize(IntPtr jpathId)
|
public unsafe static bool JniInitialize(IntPtr jpathId, IntPtr jniEnv)
|
||||||
{
|
{
|
||||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||||
PlatformInfo.IsBionic = true;
|
PlatformInfo.IsBionic = true;
|
||||||
@ -113,6 +61,10 @@ namespace LibRyujinx
|
|||||||
|
|
||||||
var init = Initialize(path);
|
var init = Initialize(path);
|
||||||
|
|
||||||
|
Interop.Initialize(new JEnvRef(jniEnv));
|
||||||
|
|
||||||
|
Interop.Test();
|
||||||
|
|
||||||
_surfaceEvent?.Set();
|
_surfaceEvent?.Set();
|
||||||
|
|
||||||
_surfaceEvent = new ManualResetEvent(false);
|
_surfaceEvent = new ManualResetEvent(false);
|
||||||
@ -120,15 +72,6 @@ namespace LibRyujinx
|
|||||||
return init;
|
return init;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string? GetString(JEnvRef jEnv, JStringLocalRef jString)
|
|
||||||
{
|
|
||||||
var stringPtr = getStringPointer(jEnv, jString);
|
|
||||||
|
|
||||||
var s = Marshal.PtrToStringAnsi(stringPtr);
|
|
||||||
Marshal.FreeHGlobal(stringPtr);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
[UnmanagedCallersOnly(EntryPoint = "deviceReloadFilesystem")]
|
[UnmanagedCallersOnly(EntryPoint = "deviceReloadFilesystem")]
|
||||||
public static void JnaReloadFileSystem()
|
public static void JnaReloadFileSystem()
|
||||||
{
|
{
|
||||||
@ -192,20 +135,6 @@ namespace LibRyujinx
|
|||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceLoad")]
|
|
||||||
public static bool JniLoadApplicationNative(JEnvRef jEnv, JObjectLocalRef jObj, JStringLocalRef pathPtr)
|
|
||||||
{
|
|
||||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
|
||||||
if (SwitchDevice?.EmulationContext == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var path = GetString(jEnv, pathPtr);
|
|
||||||
|
|
||||||
return LoadApplication(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
[UnmanagedCallersOnly(EntryPoint = "deviceLaunchMiiEditor")]
|
[UnmanagedCallersOnly(EntryPoint = "deviceLaunchMiiEditor")]
|
||||||
public static bool JNALaunchMiiEditApplet()
|
public static bool JNALaunchMiiEditApplet()
|
||||||
{
|
{
|
||||||
@ -336,11 +265,6 @@ namespace LibRyujinx
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CCharSequence GetCCharSequence(string s)
|
|
||||||
{
|
|
||||||
return Encoding.UTF8.GetBytes(s).AsSpan();
|
|
||||||
}
|
|
||||||
|
|
||||||
[UnmanagedCallersOnly(EntryPoint = "graphicsSetSurface")]
|
[UnmanagedCallersOnly(EntryPoint = "graphicsSetSurface")]
|
||||||
public static void JniSetSurface(long surfacePtr, long window)
|
public static void JniSetSurface(long surfacePtr, long window)
|
||||||
{
|
{
|
||||||
@ -455,13 +379,6 @@ namespace LibRyujinx
|
|||||||
SetVsyncState(enabled);
|
SetVsyncState(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsRendererSetSwapBufferCallback")]
|
|
||||||
public static void JniSetSwapBuffersCallbackNative(JEnvRef jEnv, JObjectLocalRef jObj, IntPtr swapBuffersCallback)
|
|
||||||
{
|
|
||||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
|
||||||
_swapBuffersCallback = Marshal.GetDelegateForFunctionPointer<SwapBuffersCallback>(swapBuffersCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
[UnmanagedCallersOnly(EntryPoint = "inputInitialize")]
|
[UnmanagedCallersOnly(EntryPoint = "inputInitialize")]
|
||||||
public static void JnaInitializeInput(int width, int height)
|
public static void JnaInitializeInput(int width, int height)
|
||||||
{
|
{
|
||||||
@ -621,22 +538,10 @@ namespace LibRyujinx
|
|||||||
SetupUiHandler();
|
SetupUiHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly(EntryPoint = "uiHandlerWait")]
|
|
||||||
public static void JniWaitUiHandler()
|
|
||||||
{
|
|
||||||
WaitUiHandler();
|
|
||||||
}
|
|
||||||
|
|
||||||
[UnmanagedCallersOnly(EntryPoint = "uiHandlerStopWait")]
|
|
||||||
public static void JniStopUiHandlerWait()
|
|
||||||
{
|
|
||||||
StopUiHandlerWait();
|
|
||||||
}
|
|
||||||
|
|
||||||
[UnmanagedCallersOnly(EntryPoint = "uiHandlerSetResponse")]
|
[UnmanagedCallersOnly(EntryPoint = "uiHandlerSetResponse")]
|
||||||
public static void JniSetUiHandlerResponse(bool isOkPressed, long input)
|
public static void JniSetUiHandlerResponse(bool isOkPressed, IntPtr input)
|
||||||
{
|
{
|
||||||
SetUiHandlerResponse(isOkPressed, input);
|
SetUiHandlerResponse(isOkPressed, Marshal.PtrToStringAnsi(input) ?? "");
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly(EntryPoint = "userOpenUser")]
|
[UnmanagedCallersOnly(EntryPoint = "userOpenUser")]
|
||||||
|
@ -667,23 +667,7 @@ namespace LibRyujinx
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void WaitUiHandler()
|
public static void SetUiHandlerResponse(bool isOkPressed, string input)
|
||||||
{
|
|
||||||
if (SwitchDevice?.HostUiHandler is AndroidUIHandler uiHandler)
|
|
||||||
{
|
|
||||||
uiHandler.Wait();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void StopUiHandlerWait()
|
|
||||||
{
|
|
||||||
if (SwitchDevice?.HostUiHandler is AndroidUIHandler uiHandler)
|
|
||||||
{
|
|
||||||
uiHandler.Set();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetUiHandlerResponse(bool isOkPressed, long input)
|
|
||||||
{
|
{
|
||||||
if (SwitchDevice?.HostUiHandler is AndroidUIHandler uiHandler)
|
if (SwitchDevice?.HostUiHandler is AndroidUIHandler uiHandler)
|
||||||
{
|
{
|
||||||
|
@ -35,8 +35,7 @@ add_library( # Sets the name of the library.
|
|||||||
|
|
||||||
# Provides a relative path to your source file(s).
|
# Provides a relative path to your source file(s).
|
||||||
vulkan_wrapper.cpp
|
vulkan_wrapper.cpp
|
||||||
string_helper.cpp
|
ryujinx.cpp)
|
||||||
ryujinx.cpp)
|
|
||||||
|
|
||||||
# Searches for a specified prebuilt library and stores the path as a
|
# Searches for a specified prebuilt library and stores the path as a
|
||||||
# variable. Because CMake includes system libraries in the search path by
|
# variable. Because CMake includes system libraries in the search path by
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include "adrenotools/driver.h"
|
#include "adrenotools/driver.h"
|
||||||
#include "native_window.h"
|
#include "native_window.h"
|
||||||
#include "string_helper.h"
|
|
||||||
|
|
||||||
// A macro to pass call to Vulkan and check for return value for success
|
// A macro to pass call to Vulkan and check for return value for success
|
||||||
#define CALL_VK(func) \
|
#define CALL_VK(func) \
|
||||||
@ -39,49 +38,6 @@
|
|||||||
|
|
||||||
void *_ryujinxNative = NULL;
|
void *_ryujinxNative = NULL;
|
||||||
|
|
||||||
class UiHandler {
|
|
||||||
public:
|
|
||||||
void setTitle(long storedTitle);
|
|
||||||
|
|
||||||
void setMessage(long storedMessage);
|
|
||||||
|
|
||||||
void setWatermark(long wm);
|
|
||||||
|
|
||||||
void setType(int t);
|
|
||||||
|
|
||||||
void setMode(int t);
|
|
||||||
|
|
||||||
void setMinLength(int t);
|
|
||||||
|
|
||||||
void setMaxLength(int t);
|
|
||||||
|
|
||||||
void setInitialText(long text);
|
|
||||||
|
|
||||||
void setSubtitle(long text);
|
|
||||||
|
|
||||||
long getTitle();
|
|
||||||
|
|
||||||
long getMessage();
|
|
||||||
|
|
||||||
long getWatermark();
|
|
||||||
|
|
||||||
long getInitialText();
|
|
||||||
|
|
||||||
long getSubtitle();
|
|
||||||
|
|
||||||
int type = 0;
|
|
||||||
int keyboardMode = 0;
|
|
||||||
int min_length = -1;
|
|
||||||
int max_length = -1;
|
|
||||||
|
|
||||||
private:
|
|
||||||
long title = -1;
|
|
||||||
long message = -1;
|
|
||||||
long watermark = -1;
|
|
||||||
long initialText = -1;
|
|
||||||
long subtitle = -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Ryujinx imported functions
|
// Ryujinx imported functions
|
||||||
bool (*initialize)(char *) = NULL;
|
bool (*initialize)(char *) = NULL;
|
||||||
|
|
||||||
@ -89,7 +45,5 @@ long _renderingThreadId = 0;
|
|||||||
JavaVM *_vm = nullptr;
|
JavaVM *_vm = nullptr;
|
||||||
jobject _mainActivity = nullptr;
|
jobject _mainActivity = nullptr;
|
||||||
jclass _mainActivityClass = nullptr;
|
jclass _mainActivityClass = nullptr;
|
||||||
string_helper str_helper = string_helper();
|
|
||||||
UiHandler ui_handler = UiHandler();
|
|
||||||
|
|
||||||
#endif //RYUJINXNATIVE_RYUIJNX_H
|
#endif //RYUJINXNATIVE_RYUIJNX_H
|
||||||
|
@ -311,61 +311,10 @@ Java_org_ryujinx_android_NativeHelpers_getProgressInfo(JNIEnv *env, jobject thiz
|
|||||||
return createStringFromStdString(env, progressInfo);
|
return createStringFromStdString(env, progressInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
|
||||||
long storeString(char *str) {
|
|
||||||
return str_helper.store_cstring(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
const char *getString(long id) {
|
|
||||||
auto str = str_helper.get_stored(id);
|
|
||||||
auto cstr = (char *) ::malloc(str.length() + 1);
|
|
||||||
::strcpy(cstr, str.c_str());
|
|
||||||
return cstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
void setUiHandlerTitle(long title) {
|
|
||||||
ui_handler.setTitle(title);
|
|
||||||
}
|
|
||||||
void setUiHandlerMessage(long message) {
|
|
||||||
ui_handler.setMessage(message);
|
|
||||||
}
|
|
||||||
void setUiHandlerWatermark(long wm) {
|
|
||||||
ui_handler.setWatermark(wm);
|
|
||||||
}
|
|
||||||
void setUiHandlerType(int type) {
|
|
||||||
ui_handler.setType(type);
|
|
||||||
}
|
|
||||||
void setUiHandlerKeyboardMode(int mode) {
|
|
||||||
ui_handler.setMode(mode);
|
|
||||||
}
|
|
||||||
void setUiHandlerMinLength(int length) {
|
|
||||||
ui_handler.setMinLength(length);
|
|
||||||
}
|
|
||||||
void setUiHandlerMaxLength(int length) {
|
|
||||||
ui_handler.setMaxLength(length);
|
|
||||||
}
|
|
||||||
void setUiHandlerInitialText(long text) {
|
|
||||||
ui_handler.setInitialText(text);
|
|
||||||
}
|
|
||||||
void setUiHandlerSubtitle(long text) {
|
|
||||||
ui_handler.setSubtitle(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
JNIEXPORT jlong JNICALL
|
|
||||||
Java_org_ryujinx_android_NativeHelpers_storeStringJava(JNIEnv *env, jobject thiz, jstring string) {
|
|
||||||
auto str = getStringPointer(env, string);
|
|
||||||
return str_helper.store_cstring(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
JNIEXPORT jstring JNICALL
|
JNIEXPORT jstring JNICALL
|
||||||
Java_org_ryujinx_android_NativeHelpers_getStringJava(JNIEnv *env, jobject thiz, jlong id) {
|
Java_org_ryujinx_android_NativeHelpers_getStringJava(JNIEnv *env, jobject thiz, jlong ptr) {
|
||||||
return createStringFromStdString(env, id > -1 ? str_helper.get_stored(id) : "");
|
return createString(env, (char*)ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
@ -374,145 +323,3 @@ Java_org_ryujinx_android_NativeHelpers_setIsInitialOrientationFlipped(JNIEnv *en
|
|||||||
jboolean is_flipped) {
|
jboolean is_flipped) {
|
||||||
isInitialOrientationFlipped = is_flipped;
|
isInitialOrientationFlipped = is_flipped;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
|
||||||
JNIEXPORT jint JNICALL
|
|
||||||
Java_org_ryujinx_android_NativeHelpers_getUiHandlerRequestType(JNIEnv *env, jobject thiz) {
|
|
||||||
return ui_handler.type;
|
|
||||||
}
|
|
||||||
extern "C"
|
|
||||||
JNIEXPORT jlong JNICALL
|
|
||||||
Java_org_ryujinx_android_NativeHelpers_getUiHandlerRequestTitle(JNIEnv *env, jobject thiz) {
|
|
||||||
return ui_handler.getTitle();
|
|
||||||
}
|
|
||||||
extern "C"
|
|
||||||
JNIEXPORT jlong JNICALL
|
|
||||||
Java_org_ryujinx_android_NativeHelpers_getUiHandlerRequestMessage(JNIEnv *env, jobject thiz) {
|
|
||||||
return ui_handler.getMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void UiHandler::setTitle(long storedTitle) {
|
|
||||||
if (title != -1) {
|
|
||||||
str_helper.get_stored(title);
|
|
||||||
title = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
title = storedTitle;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UiHandler::setMessage(long storedMessage) {
|
|
||||||
if (message != -1) {
|
|
||||||
str_helper.get_stored(message);
|
|
||||||
message = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message = storedMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UiHandler::setType(int t) {
|
|
||||||
this->type = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
long UiHandler::getTitle() {
|
|
||||||
auto v = title;
|
|
||||||
title = -1;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
long UiHandler::getMessage() {
|
|
||||||
auto v = message;
|
|
||||||
message = -1;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UiHandler::setWatermark(long wm) {
|
|
||||||
if (watermark != -1) {
|
|
||||||
str_helper.get_stored(watermark);
|
|
||||||
watermark = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
watermark = wm;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UiHandler::setMinLength(int t) {
|
|
||||||
this->min_length = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UiHandler::setMaxLength(int t) {
|
|
||||||
this->max_length = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
long UiHandler::getWatermark() {
|
|
||||||
auto v = watermark;
|
|
||||||
watermark = -1;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UiHandler::setInitialText(long text) {
|
|
||||||
if (initialText != -1) {
|
|
||||||
str_helper.get_stored(watermark);
|
|
||||||
initialText = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
initialText = text;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UiHandler::setSubtitle(long text) {
|
|
||||||
if (subtitle != -1) {
|
|
||||||
str_helper.get_stored(subtitle);
|
|
||||||
subtitle = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
subtitle = text;
|
|
||||||
}
|
|
||||||
|
|
||||||
long UiHandler::getInitialText() {
|
|
||||||
auto v = initialText;
|
|
||||||
initialText = -1;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
long UiHandler::getSubtitle() {
|
|
||||||
auto v = subtitle;
|
|
||||||
subtitle = -1;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UiHandler::setMode(int t) {
|
|
||||||
keyboardMode = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
JNIEXPORT jint JNICALL
|
|
||||||
Java_org_ryujinx_android_NativeHelpers_getUiHandlerMinLength(JNIEnv *env, jobject thiz) {
|
|
||||||
return ui_handler.min_length;
|
|
||||||
}
|
|
||||||
extern "C"
|
|
||||||
JNIEXPORT jint JNICALL
|
|
||||||
Java_org_ryujinx_android_NativeHelpers_getUiHandlerMaxLength(JNIEnv *env, jobject thiz) {
|
|
||||||
return ui_handler.max_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
JNIEXPORT jlong JNICALL
|
|
||||||
Java_org_ryujinx_android_NativeHelpers_getUiHandlerRequestWatermark(JNIEnv *env, jobject thiz) {
|
|
||||||
return ui_handler.getWatermark();
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
JNIEXPORT jlong JNICALL
|
|
||||||
Java_org_ryujinx_android_NativeHelpers_getUiHandlerRequestInitialText(JNIEnv *env, jobject thiz) {
|
|
||||||
return ui_handler.getInitialText();
|
|
||||||
}
|
|
||||||
extern "C"
|
|
||||||
JNIEXPORT jlong JNICALL
|
|
||||||
Java_org_ryujinx_android_NativeHelpers_getUiHandlerRequestSubtitle(JNIEnv *env, jobject thiz) {
|
|
||||||
return ui_handler.getSubtitle();
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
JNIEXPORT jint JNICALL
|
|
||||||
Java_org_ryujinx_android_NativeHelpers_getUiHandlerKeyboardMode(JNIEnv *env, jobject thiz) {
|
|
||||||
return ui_handler.keyboardMode;
|
|
||||||
}
|
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Emmanuel Hansen on 10/30/2023.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "string_helper.h"
|
|
||||||
|
|
||||||
long string_helper::store_cstring(const char *cstr) {
|
|
||||||
auto id = ++current_id;
|
|
||||||
_map.insert({id, cstr});
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
long string_helper::store_string(const string& str) {
|
|
||||||
auto id = ++current_id;
|
|
||||||
_map.insert({id, str});
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
string string_helper::get_stored(long id) {
|
|
||||||
auto str = _map[id];
|
|
||||||
_map.erase(id);
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Emmanuel Hansen on 10/30/2023.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef RYUJINXANDROID_STRING_HELPER_H
|
|
||||||
#define RYUJINXANDROID_STRING_HELPER_H
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
using namespace std;
|
|
||||||
class string_helper {
|
|
||||||
public:
|
|
||||||
long store_cstring(const char * cstr);
|
|
||||||
long store_string(const string& str);
|
|
||||||
|
|
||||||
string get_stored(long id);
|
|
||||||
|
|
||||||
string_helper(){
|
|
||||||
_map = unordered_map<long,string>();
|
|
||||||
current_id = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
unordered_map<long, string> _map;
|
|
||||||
long current_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //RYUJINXANDROID_STRING_HELPER_H
|
|
@ -72,7 +72,7 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
|
|||||||
_isInit = false
|
_isInit = false
|
||||||
_isStarted = false
|
_isStarted = false
|
||||||
|
|
||||||
mainViewModel.activity.uiHandler.stop()
|
RyujinxNative.jnaInstance.uiHandlerSetResponse(false, "")
|
||||||
|
|
||||||
_updateThread?.join()
|
_updateThread?.join()
|
||||||
_renderingThreadWatcher?.join()
|
_renderingThreadWatcher?.join()
|
||||||
@ -142,10 +142,6 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun runGame() {
|
private fun runGame() {
|
||||||
|
|
||||||
thread {
|
|
||||||
mainViewModel.activity.uiHandler.listen()
|
|
||||||
}
|
|
||||||
RyujinxNative.jnaInstance.graphicsRendererRunLoop()
|
RyujinxNative.jnaInstance.graphicsRendererRunLoop()
|
||||||
|
|
||||||
game?.close()
|
game?.close()
|
||||||
|
@ -16,6 +16,7 @@ import androidx.core.view.WindowCompat
|
|||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.core.view.WindowInsetsControllerCompat
|
import androidx.core.view.WindowInsetsControllerCompat
|
||||||
import com.anggrayudi.storage.SimpleStorageHelper
|
import com.anggrayudi.storage.SimpleStorageHelper
|
||||||
|
import com.sun.jna.JNIEnv
|
||||||
import org.ryujinx.android.ui.theme.RyujinxAndroidTheme
|
import org.ryujinx.android.ui.theme.RyujinxAndroidTheme
|
||||||
import org.ryujinx.android.viewmodels.MainViewModel
|
import org.ryujinx.android.viewmodels.MainViewModel
|
||||||
import org.ryujinx.android.viewmodels.QuickSettings
|
import org.ryujinx.android.viewmodels.QuickSettings
|
||||||
@ -101,7 +102,7 @@ class MainActivity : BaseActivity() {
|
|||||||
quickSettings.enableTraceLogs
|
quickSettings.enableTraceLogs
|
||||||
)
|
)
|
||||||
val success =
|
val success =
|
||||||
RyujinxNative.jnaInstance.javaInitialize(appPath)
|
RyujinxNative.jnaInstance.javaInitialize(appPath, JNIEnv.CURRENT)
|
||||||
|
|
||||||
uiHandler = UiHandler()
|
uiHandler = UiHandler()
|
||||||
_isInit = success
|
_isInit = success
|
||||||
|
@ -30,16 +30,6 @@ class NativeHelpers {
|
|||||||
external fun setSwapInterval(nativeWindow: Long, swapInterval: Int): Int
|
external fun setSwapInterval(nativeWindow: Long, swapInterval: Int): Int
|
||||||
external fun getProgressInfo(): String
|
external fun getProgressInfo(): String
|
||||||
external fun getProgressValue(): Float
|
external fun getProgressValue(): Float
|
||||||
external fun storeStringJava(string: String): Long
|
external fun getStringJava(ptr: Long): String
|
||||||
external fun getStringJava(id: Long): String
|
|
||||||
external fun setIsInitialOrientationFlipped(isFlipped: Boolean)
|
external fun setIsInitialOrientationFlipped(isFlipped: Boolean)
|
||||||
external fun getUiHandlerRequestType(): Int
|
|
||||||
external fun getUiHandlerRequestTitle(): Long
|
|
||||||
external fun getUiHandlerRequestMessage(): Long
|
|
||||||
external fun getUiHandlerMinLength(): Int
|
|
||||||
external fun getUiHandlerMaxLength(): Int
|
|
||||||
external fun getUiHandlerKeyboardMode(): Int
|
|
||||||
external fun getUiHandlerRequestWatermark(): Long
|
|
||||||
external fun getUiHandlerRequestInitialText(): Long
|
|
||||||
external fun getUiHandlerRequestSubtitle(): Long
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package org.ryujinx.android
|
package org.ryujinx.android
|
||||||
|
|
||||||
|
import com.sun.jna.JNIEnv
|
||||||
import com.sun.jna.Library
|
import com.sun.jna.Library
|
||||||
import com.sun.jna.Native
|
import com.sun.jna.Native
|
||||||
import org.ryujinx.android.viewmodels.GameInfo
|
import org.ryujinx.android.viewmodels.GameInfo
|
||||||
|
import java.util.Collections
|
||||||
|
|
||||||
interface RyujinxNativeJna : Library {
|
interface RyujinxNativeJna : Library {
|
||||||
fun deviceInitialize(
|
fun deviceInitialize(
|
||||||
@ -35,7 +37,7 @@ interface RyujinxNativeJna : Library {
|
|||||||
driver: Long
|
driver: Long
|
||||||
): Boolean
|
): Boolean
|
||||||
|
|
||||||
fun javaInitialize(appPath: String): Boolean
|
fun javaInitialize(appPath: String, env: JNIEnv): Boolean
|
||||||
fun deviceLaunchMiiEditor(): Boolean
|
fun deviceLaunchMiiEditor(): Boolean
|
||||||
fun deviceGetGameFrameRate(): Double
|
fun deviceGetGameFrameRate(): Double
|
||||||
fun deviceGetGameFrameTime(): Double
|
fun deviceGetGameFrameTime(): Double
|
||||||
@ -73,9 +75,7 @@ interface RyujinxNativeJna : Library {
|
|||||||
fun deviceInstallFirmware(fileDescriptor: Int, isXci: Boolean)
|
fun deviceInstallFirmware(fileDescriptor: Int, isXci: Boolean)
|
||||||
fun deviceGetInstalledFirmwareVersion(): String
|
fun deviceGetInstalledFirmwareVersion(): String
|
||||||
fun uiHandlerSetup()
|
fun uiHandlerSetup()
|
||||||
fun uiHandlerWait()
|
fun uiHandlerSetResponse(isOkPressed: Boolean, input: String)
|
||||||
fun uiHandlerStopWait()
|
|
||||||
fun uiHandlerSetResponse(isOkPressed: Boolean, input: Long)
|
|
||||||
fun deviceGetDlcTitleId(path: String, ncaPath: String): String
|
fun deviceGetDlcTitleId(path: String, ncaPath: String): String
|
||||||
fun deviceGetGameInfo(fileDescriptor: Int, extension: String, info: GameInfo)
|
fun deviceGetGameInfo(fileDescriptor: Int, extension: String, info: GameInfo)
|
||||||
fun userGetAllUsers(): Array<String>
|
fun userGetAllUsers(): Array<String>
|
||||||
@ -88,7 +88,47 @@ class RyujinxNative {
|
|||||||
companion object {
|
companion object {
|
||||||
val jnaInstance: RyujinxNativeJna = Native.load(
|
val jnaInstance: RyujinxNativeJna = Native.load(
|
||||||
"ryujinx",
|
"ryujinx",
|
||||||
RyujinxNativeJna::class.java
|
RyujinxNativeJna::class.java,
|
||||||
|
Collections.singletonMap(Library.OPTION_ALLOW_OBJECTS, true)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun test()
|
||||||
|
{
|
||||||
|
val i = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun updateUiHandler(
|
||||||
|
newTitlePointer: Long,
|
||||||
|
newMessagePointer: Long,
|
||||||
|
newWatermarkPointer: Long,
|
||||||
|
newType: Int,
|
||||||
|
min: Int,
|
||||||
|
max: Int,
|
||||||
|
nMode: Int,
|
||||||
|
newSubtitlePointer: Long,
|
||||||
|
newInitialTextPointer: Long
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var uiHandler = MainActivity.mainViewModel?.activity?.uiHandler
|
||||||
|
uiHandler?.apply {
|
||||||
|
val newTitle = NativeHelpers.instance.getStringJava(newTitlePointer)
|
||||||
|
val newMessage = NativeHelpers.instance.getStringJava(newMessagePointer)
|
||||||
|
val newWatermark = NativeHelpers.instance.getStringJava(newWatermarkPointer)
|
||||||
|
val newSubtitle = NativeHelpers.instance.getStringJava(newSubtitlePointer)
|
||||||
|
val newInitialText = NativeHelpers.instance.getStringJava(newInitialTextPointer)
|
||||||
|
val newMode = KeyboardMode.entries[nMode]
|
||||||
|
update(newTitle,
|
||||||
|
newMessage,
|
||||||
|
newWatermark,
|
||||||
|
newType,
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
newMode,
|
||||||
|
newSubtitle,
|
||||||
|
newInitialText);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ import androidx.compose.foundation.rememberScrollState
|
|||||||
import androidx.compose.foundation.text.KeyboardActions
|
import androidx.compose.foundation.text.KeyboardActions
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.AlertDialog
|
|
||||||
import androidx.compose.material3.AlertDialogDefaults
|
import androidx.compose.material3.AlertDialogDefaults
|
||||||
import androidx.compose.material3.BasicAlertDialog
|
import androidx.compose.material3.BasicAlertDialog
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
@ -32,7 +31,7 @@ import androidx.compose.ui.window.DialogProperties
|
|||||||
import com.halilibo.richtext.markdown.Markdown
|
import com.halilibo.richtext.markdown.Markdown
|
||||||
import com.halilibo.richtext.ui.material3.RichText
|
import com.halilibo.richtext.ui.material3.RichText
|
||||||
|
|
||||||
internal enum class KeyboardMode {
|
enum class KeyboardMode {
|
||||||
Default, Numeric, ASCII, FullLatin, Alphabet, SimplifiedChinese, TraditionalChinese, Korean, LanguageSet2, LanguageSet2Latin
|
Default, Numeric, ASCII, FullLatin, Alphabet, SimplifiedChinese, TraditionalChinese, Korean, LanguageSet2, LanguageSet2Latin
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,39 +47,34 @@ class UiHandler {
|
|||||||
val inputText = mutableStateOf("")
|
val inputText = mutableStateOf("")
|
||||||
var title: String = ""
|
var title: String = ""
|
||||||
var message: String = ""
|
var message: String = ""
|
||||||
var shouldListen = true
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
RyujinxNative.jnaInstance.uiHandlerSetup()
|
RyujinxNative.jnaInstance.uiHandlerSetup()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun listen() {
|
fun update(
|
||||||
showMessage.value = false
|
newTitle: String,
|
||||||
while (shouldListen) {
|
newMessage: String,
|
||||||
RyujinxNative.jnaInstance.uiHandlerWait()
|
newWatermark: String,
|
||||||
|
newType: Int,
|
||||||
title =
|
min: Int,
|
||||||
NativeHelpers.instance.getStringJava(NativeHelpers.instance.getUiHandlerRequestTitle())
|
max: Int,
|
||||||
message =
|
newMode: KeyboardMode,
|
||||||
NativeHelpers.instance.getStringJava(NativeHelpers.instance.getUiHandlerRequestMessage())
|
newSubtitle: String,
|
||||||
watermark =
|
newInitialText: String
|
||||||
NativeHelpers.instance.getStringJava(NativeHelpers.instance.getUiHandlerRequestWatermark())
|
)
|
||||||
type = NativeHelpers.instance.getUiHandlerRequestType()
|
{
|
||||||
minLength = NativeHelpers.instance.getUiHandlerMinLength()
|
title = newTitle
|
||||||
maxLength = NativeHelpers.instance.getUiHandlerMaxLength()
|
message = newMessage
|
||||||
mode = KeyboardMode.values()[NativeHelpers.instance.getUiHandlerKeyboardMode()]
|
watermark = newWatermark
|
||||||
subtitle =
|
type = newType
|
||||||
NativeHelpers.instance.getStringJava(NativeHelpers.instance.getUiHandlerRequestSubtitle())
|
minLength = min
|
||||||
initialText =
|
maxLength = max
|
||||||
NativeHelpers.instance.getStringJava(NativeHelpers.instance.getUiHandlerRequestInitialText())
|
mode = newMode
|
||||||
inputText.value = initialText
|
subtitle = newSubtitle
|
||||||
showMessage.value = type > 0
|
initialText = newInitialText
|
||||||
}
|
inputText.value = initialText
|
||||||
}
|
showMessage.value = type > 0
|
||||||
|
|
||||||
fun stop() {
|
|
||||||
shouldListen = false
|
|
||||||
RyujinxNative.jnaInstance.uiHandlerStopWait()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@ -119,15 +113,15 @@ class UiHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun submit() {
|
fun submit() {
|
||||||
var input: Long = -1
|
|
||||||
if (type == 2) {
|
if (type == 2) {
|
||||||
if (inputListener.value.length < minLength || inputListener.value.length > maxLength)
|
if (inputListener.value.length < minLength || inputListener.value.length > maxLength)
|
||||||
return
|
return
|
||||||
input =
|
|
||||||
NativeHelpers.instance.storeStringJava(inputListener.value)
|
|
||||||
}
|
}
|
||||||
|
RyujinxNative.jnaInstance.uiHandlerSetResponse(
|
||||||
|
true,
|
||||||
|
if (type == 2) inputListener.value else ""
|
||||||
|
)
|
||||||
showMessageListener.value = false
|
showMessageListener.value = false
|
||||||
RyujinxNative.jnaInstance.uiHandlerSetResponse(true, input)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showMessageListener.value) {
|
if (showMessageListener.value) {
|
||||||
|
@ -24,7 +24,7 @@ android.nonTransitiveRClass=true
|
|||||||
# Build configuration
|
# Build configuration
|
||||||
# It needs to be set to either "debug" or "release" and can also be overriden on a per build basis
|
# It needs to be set to either "debug" or "release" and can also be overriden on a per build basis
|
||||||
# by adding -Dorg.ryujinx.config=NAME to the command line.
|
# by adding -Dorg.ryujinx.config=NAME to the command line.
|
||||||
org.ryujinx.config=release
|
org.ryujinx.config=debug
|
||||||
# Controls stripping of symbols from libryujinx
|
# Controls stripping of symbols from libryujinx
|
||||||
# Setting this property to auto causes symbols to be stripped for release builds,
|
# Setting this property to auto causes symbols to be stripped for release builds,
|
||||||
# but not for debug builds.
|
# but not for debug builds.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user