forked from MeloNX/MeloNX
add basic touch and button input interface
This commit is contained in:
parent
24b8d7c981
commit
c27a12df2c
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -38,6 +39,33 @@ namespace LibRyujinx.Sample
|
|||||||
|
|
||||||
[DllImport(dll, EntryPoint = "graphics_renderer_set_vsync")]
|
[DllImport(dll, EntryPoint = "graphics_renderer_set_vsync")]
|
||||||
internal extern static void SetVsyncState(bool enabled);
|
internal extern static void SetVsyncState(bool enabled);
|
||||||
|
|
||||||
|
[DllImport(dll, EntryPoint = "input_initialize")]
|
||||||
|
internal extern static void InitializeInput(int width, int height);
|
||||||
|
|
||||||
|
[DllImport(dll, EntryPoint = "input_set_client_size")]
|
||||||
|
internal extern static void SetClientSize(int width, int height);
|
||||||
|
|
||||||
|
[DllImport(dll, EntryPoint = "input_set_touch_point")]
|
||||||
|
internal extern static void SetTouchPoint(int x, int y);
|
||||||
|
|
||||||
|
[DllImport(dll, EntryPoint = "input_release_touch_point")]
|
||||||
|
internal extern static void ReleaseTouchPoint();
|
||||||
|
|
||||||
|
[DllImport(dll, EntryPoint = "input_update")]
|
||||||
|
internal extern static void UpdateInput();
|
||||||
|
|
||||||
|
[DllImport(dll, EntryPoint = "input_set_button_pressed")]
|
||||||
|
public extern static void SetButtonPressed(GamepadButtonInputId button, IntPtr idPtr);
|
||||||
|
|
||||||
|
[DllImport(dll, EntryPoint = "input_set_button_released")]
|
||||||
|
public extern static void SetButtonReleased(GamepadButtonInputId button, IntPtr idPtr);
|
||||||
|
|
||||||
|
[DllImport(dll, EntryPoint = "input_set_stick_axis")]
|
||||||
|
public extern static void SetStickAxis(StickInputId stick, Vector2 axes, IntPtr idPtr);
|
||||||
|
|
||||||
|
[DllImport(dll, EntryPoint = "input_connect_gamepad")]
|
||||||
|
public extern static IntPtr ConnectGamepad(int index);
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
@ -53,11 +81,13 @@ namespace LibRyujinx.Sample
|
|||||||
public bool EnableSpirvCompilationOnVulkan = true;
|
public bool EnableSpirvCompilationOnVulkan = true;
|
||||||
public bool EnableTextureRecompression = false;
|
public bool EnableTextureRecompression = false;
|
||||||
public BackendThreading BackendThreading = BackendThreading.Auto;
|
public BackendThreading BackendThreading = BackendThreading.Auto;
|
||||||
|
public AspectRatio AspectRatio = AspectRatio.Fixed16x9;
|
||||||
|
|
||||||
public GraphicsConfiguration()
|
public GraphicsConfiguration()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum GraphicsBackend
|
public enum GraphicsBackend
|
||||||
{
|
{
|
||||||
Vulkan,
|
Vulkan,
|
||||||
@ -78,4 +108,77 @@ namespace LibRyujinx.Sample
|
|||||||
public IntPtr VkRequiredExtensions;
|
public IntPtr VkRequiredExtensions;
|
||||||
public int VkRequiredExtensionsCount;
|
public int VkRequiredExtensionsCount;
|
||||||
}
|
}
|
||||||
|
public enum AspectRatio
|
||||||
|
{
|
||||||
|
Fixed4x3,
|
||||||
|
Fixed16x9,
|
||||||
|
Fixed16x10,
|
||||||
|
Fixed21x9,
|
||||||
|
Fixed32x9,
|
||||||
|
Stretched
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represent a button from a gamepad.
|
||||||
|
/// </summary>
|
||||||
|
public enum GamepadButtonInputId : byte
|
||||||
|
{
|
||||||
|
Unbound,
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
X,
|
||||||
|
Y,
|
||||||
|
LeftStick,
|
||||||
|
RightStick,
|
||||||
|
LeftShoulder,
|
||||||
|
RightShoulder,
|
||||||
|
|
||||||
|
// Likely axis
|
||||||
|
LeftTrigger,
|
||||||
|
// Likely axis
|
||||||
|
RightTrigger,
|
||||||
|
|
||||||
|
DpadUp,
|
||||||
|
DpadDown,
|
||||||
|
DpadLeft,
|
||||||
|
DpadRight,
|
||||||
|
|
||||||
|
// Special buttons
|
||||||
|
|
||||||
|
Minus,
|
||||||
|
Plus,
|
||||||
|
|
||||||
|
Back = Minus,
|
||||||
|
Start = Plus,
|
||||||
|
|
||||||
|
Guide,
|
||||||
|
Misc1,
|
||||||
|
|
||||||
|
// Xbox Elite paddle
|
||||||
|
Paddle1,
|
||||||
|
Paddle2,
|
||||||
|
Paddle3,
|
||||||
|
Paddle4,
|
||||||
|
|
||||||
|
// PS5 touchpad button
|
||||||
|
Touchpad,
|
||||||
|
|
||||||
|
// Virtual buttons for single joycon
|
||||||
|
SingleLeftTrigger0,
|
||||||
|
SingleRightTrigger0,
|
||||||
|
|
||||||
|
SingleLeftTrigger1,
|
||||||
|
SingleRightTrigger1,
|
||||||
|
|
||||||
|
Count
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum StickInputId : byte
|
||||||
|
{
|
||||||
|
Unbound,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
|
||||||
|
Count
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
using LibRyujinx.Sample;
|
using LibRyujinx.Sample;
|
||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
|
using OpenTK.Mathematics;
|
||||||
|
using OpenTK.Windowing.Common;
|
||||||
using OpenTK.Windowing.Desktop;
|
using OpenTK.Windowing.Desktop;
|
||||||
using OpenTK.Windowing.GraphicsLibraryFramework;
|
using OpenTK.Windowing.GraphicsLibraryFramework;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
@ -13,7 +15,12 @@ namespace LibRyujinx.NativeSample
|
|||||||
public delegate IntPtr GetProcAddress(string name);
|
public delegate IntPtr GetProcAddress(string name);
|
||||||
public delegate IntPtr CreateSurface(IntPtr instance);
|
public delegate IntPtr CreateSurface(IntPtr instance);
|
||||||
|
|
||||||
|
private bool _run;
|
||||||
private bool _isVulkan;
|
private bool _isVulkan;
|
||||||
|
private Vector2 _lastPosition;
|
||||||
|
private bool _mousePressed;
|
||||||
|
private nint _gamepadIdPtr;
|
||||||
|
private string? _gamepadId;
|
||||||
|
|
||||||
public NativeWindow(NativeWindowSettings nativeWindowSettings) : base(nativeWindowSettings)
|
public NativeWindow(NativeWindowSettings nativeWindowSettings) : base(nativeWindowSettings)
|
||||||
{
|
{
|
||||||
@ -55,6 +62,7 @@ namespace LibRyujinx.NativeSample
|
|||||||
};
|
};
|
||||||
var success = LibRyujinxInterop.InitializeGraphicsRenderer(_isVulkan ? GraphicsBackend.Vulkan : GraphicsBackend.OpenGl, nativeGraphicsInterop);
|
var success = LibRyujinxInterop.InitializeGraphicsRenderer(_isVulkan ? GraphicsBackend.Vulkan : GraphicsBackend.OpenGl, nativeGraphicsInterop);
|
||||||
success = LibRyujinxInterop.InitializeDevice();
|
success = LibRyujinxInterop.InitializeDevice();
|
||||||
|
LibRyujinxInterop.InitializeInput(ClientSize.X, ClientSize.Y);
|
||||||
|
|
||||||
var path = Marshal.StringToHGlobalAnsi(gamePath);
|
var path = Marshal.StringToHGlobalAnsi(gamePath);
|
||||||
var loaded = LibRyujinxInterop.LoadApplication(path);
|
var loaded = LibRyujinxInterop.LoadApplication(path);
|
||||||
@ -62,19 +70,28 @@ namespace LibRyujinx.NativeSample
|
|||||||
Marshal.FreeHGlobal(path);
|
Marshal.FreeHGlobal(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_gamepadIdPtr = LibRyujinxInterop.ConnectGamepad(0);
|
||||||
|
_gamepadId = Marshal.PtrToStringAnsi(_gamepadIdPtr);
|
||||||
|
|
||||||
if (!_isVulkan)
|
if (!_isVulkan)
|
||||||
{
|
{
|
||||||
Context.MakeNoneCurrent();
|
Context.MakeNoneCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_run = true;
|
||||||
var thread = new Thread(new ThreadStart(RunLoop));
|
var thread = new Thread(new ThreadStart(RunLoop));
|
||||||
thread.Start();
|
thread.Start();
|
||||||
|
|
||||||
|
UpdateLoop();
|
||||||
|
|
||||||
thread.Join();
|
thread.Join();
|
||||||
|
|
||||||
foreach(var ptr in pointers)
|
foreach(var ptr in pointers)
|
||||||
{
|
{
|
||||||
Marshal.FreeHGlobal(ptr);
|
Marshal.FreeHGlobal(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Marshal.FreeHGlobal(_gamepadIdPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RunLoop()
|
public void RunLoop()
|
||||||
@ -89,15 +106,17 @@ namespace LibRyujinx.NativeSample
|
|||||||
Context.SwapInterval = 0;
|
Context.SwapInterval = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Task.Run(async () =>
|
/* Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await Task.Delay(1000);
|
await Task.Delay(1000);
|
||||||
|
|
||||||
LibRyujinxInterop.SetVsyncState(false);
|
LibRyujinxInterop.SetVsyncState(true);
|
||||||
});
|
});*/
|
||||||
|
|
||||||
LibRyujinxInterop.RunLoop();
|
LibRyujinxInterop.RunLoop();
|
||||||
|
|
||||||
|
_run = false;
|
||||||
|
|
||||||
if (!_isVulkan)
|
if (!_isVulkan)
|
||||||
{
|
{
|
||||||
Context.MakeNoneCurrent();
|
Context.MakeNoneCurrent();
|
||||||
@ -111,5 +130,120 @@ namespace LibRyujinx.NativeSample
|
|||||||
this.Context.SwapBuffers();
|
this.Context.SwapBuffers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseMove(MouseMoveEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnMouseMove(e);
|
||||||
|
_lastPosition = e.Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseDown(MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnMouseDown(e);
|
||||||
|
if(e.Button == MouseButton.Left)
|
||||||
|
{
|
||||||
|
_mousePressed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnResize(ResizeEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnResize(e);
|
||||||
|
|
||||||
|
if (_run)
|
||||||
|
{
|
||||||
|
LibRyujinxInterop.SetRendererSize(e.Width, e.Height);
|
||||||
|
LibRyujinxInterop.SetClientSize(e.Width, e.Height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseUp(MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnMouseUp(e);
|
||||||
|
if (e.Button == MouseButton.Left)
|
||||||
|
{
|
||||||
|
_mousePressed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnKeyUp(KeyboardKeyEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnKeyUp(e);
|
||||||
|
|
||||||
|
if (_gamepadIdPtr != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
var key = GetKeyMapping(e.Key);
|
||||||
|
|
||||||
|
LibRyujinxInterop.SetButtonReleased(key, _gamepadIdPtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnKeyDown(KeyboardKeyEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnKeyDown(e);
|
||||||
|
|
||||||
|
if (_gamepadIdPtr != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
var key = GetKeyMapping(e.Key);
|
||||||
|
|
||||||
|
LibRyujinxInterop.SetButtonPressed(key, _gamepadIdPtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateLoop()
|
||||||
|
{
|
||||||
|
while(_run)
|
||||||
|
{
|
||||||
|
ProcessWindowEvents(true);
|
||||||
|
ProcessInputEvents();
|
||||||
|
ProcessWindowEvents(IsEventDriven);
|
||||||
|
if (_mousePressed)
|
||||||
|
{
|
||||||
|
LibRyujinxInterop.SetTouchPoint((int)_lastPosition.X, (int)_lastPosition.Y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LibRyujinxInterop.ReleaseTouchPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
LibRyujinxInterop.UpdateInput();
|
||||||
|
|
||||||
|
Thread.Sleep(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GamepadButtonInputId GetKeyMapping(Keys key)
|
||||||
|
{
|
||||||
|
if(_keyMapping.TryGetValue(key, out var mapping))
|
||||||
|
{
|
||||||
|
return mapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GamepadButtonInputId.Unbound;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<Keys, GamepadButtonInputId> _keyMapping = new Dictionary<Keys, GamepadButtonInputId>()
|
||||||
|
{
|
||||||
|
{Keys.A, GamepadButtonInputId.A },
|
||||||
|
{Keys.S, GamepadButtonInputId.B },
|
||||||
|
{Keys.Z, GamepadButtonInputId.X },
|
||||||
|
{Keys.X, GamepadButtonInputId.Y },
|
||||||
|
{Keys.Equal, GamepadButtonInputId.Plus },
|
||||||
|
{Keys.Minus, GamepadButtonInputId.Minus },
|
||||||
|
{Keys.Q, GamepadButtonInputId.LeftShoulder },
|
||||||
|
{Keys.D1, GamepadButtonInputId.LeftTrigger },
|
||||||
|
{Keys.W, GamepadButtonInputId.RightShoulder },
|
||||||
|
{Keys.D2, GamepadButtonInputId.RightTrigger },
|
||||||
|
{Keys.E, GamepadButtonInputId.LeftStick },
|
||||||
|
{Keys.R, GamepadButtonInputId.RightStick },
|
||||||
|
{Keys.Up, GamepadButtonInputId.DpadUp },
|
||||||
|
{Keys.Down, GamepadButtonInputId.DpadDown },
|
||||||
|
{Keys.Left, GamepadButtonInputId.DpadLeft },
|
||||||
|
{Keys.Right, GamepadButtonInputId.DpadRight },
|
||||||
|
{Keys.U, GamepadButtonInputId.SingleLeftTrigger0 },
|
||||||
|
{Keys.D7, GamepadButtonInputId.SingleLeftTrigger1 },
|
||||||
|
{Keys.O, GamepadButtonInputId.SingleRightTrigger0 },
|
||||||
|
{Keys.D9, GamepadButtonInputId.SingleRightTrigger1 }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ namespace LibRyujinx.NativeSample
|
|||||||
Size = new Vector2i(800, 600),
|
Size = new Vector2i(800, 600),
|
||||||
Title = "Ryujinx",
|
Title = "Ryujinx",
|
||||||
API = ContextAPI.NoAPI,
|
API = ContextAPI.NoAPI,
|
||||||
IsEventDriven = true,
|
IsEventDriven = false,
|
||||||
// This is needed to run on macos
|
// This is needed to run on macos
|
||||||
Flags = ContextFlags.ForwardCompatible,
|
Flags = ContextFlags.ForwardCompatible,
|
||||||
};
|
};
|
||||||
|
@ -207,6 +207,7 @@ namespace LibRyujinx
|
|||||||
public bool EnableSpirvCompilationOnVulkan = true;
|
public bool EnableSpirvCompilationOnVulkan = true;
|
||||||
public bool EnableTextureRecompression = false;
|
public bool EnableTextureRecompression = false;
|
||||||
public BackendThreading BackendThreading = BackendThreading.Auto;
|
public BackendThreading BackendThreading = BackendThreading.Auto;
|
||||||
|
public AspectRatio AspectRatio = AspectRatio.Fixed16x9;
|
||||||
|
|
||||||
public GraphicsConfiguration()
|
public GraphicsConfiguration()
|
||||||
{
|
{
|
||||||
|
@ -1,12 +1,562 @@
|
|||||||
using System;
|
using DiscordRPC;
|
||||||
|
using Ryujinx.Common.Configuration;
|
||||||
|
using Ryujinx.Common.Configuration.Hid;
|
||||||
|
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||||
|
using Ryujinx.Common.Configuration.Hid.Controller.Motion;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Common.Memory;
|
||||||
|
using Ryujinx.Input;
|
||||||
|
using Ryujinx.Input.HLE;
|
||||||
|
using Ryujinx.Ui.Common.Configuration;
|
||||||
|
using Silk.NET.Vulkan;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId;
|
||||||
|
using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
|
||||||
|
using StickInputId = Ryujinx.Input.StickInputId;
|
||||||
|
|
||||||
namespace LibRyujinx
|
namespace LibRyujinx
|
||||||
{
|
{
|
||||||
public static partial class LibRyujinx
|
public static partial class LibRyujinx
|
||||||
{
|
{
|
||||||
|
private static VirtualGamepadDriver? _gamepadDriver;
|
||||||
|
private static VirtualTouchScreen? _virtualTouchScreen;
|
||||||
|
private static VirtualTouchScreenDriver? _touchScreenDriver;
|
||||||
|
private static TouchScreenManager? _touchScreenManager;
|
||||||
|
private static InputManager? _inputManager;
|
||||||
|
private static NpadManager _npadManager;
|
||||||
|
private static InputConfig[] _configs;
|
||||||
|
|
||||||
|
public static void InitializeInput(int width, int height)
|
||||||
|
{
|
||||||
|
if(SwitchDevice!.InputManager != null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Input is already initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
_gamepadDriver = new VirtualGamepadDriver(4);
|
||||||
|
_configs = new InputConfig[4];
|
||||||
|
_virtualTouchScreen = new VirtualTouchScreen();
|
||||||
|
_touchScreenDriver = new VirtualTouchScreenDriver(_virtualTouchScreen);
|
||||||
|
_inputManager = new InputManager(null, _gamepadDriver);
|
||||||
|
_inputManager.SetMouseDriver(_touchScreenDriver);
|
||||||
|
_npadManager = _inputManager.CreateNpadManager();
|
||||||
|
|
||||||
|
SwitchDevice!.InputManager = _inputManager;
|
||||||
|
|
||||||
|
_touchScreenManager = _inputManager.CreateTouchScreenManager();
|
||||||
|
_touchScreenManager.Initialize(SwitchDevice!.EmulationContext);
|
||||||
|
|
||||||
|
_npadManager.Initialize(SwitchDevice.EmulationContext, new List<InputConfig>(), false, false);
|
||||||
|
|
||||||
|
_virtualTouchScreen.ClientSize = new Size(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetClientSize(int width, int height)
|
||||||
|
{
|
||||||
|
_virtualTouchScreen!.ClientSize = new Size(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetTouchPoint(int x, int y)
|
||||||
|
{
|
||||||
|
_virtualTouchScreen?.SetPosition(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ReleaseTouchPoint()
|
||||||
|
{
|
||||||
|
_virtualTouchScreen?.ReleaseTouch();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetButtonPressed(GamepadButtonInputId button, string id)
|
||||||
|
{
|
||||||
|
_gamepadDriver?.SetButtonPressed(button, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetButtonReleased(GamepadButtonInputId button, string id)
|
||||||
|
{
|
||||||
|
_gamepadDriver?.SetButtonReleased(button, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetStickAxis(StickInputId stick, Vector2 axes, string deviceId)
|
||||||
|
{
|
||||||
|
_gamepadDriver?.SetStickAxis(stick, axes, deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ConnectGamepad(int index)
|
||||||
|
{
|
||||||
|
var gamepad = _gamepadDriver?.GetGamepad(index);
|
||||||
|
if (gamepad != null)
|
||||||
|
{
|
||||||
|
var config = CreateDefaultInputConfig();
|
||||||
|
|
||||||
|
config.Id = gamepad.Id;
|
||||||
|
config.PlayerIndex = (PlayerIndex)index;
|
||||||
|
|
||||||
|
_configs[index] = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
_npadManager?.ReloadConfiguration(_configs.Where(x => x != null).ToList(), false, false);
|
||||||
|
|
||||||
|
return gamepad?.Id ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InputConfig CreateDefaultInputConfig()
|
||||||
|
{
|
||||||
|
return new StandardControllerInputConfig
|
||||||
|
{
|
||||||
|
Version = InputConfig.CurrentVersion,
|
||||||
|
Backend = InputBackendType.GamepadSDL2,
|
||||||
|
Id = null,
|
||||||
|
ControllerType = ControllerType.JoyconPair,
|
||||||
|
DeadzoneLeft = 0.1f,
|
||||||
|
DeadzoneRight = 0.1f,
|
||||||
|
RangeLeft = 1.0f,
|
||||||
|
RangeRight = 1.0f,
|
||||||
|
TriggerThreshold = 0.5f,
|
||||||
|
LeftJoycon = new LeftJoyconCommonConfig<ConfigGamepadInputId>
|
||||||
|
{
|
||||||
|
DpadUp = ConfigGamepadInputId.DpadUp,
|
||||||
|
DpadDown = ConfigGamepadInputId.DpadDown,
|
||||||
|
DpadLeft = ConfigGamepadInputId.DpadLeft,
|
||||||
|
DpadRight = ConfigGamepadInputId.DpadRight,
|
||||||
|
ButtonMinus = ConfigGamepadInputId.Minus,
|
||||||
|
ButtonL = ConfigGamepadInputId.LeftShoulder,
|
||||||
|
ButtonZl = ConfigGamepadInputId.LeftTrigger,
|
||||||
|
ButtonSl = ConfigGamepadInputId.Unbound,
|
||||||
|
ButtonSr = ConfigGamepadInputId.Unbound,
|
||||||
|
},
|
||||||
|
|
||||||
|
LeftJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
|
||||||
|
{
|
||||||
|
Joystick = ConfigStickInputId.Left,
|
||||||
|
StickButton = ConfigGamepadInputId.LeftStick,
|
||||||
|
InvertStickX = false,
|
||||||
|
InvertStickY = false,
|
||||||
|
Rotate90CW = false,
|
||||||
|
},
|
||||||
|
|
||||||
|
RightJoycon = new RightJoyconCommonConfig<ConfigGamepadInputId>
|
||||||
|
{
|
||||||
|
ButtonA = ConfigGamepadInputId.A,
|
||||||
|
ButtonB = ConfigGamepadInputId.B,
|
||||||
|
ButtonX = ConfigGamepadInputId.X,
|
||||||
|
ButtonY = ConfigGamepadInputId.Y,
|
||||||
|
ButtonPlus = ConfigGamepadInputId.Plus,
|
||||||
|
ButtonR = ConfigGamepadInputId.RightShoulder,
|
||||||
|
ButtonZr = ConfigGamepadInputId.RightTrigger,
|
||||||
|
ButtonSl = ConfigGamepadInputId.Unbound,
|
||||||
|
ButtonSr = ConfigGamepadInputId.Unbound,
|
||||||
|
},
|
||||||
|
|
||||||
|
RightJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
|
||||||
|
{
|
||||||
|
Joystick = ConfigStickInputId.Right,
|
||||||
|
StickButton = ConfigGamepadInputId.RightStick,
|
||||||
|
InvertStickX = false,
|
||||||
|
InvertStickY = false,
|
||||||
|
Rotate90CW = false,
|
||||||
|
},
|
||||||
|
|
||||||
|
Motion = new StandardMotionConfigController
|
||||||
|
{
|
||||||
|
MotionBackend = MotionInputBackendType.GamepadDriver,
|
||||||
|
EnableMotion = true,
|
||||||
|
Sensitivity = 100,
|
||||||
|
GyroDeadzone = 1,
|
||||||
|
},
|
||||||
|
Rumble = new RumbleConfigController
|
||||||
|
{
|
||||||
|
StrongRumble = 1f,
|
||||||
|
WeakRumble = 1f,
|
||||||
|
EnableRumble = false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UpdateInput()
|
||||||
|
{
|
||||||
|
_npadManager?.Update(GraphicsConfiguration.AspectRatio.ToFloat());
|
||||||
|
|
||||||
|
if(!_touchScreenManager!.Update(true, _virtualTouchScreen!.IsButtonPressed(MouseButton.Button1), GraphicsConfiguration.AspectRatio.ToFloat()))
|
||||||
|
{
|
||||||
|
SwitchDevice!.EmulationContext?.Hid.Touchscreen.Update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Native Methods
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly(EntryPoint = "input_initialize")]
|
||||||
|
public static void InitializeInputNative(int width, int height)
|
||||||
|
{
|
||||||
|
InitializeInput(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly(EntryPoint = "input_set_client_size")]
|
||||||
|
public static void SetClientSizeNative(int width, int height)
|
||||||
|
{
|
||||||
|
SetClientSize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly(EntryPoint = "input_set_touch_point")]
|
||||||
|
public static void SetTouchPointNative(int x, int y)
|
||||||
|
{
|
||||||
|
SetTouchPoint(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly(EntryPoint = "input_release_touch_point")]
|
||||||
|
public static void ReleaseTouchPointNative()
|
||||||
|
{
|
||||||
|
ReleaseTouchPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly(EntryPoint = "input_update")]
|
||||||
|
public static void UpdateInputNative()
|
||||||
|
{
|
||||||
|
UpdateInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly(EntryPoint = "input_set_button_pressed")]
|
||||||
|
public static void SetButtonPressedNative(GamepadButtonInputId button, IntPtr idPtr)
|
||||||
|
{
|
||||||
|
var id = Marshal.PtrToStringAnsi(idPtr);
|
||||||
|
SetButtonPressed(button, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly(EntryPoint = "input_set_button_released")]
|
||||||
|
public static void SetButtonReleased(GamepadButtonInputId button, IntPtr idPtr)
|
||||||
|
{
|
||||||
|
var id = Marshal.PtrToStringAnsi(idPtr);
|
||||||
|
SetButtonReleased(button, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly(EntryPoint = "input_set_stick_axis")]
|
||||||
|
public static void SetStickAxisNative(StickInputId stick, Vector2 axes, IntPtr idPtr)
|
||||||
|
{
|
||||||
|
var id = Marshal.PtrToStringAnsi(idPtr);
|
||||||
|
SetStickAxis(stick, axes, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly(EntryPoint = "input_connect_gamepad")]
|
||||||
|
public static IntPtr ConnectGamepadNative(int index)
|
||||||
|
{
|
||||||
|
var id = ConnectGamepad(index);
|
||||||
|
|
||||||
|
return Marshal.StringToHGlobalAnsi(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class VirtualTouchScreen : IMouse
|
||||||
|
{
|
||||||
|
public Size ClientSize { get; set; }
|
||||||
|
|
||||||
|
public bool[] Buttons { get; }
|
||||||
|
|
||||||
|
public VirtualTouchScreen()
|
||||||
|
{
|
||||||
|
Buttons = new bool[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2 CurrentPosition { get; private set; }
|
||||||
|
public Vector2 Scroll { get; private set; }
|
||||||
|
public string Id => "0";
|
||||||
|
public string Name => "AvaloniaMouse";
|
||||||
|
|
||||||
|
public bool IsConnected => true;
|
||||||
|
public GamepadFeaturesFlag Features => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public GamepadStateSnapshot GetMappedStateSnapshot()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetPosition(int x, int y)
|
||||||
|
{
|
||||||
|
CurrentPosition = new Vector2(x, y);
|
||||||
|
|
||||||
|
Buttons[0] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReleaseTouch()
|
||||||
|
{
|
||||||
|
Buttons[0] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 GetMotionData(MotionInputId inputId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2 GetPosition()
|
||||||
|
{
|
||||||
|
return CurrentPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2 GetScroll()
|
||||||
|
{
|
||||||
|
return Scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GamepadStateSnapshot GetStateSnapshot()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public (float, float) GetStick(Ryujinx.Input.StickInputId inputId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsButtonPressed(MouseButton button)
|
||||||
|
{
|
||||||
|
return Buttons[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsPressed(GamepadButtonInputId inputId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetConfiguration(InputConfig configuration)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetTriggerThreshold(float triggerThreshold)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class VirtualTouchScreenDriver : IGamepadDriver
|
||||||
|
{
|
||||||
|
private readonly VirtualTouchScreen _virtualTouchScreen;
|
||||||
|
|
||||||
|
public VirtualTouchScreenDriver(VirtualTouchScreen virtualTouchScreen)
|
||||||
|
{
|
||||||
|
_virtualTouchScreen = virtualTouchScreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string DriverName => "VirtualTouchDriver";
|
||||||
|
|
||||||
|
public ReadOnlySpan<string> GamepadsIds => new[] { "0" };
|
||||||
|
|
||||||
|
|
||||||
|
public event Action<string> OnGamepadConnected
|
||||||
|
{
|
||||||
|
add { }
|
||||||
|
remove { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event Action<string> OnGamepadDisconnected
|
||||||
|
{
|
||||||
|
add { }
|
||||||
|
remove { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public IGamepad GetGamepad(string id)
|
||||||
|
{
|
||||||
|
return _virtualTouchScreen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class VirtualGamepadDriver : IGamepadDriver
|
||||||
|
{
|
||||||
|
private readonly int _controllerCount;
|
||||||
|
|
||||||
|
public ReadOnlySpan<string> GamepadsIds => _gamePads.Keys.ToArray();
|
||||||
|
|
||||||
|
public string DriverName => "SDL2";
|
||||||
|
|
||||||
|
public event Action<string> OnGamepadConnected;
|
||||||
|
public event Action<string> OnGamepadDisconnected;
|
||||||
|
|
||||||
|
private Dictionary<string, VirtualGamepad> _gamePads;
|
||||||
|
|
||||||
|
public VirtualGamepadDriver(int controllerCount)
|
||||||
|
{
|
||||||
|
_gamePads = new Dictionary<string, VirtualGamepad>();
|
||||||
|
for (int joystickIndex = 0; joystickIndex < controllerCount; joystickIndex++)
|
||||||
|
{
|
||||||
|
HandleJoyStickConnected(joystickIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
_controllerCount = controllerCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GenerateGamepadId(int joystickIndex)
|
||||||
|
{
|
||||||
|
return "VirtualGamePad-" + joystickIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleJoyStickConnected(int joystickDeviceId)
|
||||||
|
{
|
||||||
|
string id = GenerateGamepadId(joystickDeviceId);
|
||||||
|
_gamePads[id] = new VirtualGamepad(this, id);
|
||||||
|
OnGamepadConnected?.Invoke(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
// Simulate a full disconnect when disposing
|
||||||
|
var ids = GamepadsIds;
|
||||||
|
foreach (string id in ids)
|
||||||
|
{
|
||||||
|
OnGamepadDisconnected?.Invoke(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
_gamePads.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IGamepad GetGamepad(string id)
|
||||||
|
{
|
||||||
|
return _gamePads[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
public IGamepad GetGamepad(int index)
|
||||||
|
{
|
||||||
|
string id = GenerateGamepadId(index);
|
||||||
|
return _gamePads[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetStickAxis(StickInputId stick, Vector2 axes, string deviceId)
|
||||||
|
{
|
||||||
|
if(_gamePads.TryGetValue(deviceId, out var gamePad))
|
||||||
|
{
|
||||||
|
gamePad.StickInputs[(int)stick] = axes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetButtonPressed(GamepadButtonInputId button, string deviceId)
|
||||||
|
{
|
||||||
|
if (_gamePads.TryGetValue(deviceId, out var gamePad))
|
||||||
|
{
|
||||||
|
gamePad.ButtonInputs[(int)button] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetButtonReleased(GamepadButtonInputId button, string deviceId)
|
||||||
|
{
|
||||||
|
if (_gamePads.TryGetValue(deviceId, out var gamePad))
|
||||||
|
{
|
||||||
|
gamePad.ButtonInputs[(int)button] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class VirtualGamepad : IGamepad
|
||||||
|
{
|
||||||
|
private readonly VirtualGamepadDriver _driver;
|
||||||
|
|
||||||
|
private bool[] _buttonInputs;
|
||||||
|
|
||||||
|
private Vector2[] _stickInputs;
|
||||||
|
|
||||||
|
public VirtualGamepad(VirtualGamepadDriver driver, string id)
|
||||||
|
{
|
||||||
|
_buttonInputs = new bool[(int)GamepadButtonInputId.Count];
|
||||||
|
_stickInputs = new Vector2[(int)StickInputId.Count];
|
||||||
|
_driver = driver;
|
||||||
|
Id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() { }
|
||||||
|
|
||||||
|
public GamepadFeaturesFlag Features { get; }
|
||||||
|
public string Id { get; }
|
||||||
|
|
||||||
|
public string Name => Id;
|
||||||
|
public bool IsConnected { get; }
|
||||||
|
public Vector2[] StickInputs { get => _stickInputs; set => _stickInputs = value; }
|
||||||
|
public bool[] ButtonInputs { get => _buttonInputs; set => _buttonInputs = value; }
|
||||||
|
|
||||||
|
public bool IsPressed(GamepadButtonInputId inputId)
|
||||||
|
{
|
||||||
|
return _buttonInputs[(int)inputId];
|
||||||
|
}
|
||||||
|
|
||||||
|
public (float, float) GetStick(StickInputId inputId)
|
||||||
|
{
|
||||||
|
var v = _stickInputs[(int)inputId];
|
||||||
|
|
||||||
|
return (v.X, v.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 GetMotionData(MotionInputId inputId)
|
||||||
|
{
|
||||||
|
return new Vector3();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetTriggerThreshold(float triggerThreshold)
|
||||||
|
{
|
||||||
|
//throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetConfiguration(InputConfig configuration)
|
||||||
|
{
|
||||||
|
//throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
|
||||||
|
{
|
||||||
|
//throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public GamepadStateSnapshot GetMappedStateSnapshot()
|
||||||
|
{
|
||||||
|
GamepadStateSnapshot result = default;
|
||||||
|
|
||||||
|
foreach (var button in Enum.GetValues<GamepadButtonInputId>())
|
||||||
|
{
|
||||||
|
// Do not touch state of button already pressed
|
||||||
|
if (button != GamepadButtonInputId.Count && !result.IsPressed(button))
|
||||||
|
{
|
||||||
|
result.SetPressed(button, IsPressed(button));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(float leftStickX, float leftStickY) = GetStick(StickInputId.Left);
|
||||||
|
(float rightStickX, float rightStickY) = GetStick(StickInputId.Right);
|
||||||
|
|
||||||
|
result.SetStick(StickInputId.Left, leftStickX, leftStickY);
|
||||||
|
result.SetStick(StickInputId.Right, rightStickX, rightStickY);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GamepadStateSnapshot GetStateSnapshot()
|
||||||
|
{
|
||||||
|
return new GamepadStateSnapshot();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,7 @@ namespace LibRyujinx
|
|||||||
"UTC",
|
"UTC",
|
||||||
MemoryManagerMode.HostMappedUnsafe,
|
MemoryManagerMode.HostMappedUnsafe,
|
||||||
false,
|
false,
|
||||||
AspectRatio.Fixed16x9,
|
LibRyujinx.GraphicsConfiguration.AspectRatio,
|
||||||
0,
|
0,
|
||||||
true,
|
true,
|
||||||
"");
|
"");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user