add basic touch and button input interface

This commit is contained in:
Emmanuel Hansen 2023-06-25 17:08:50 +00:00
parent 3f93620d74
commit b9331f30d1
6 changed files with 794 additions and 6 deletions

View file

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
@ -38,6 +39,33 @@ namespace LibRyujinx.Sample
[DllImport(dll, EntryPoint = "graphics_renderer_set_vsync")]
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)]
@ -53,11 +81,13 @@ namespace LibRyujinx.Sample
public bool EnableSpirvCompilationOnVulkan = true;
public bool EnableTextureRecompression = false;
public BackendThreading BackendThreading = BackendThreading.Auto;
public AspectRatio AspectRatio = AspectRatio.Fixed16x9;
public GraphicsConfiguration()
{
}
}
public enum GraphicsBackend
{
Vulkan,
@ -78,4 +108,77 @@ namespace LibRyujinx.Sample
public IntPtr VkRequiredExtensions;
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
}
}

View file

@ -1,5 +1,7 @@
using LibRyujinx.Sample;
using OpenTK.Graphics.OpenGL;
using OpenTK.Mathematics;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.Desktop;
using OpenTK.Windowing.GraphicsLibraryFramework;
using System.Runtime.InteropServices;
@ -13,7 +15,12 @@ namespace LibRyujinx.NativeSample
public delegate IntPtr GetProcAddress(string name);
public delegate IntPtr CreateSurface(IntPtr instance);
private bool _run;
private bool _isVulkan;
private Vector2 _lastPosition;
private bool _mousePressed;
private nint _gamepadIdPtr;
private string? _gamepadId;
public NativeWindow(NativeWindowSettings nativeWindowSettings) : base(nativeWindowSettings)
{
@ -55,6 +62,7 @@ namespace LibRyujinx.NativeSample
};
var success = LibRyujinxInterop.InitializeGraphicsRenderer(_isVulkan ? GraphicsBackend.Vulkan : GraphicsBackend.OpenGl, nativeGraphicsInterop);
success = LibRyujinxInterop.InitializeDevice();
LibRyujinxInterop.InitializeInput(ClientSize.X, ClientSize.Y);
var path = Marshal.StringToHGlobalAnsi(gamePath);
var loaded = LibRyujinxInterop.LoadApplication(path);
@ -62,19 +70,28 @@ namespace LibRyujinx.NativeSample
Marshal.FreeHGlobal(path);
}
_gamepadIdPtr = LibRyujinxInterop.ConnectGamepad(0);
_gamepadId = Marshal.PtrToStringAnsi(_gamepadIdPtr);
if (!_isVulkan)
{
Context.MakeNoneCurrent();
}
_run = true;
var thread = new Thread(new ThreadStart(RunLoop));
thread.Start();
UpdateLoop();
thread.Join();
foreach(var ptr in pointers)
{
Marshal.FreeHGlobal(ptr);
}
Marshal.FreeHGlobal(_gamepadIdPtr);
}
public void RunLoop()
@ -89,15 +106,17 @@ namespace LibRyujinx.NativeSample
Context.SwapInterval = 0;
}
Task.Run(async () =>
/* Task.Run(async () =>
{
await Task.Delay(1000);
LibRyujinxInterop.SetVsyncState(false);
});
LibRyujinxInterop.SetVsyncState(true);
});*/
LibRyujinxInterop.RunLoop();
_run = false;
if (!_isVulkan)
{
Context.MakeNoneCurrent();
@ -111,5 +130,120 @@ namespace LibRyujinx.NativeSample
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 }
};
}
}

View file

@ -18,7 +18,7 @@ namespace LibRyujinx.NativeSample
Size = new Vector2i(800, 600),
Title = "Ryujinx",
API = ContextAPI.NoAPI,
IsEventDriven = true,
IsEventDriven = false,
// This is needed to run on macos
Flags = ContextFlags.ForwardCompatible,
};