mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-07-24 04:17:11 +02:00
infra: Make Avalonia the default UI (#6375)
* misc: Move Ryujinx project to Ryujinx.Gtk3 This breaks release CI for now but that's fine. Signed-off-by: Mary Guillemard <mary@mary.zone> * misc: Move Ryujinx.Ava project to Ryujinx This breaks CI for now, but it's fine. Signed-off-by: Mary Guillemard <mary@mary.zone> * infra: Make Avalonia the default UI Should fix CI after the previous changes. GTK3 isn't build by the release job anymore, only by PR CI. This also ensure that the test-ava update package is still generated to allow update from the old testing channel. Signed-off-by: Mary Guillemard <mary@mary.zone> * Fix missing copy in create_app_bundle.sh Signed-off-by: Mary Guillemard <mary@mary.zone> * Fix syntax error Signed-off-by: Mary Guillemard <mary@mary.zone> --------- Signed-off-by: Mary Guillemard <mary@mary.zone>
This commit is contained in:
parent
53b5985da6
commit
ec6cb0abb4
239 changed files with 1235 additions and 1232 deletions
|
@ -1,18 +1,32 @@
|
|||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Configuration.Hid.Keyboard;
|
||||
using Ryujinx.Input;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using ConfigKey = Ryujinx.Common.Configuration.Hid.Key;
|
||||
using Key = Ryujinx.Input.Key;
|
||||
|
||||
namespace Ryujinx.Input.GTK3
|
||||
namespace Ryujinx.Ava.Input
|
||||
{
|
||||
public class GTK3Keyboard : IKeyboard
|
||||
internal class AvaloniaKeyboard : IKeyboard
|
||||
{
|
||||
private readonly List<ButtonMappingEntry> _buttonsUserMapping;
|
||||
private readonly AvaloniaKeyboardDriver _driver;
|
||||
private StandardKeyboardInputConfig _configuration;
|
||||
|
||||
private readonly object _userMappingLock = new();
|
||||
|
||||
public string Id { get; }
|
||||
public string Name { get; }
|
||||
|
||||
public bool IsConnected => true;
|
||||
public GamepadFeaturesFlag Features => GamepadFeaturesFlag.None;
|
||||
|
||||
private class ButtonMappingEntry
|
||||
{
|
||||
public readonly GamepadButtonInputId To;
|
||||
public readonly Key From;
|
||||
public readonly GamepadButtonInputId To;
|
||||
|
||||
public ButtonMappingEntry(GamepadButtonInputId to, Key from)
|
||||
{
|
||||
|
@ -21,34 +35,13 @@ namespace Ryujinx.Input.GTK3
|
|||
}
|
||||
}
|
||||
|
||||
private readonly object _userMappingLock = new();
|
||||
|
||||
private readonly GTK3KeyboardDriver _driver;
|
||||
private StandardKeyboardInputConfig _configuration;
|
||||
private readonly List<ButtonMappingEntry> _buttonsUserMapping;
|
||||
|
||||
public GTK3Keyboard(GTK3KeyboardDriver driver, string id, string name)
|
||||
public AvaloniaKeyboard(AvaloniaKeyboardDriver driver, string id, string name)
|
||||
{
|
||||
_buttonsUserMapping = new List<ButtonMappingEntry>();
|
||||
|
||||
_driver = driver;
|
||||
Id = id;
|
||||
Name = name;
|
||||
_buttonsUserMapping = new List<ButtonMappingEntry>();
|
||||
}
|
||||
|
||||
private bool HasConfiguration => _configuration != null;
|
||||
|
||||
public string Id { get; }
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
public bool IsConnected => true;
|
||||
|
||||
public GamepadFeaturesFlag Features => GamepadFeaturesFlag.None;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// No operations
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public KeyboardStateSnapshot GetKeyboardStateSnapshot()
|
||||
|
@ -56,45 +49,6 @@ namespace Ryujinx.Input.GTK3
|
|||
return IKeyboard.GetStateSnapshot(this);
|
||||
}
|
||||
|
||||
private static float ConvertRawStickValue(short value)
|
||||
{
|
||||
const float ConvertRate = 1.0f / (short.MaxValue + 0.5f);
|
||||
|
||||
return value * ConvertRate;
|
||||
}
|
||||
|
||||
private static (short, short) GetStickValues(ref KeyboardStateSnapshot snapshot, JoyconConfigKeyboardStick<ConfigKey> stickConfig)
|
||||
{
|
||||
short stickX = 0;
|
||||
short stickY = 0;
|
||||
|
||||
if (snapshot.IsPressed((Key)stickConfig.StickUp))
|
||||
{
|
||||
stickY += 1;
|
||||
}
|
||||
|
||||
if (snapshot.IsPressed((Key)stickConfig.StickDown))
|
||||
{
|
||||
stickY -= 1;
|
||||
}
|
||||
|
||||
if (snapshot.IsPressed((Key)stickConfig.StickRight))
|
||||
{
|
||||
stickX += 1;
|
||||
}
|
||||
|
||||
if (snapshot.IsPressed((Key)stickConfig.StickLeft))
|
||||
{
|
||||
stickX -= 1;
|
||||
}
|
||||
|
||||
OpenTK.Mathematics.Vector2 stick = new(stickX, stickY);
|
||||
|
||||
stick.NormalizeFast();
|
||||
|
||||
return ((short)(stick.X * short.MaxValue), (short)(stick.Y * short.MaxValue));
|
||||
}
|
||||
|
||||
public GamepadStateSnapshot GetMappedStateSnapshot()
|
||||
{
|
||||
KeyboardStateSnapshot rawState = GetKeyboardStateSnapshot();
|
||||
|
@ -102,7 +56,7 @@ namespace Ryujinx.Input.GTK3
|
|||
|
||||
lock (_userMappingLock)
|
||||
{
|
||||
if (!HasConfiguration)
|
||||
if (_configuration == null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
@ -114,7 +68,7 @@ namespace Ryujinx.Input.GTK3
|
|||
continue;
|
||||
}
|
||||
|
||||
// Do not touch state of button already pressed
|
||||
// NOTE: Do not touch state of the button already pressed.
|
||||
if (!result.IsPressed(entry.To))
|
||||
{
|
||||
result.SetPressed(entry.To, rawState.IsPressed(entry.From));
|
||||
|
@ -148,7 +102,14 @@ namespace Ryujinx.Input.GTK3
|
|||
|
||||
public bool IsPressed(Key key)
|
||||
{
|
||||
return _driver.IsPressed(key);
|
||||
try
|
||||
{
|
||||
return _driver.IsPressed(key);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetConfiguration(InputConfig configuration)
|
||||
|
@ -159,47 +120,84 @@ namespace Ryujinx.Input.GTK3
|
|||
|
||||
_buttonsUserMapping.Clear();
|
||||
|
||||
// Then left joycon
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick, (Key)_configuration.LeftJoyconStick.StickButton));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp, (Key)_configuration.LeftJoycon.DpadUp));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadDown, (Key)_configuration.LeftJoycon.DpadDown));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadLeft, (Key)_configuration.LeftJoycon.DpadLeft));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadRight, (Key)_configuration.LeftJoycon.DpadRight));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Minus, (Key)_configuration.LeftJoycon.ButtonMinus));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftShoulder, (Key)_configuration.LeftJoycon.ButtonL));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftTrigger, (Key)_configuration.LeftJoycon.ButtonZl));
|
||||
#pragma warning disable IDE0055 // Disable formatting
|
||||
// Left JoyCon
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick, (Key)_configuration.LeftJoyconStick.StickButton));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp, (Key)_configuration.LeftJoycon.DpadUp));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadDown, (Key)_configuration.LeftJoycon.DpadDown));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadLeft, (Key)_configuration.LeftJoycon.DpadLeft));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadRight, (Key)_configuration.LeftJoycon.DpadRight));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Minus, (Key)_configuration.LeftJoycon.ButtonMinus));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftShoulder, (Key)_configuration.LeftJoycon.ButtonL));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftTrigger, (Key)_configuration.LeftJoycon.ButtonZl));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger0, (Key)_configuration.LeftJoycon.ButtonSr));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger0, (Key)_configuration.LeftJoycon.ButtonSl));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger0, (Key)_configuration.LeftJoycon.ButtonSl));
|
||||
|
||||
// Finally right joycon
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightStick, (Key)_configuration.RightJoyconStick.StickButton));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.A, (Key)_configuration.RightJoycon.ButtonA));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.B, (Key)_configuration.RightJoycon.ButtonB));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.X, (Key)_configuration.RightJoycon.ButtonX));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Y, (Key)_configuration.RightJoycon.ButtonY));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Plus, (Key)_configuration.RightJoycon.ButtonPlus));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightShoulder, (Key)_configuration.RightJoycon.ButtonR));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightTrigger, (Key)_configuration.RightJoycon.ButtonZr));
|
||||
// Right JoyCon
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightStick, (Key)_configuration.RightJoyconStick.StickButton));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.A, (Key)_configuration.RightJoycon.ButtonA));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.B, (Key)_configuration.RightJoycon.ButtonB));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.X, (Key)_configuration.RightJoycon.ButtonX));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Y, (Key)_configuration.RightJoycon.ButtonY));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Plus, (Key)_configuration.RightJoycon.ButtonPlus));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightShoulder, (Key)_configuration.RightJoycon.ButtonR));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightTrigger, (Key)_configuration.RightJoycon.ButtonZr));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger1, (Key)_configuration.RightJoycon.ButtonSr));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger1, (Key)_configuration.RightJoycon.ButtonSl));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger1, (Key)_configuration.RightJoycon.ButtonSl));
|
||||
#pragma warning restore IDE0055
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTriggerThreshold(float triggerThreshold)
|
||||
public void SetTriggerThreshold(float triggerThreshold) { }
|
||||
|
||||
public void Rumble(float lowFrequency, float highFrequency, uint durationMs) { }
|
||||
|
||||
public Vector3 GetMotionData(MotionInputId inputId) => Vector3.Zero;
|
||||
|
||||
private static float ConvertRawStickValue(short value)
|
||||
{
|
||||
// No operations
|
||||
const float ConvertRate = 1.0f / (short.MaxValue + 0.5f);
|
||||
|
||||
return value * ConvertRate;
|
||||
}
|
||||
|
||||
public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
|
||||
private static (short, short) GetStickValues(ref KeyboardStateSnapshot snapshot, JoyconConfigKeyboardStick<ConfigKey> stickConfig)
|
||||
{
|
||||
// No operations
|
||||
short stickX = 0;
|
||||
short stickY = 0;
|
||||
|
||||
if (snapshot.IsPressed((Key)stickConfig.StickUp))
|
||||
{
|
||||
stickY += 1;
|
||||
}
|
||||
|
||||
if (snapshot.IsPressed((Key)stickConfig.StickDown))
|
||||
{
|
||||
stickY -= 1;
|
||||
}
|
||||
|
||||
if (snapshot.IsPressed((Key)stickConfig.StickRight))
|
||||
{
|
||||
stickX += 1;
|
||||
}
|
||||
|
||||
if (snapshot.IsPressed((Key)stickConfig.StickLeft))
|
||||
{
|
||||
stickX -= 1;
|
||||
}
|
||||
|
||||
Vector2 stick = new(stickX, stickY);
|
||||
|
||||
stick = Vector2.Normalize(stick);
|
||||
|
||||
return ((short)(stick.X * short.MaxValue), (short)(stick.Y * short.MaxValue));
|
||||
}
|
||||
|
||||
public Vector3 GetMotionData(MotionInputId inputId)
|
||||
public void Clear()
|
||||
{
|
||||
// No operations
|
||||
|
||||
return Vector3.Zero;
|
||||
_driver?.ResetKeys();
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
}
|
||||
}
|
107
src/Ryujinx/Input/AvaloniaKeyboardDriver.cs
Normal file
107
src/Ryujinx/Input/AvaloniaKeyboardDriver.cs
Normal file
|
@ -0,0 +1,107 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Input;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AvaKey = Avalonia.Input.Key;
|
||||
using Key = Ryujinx.Input.Key;
|
||||
|
||||
namespace Ryujinx.Ava.Input
|
||||
{
|
||||
internal class AvaloniaKeyboardDriver : IGamepadDriver
|
||||
{
|
||||
private static readonly string[] _keyboardIdentifers = new string[1] { "0" };
|
||||
private readonly Control _control;
|
||||
private readonly HashSet<AvaKey> _pressedKeys;
|
||||
|
||||
public event EventHandler<KeyEventArgs> KeyPressed;
|
||||
public event EventHandler<KeyEventArgs> KeyRelease;
|
||||
public event EventHandler<string> TextInput;
|
||||
|
||||
public string DriverName => "AvaloniaKeyboardDriver";
|
||||
public ReadOnlySpan<string> GamepadsIds => _keyboardIdentifers;
|
||||
|
||||
public AvaloniaKeyboardDriver(Control control)
|
||||
{
|
||||
_control = control;
|
||||
_pressedKeys = new HashSet<AvaKey>();
|
||||
|
||||
_control.KeyDown += OnKeyPress;
|
||||
_control.KeyUp += OnKeyRelease;
|
||||
_control.TextInput += Control_TextInput;
|
||||
}
|
||||
|
||||
private void Control_TextInput(object sender, TextInputEventArgs e)
|
||||
{
|
||||
TextInput?.Invoke(this, e.Text);
|
||||
}
|
||||
|
||||
public event Action<string> OnGamepadConnected
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
|
||||
public event Action<string> OnGamepadDisconnected
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
|
||||
public IGamepad GetGamepad(string id)
|
||||
{
|
||||
if (!_keyboardIdentifers[0].Equals(id))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new AvaloniaKeyboard(this, _keyboardIdentifers[0], LocaleManager.Instance[LocaleKeys.AllKeyboards]);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_control.KeyUp -= OnKeyPress;
|
||||
_control.KeyDown -= OnKeyRelease;
|
||||
}
|
||||
}
|
||||
|
||||
protected void OnKeyPress(object sender, KeyEventArgs args)
|
||||
{
|
||||
_pressedKeys.Add(args.Key);
|
||||
|
||||
KeyPressed?.Invoke(this, args);
|
||||
}
|
||||
|
||||
protected void OnKeyRelease(object sender, KeyEventArgs args)
|
||||
{
|
||||
_pressedKeys.Remove(args.Key);
|
||||
|
||||
KeyRelease?.Invoke(this, args);
|
||||
}
|
||||
|
||||
internal bool IsPressed(Key key)
|
||||
{
|
||||
if (key == Key.Unbound || key == Key.Unknown)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AvaloniaKeyboardMappingHelper.TryGetAvaKey(key, out var nativeKey);
|
||||
|
||||
return _pressedKeys.Contains(nativeKey);
|
||||
}
|
||||
|
||||
public void ResetKeys()
|
||||
{
|
||||
_pressedKeys.Clear();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
}
|
||||
}
|
185
src/Ryujinx/Input/AvaloniaKeyboardMappingHelper.cs
Normal file
185
src/Ryujinx/Input/AvaloniaKeyboardMappingHelper.cs
Normal file
|
@ -0,0 +1,185 @@
|
|||
using Ryujinx.Input;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AvaKey = Avalonia.Input.Key;
|
||||
|
||||
namespace Ryujinx.Ava.Input
|
||||
{
|
||||
internal static class AvaloniaKeyboardMappingHelper
|
||||
{
|
||||
private static readonly AvaKey[] _keyMapping = {
|
||||
// NOTE: Invalid
|
||||
AvaKey.None,
|
||||
|
||||
AvaKey.LeftShift,
|
||||
AvaKey.RightShift,
|
||||
AvaKey.LeftCtrl,
|
||||
AvaKey.RightCtrl,
|
||||
AvaKey.LeftAlt,
|
||||
AvaKey.RightAlt,
|
||||
AvaKey.LWin,
|
||||
AvaKey.RWin,
|
||||
AvaKey.Apps,
|
||||
AvaKey.F1,
|
||||
AvaKey.F2,
|
||||
AvaKey.F3,
|
||||
AvaKey.F4,
|
||||
AvaKey.F5,
|
||||
AvaKey.F6,
|
||||
AvaKey.F7,
|
||||
AvaKey.F8,
|
||||
AvaKey.F9,
|
||||
AvaKey.F10,
|
||||
AvaKey.F11,
|
||||
AvaKey.F12,
|
||||
AvaKey.F13,
|
||||
AvaKey.F14,
|
||||
AvaKey.F15,
|
||||
AvaKey.F16,
|
||||
AvaKey.F17,
|
||||
AvaKey.F18,
|
||||
AvaKey.F19,
|
||||
AvaKey.F20,
|
||||
AvaKey.F21,
|
||||
AvaKey.F22,
|
||||
AvaKey.F23,
|
||||
AvaKey.F24,
|
||||
|
||||
AvaKey.None,
|
||||
AvaKey.None,
|
||||
AvaKey.None,
|
||||
AvaKey.None,
|
||||
AvaKey.None,
|
||||
AvaKey.None,
|
||||
AvaKey.None,
|
||||
AvaKey.None,
|
||||
AvaKey.None,
|
||||
AvaKey.None,
|
||||
AvaKey.None,
|
||||
|
||||
AvaKey.Up,
|
||||
AvaKey.Down,
|
||||
AvaKey.Left,
|
||||
AvaKey.Right,
|
||||
AvaKey.Return,
|
||||
AvaKey.Escape,
|
||||
AvaKey.Space,
|
||||
AvaKey.Tab,
|
||||
AvaKey.Back,
|
||||
AvaKey.Insert,
|
||||
AvaKey.Delete,
|
||||
AvaKey.PageUp,
|
||||
AvaKey.PageDown,
|
||||
AvaKey.Home,
|
||||
AvaKey.End,
|
||||
AvaKey.CapsLock,
|
||||
AvaKey.Scroll,
|
||||
AvaKey.Print,
|
||||
AvaKey.Pause,
|
||||
AvaKey.NumLock,
|
||||
AvaKey.Clear,
|
||||
AvaKey.NumPad0,
|
||||
AvaKey.NumPad1,
|
||||
AvaKey.NumPad2,
|
||||
AvaKey.NumPad3,
|
||||
AvaKey.NumPad4,
|
||||
AvaKey.NumPad5,
|
||||
AvaKey.NumPad6,
|
||||
AvaKey.NumPad7,
|
||||
AvaKey.NumPad8,
|
||||
AvaKey.NumPad9,
|
||||
AvaKey.Divide,
|
||||
AvaKey.Multiply,
|
||||
AvaKey.Subtract,
|
||||
AvaKey.Add,
|
||||
AvaKey.Decimal,
|
||||
AvaKey.Enter,
|
||||
AvaKey.A,
|
||||
AvaKey.B,
|
||||
AvaKey.C,
|
||||
AvaKey.D,
|
||||
AvaKey.E,
|
||||
AvaKey.F,
|
||||
AvaKey.G,
|
||||
AvaKey.H,
|
||||
AvaKey.I,
|
||||
AvaKey.J,
|
||||
AvaKey.K,
|
||||
AvaKey.L,
|
||||
AvaKey.M,
|
||||
AvaKey.N,
|
||||
AvaKey.O,
|
||||
AvaKey.P,
|
||||
AvaKey.Q,
|
||||
AvaKey.R,
|
||||
AvaKey.S,
|
||||
AvaKey.T,
|
||||
AvaKey.U,
|
||||
AvaKey.V,
|
||||
AvaKey.W,
|
||||
AvaKey.X,
|
||||
AvaKey.Y,
|
||||
AvaKey.Z,
|
||||
AvaKey.D0,
|
||||
AvaKey.D1,
|
||||
AvaKey.D2,
|
||||
AvaKey.D3,
|
||||
AvaKey.D4,
|
||||
AvaKey.D5,
|
||||
AvaKey.D6,
|
||||
AvaKey.D7,
|
||||
AvaKey.D8,
|
||||
AvaKey.D9,
|
||||
AvaKey.OemTilde,
|
||||
AvaKey.OemTilde,AvaKey.OemMinus,
|
||||
AvaKey.OemPlus,
|
||||
AvaKey.OemOpenBrackets,
|
||||
AvaKey.OemCloseBrackets,
|
||||
AvaKey.OemSemicolon,
|
||||
AvaKey.OemQuotes,
|
||||
AvaKey.OemComma,
|
||||
AvaKey.OemPeriod,
|
||||
AvaKey.OemQuestion,
|
||||
AvaKey.OemBackslash,
|
||||
|
||||
// NOTE: invalid
|
||||
AvaKey.None,
|
||||
};
|
||||
|
||||
private static readonly Dictionary<AvaKey, Key> _avaKeyMapping;
|
||||
|
||||
static AvaloniaKeyboardMappingHelper()
|
||||
{
|
||||
var inputKeys = Enum.GetValues<Key>();
|
||||
|
||||
// NOTE: Avalonia.Input.Key is not contiguous and quite large, so use a dictionary instead of an array.
|
||||
_avaKeyMapping = new Dictionary<AvaKey, Key>();
|
||||
|
||||
foreach (var key in inputKeys)
|
||||
{
|
||||
if (TryGetAvaKey(key, out var index))
|
||||
{
|
||||
_avaKeyMapping[index] = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryGetAvaKey(Key key, out AvaKey avaKey)
|
||||
{
|
||||
avaKey = AvaKey.None;
|
||||
|
||||
bool keyExist = (int)key < _keyMapping.Length;
|
||||
if (keyExist)
|
||||
{
|
||||
avaKey = _keyMapping[(int)key];
|
||||
}
|
||||
|
||||
return keyExist;
|
||||
}
|
||||
|
||||
public static Key ToInputKey(AvaKey key)
|
||||
{
|
||||
return _avaKeyMapping.GetValueOrDefault(key, Key.Unknown);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,25 +1,23 @@
|
|||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Input;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Ryujinx.Input.GTK3
|
||||
namespace Ryujinx.Ava.Input
|
||||
{
|
||||
public class GTK3Mouse : IMouse
|
||||
internal class AvaloniaMouse : IMouse
|
||||
{
|
||||
private GTK3MouseDriver _driver;
|
||||
|
||||
public GamepadFeaturesFlag Features => throw new NotImplementedException();
|
||||
private AvaloniaMouseDriver _driver;
|
||||
|
||||
public string Id => "0";
|
||||
|
||||
public string Name => "GTKMouse";
|
||||
public string Name => "AvaloniaMouse";
|
||||
|
||||
public bool IsConnected => true;
|
||||
|
||||
public GamepadFeaturesFlag Features => throw new NotImplementedException();
|
||||
public bool[] Buttons => _driver.PressedButtons;
|
||||
|
||||
public GTK3Mouse(GTK3MouseDriver driver)
|
||||
public AvaloniaMouse(AvaloniaMouseDriver driver)
|
||||
{
|
||||
_driver = driver;
|
||||
}
|
||||
|
@ -83,7 +81,6 @@ namespace Ryujinx.Input.GTK3
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
_driver = null;
|
||||
}
|
||||
}
|
159
src/Ryujinx/Input/AvaloniaMouseDriver.cs
Normal file
159
src/Ryujinx/Input/AvaloniaMouseDriver.cs
Normal file
|
@ -0,0 +1,159 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Ryujinx.Input;
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using MouseButton = Ryujinx.Input.MouseButton;
|
||||
using Size = System.Drawing.Size;
|
||||
|
||||
namespace Ryujinx.Ava.Input
|
||||
{
|
||||
internal class AvaloniaMouseDriver : IGamepadDriver
|
||||
{
|
||||
private Control _widget;
|
||||
private bool _isDisposed;
|
||||
private Size _size;
|
||||
private readonly TopLevel _window;
|
||||
|
||||
public bool[] PressedButtons { get; }
|
||||
public Vector2 CurrentPosition { get; private set; }
|
||||
public Vector2 Scroll { get; private set; }
|
||||
|
||||
public string DriverName => "AvaloniaMouseDriver";
|
||||
public ReadOnlySpan<string> GamepadsIds => new[] { "0" };
|
||||
|
||||
public AvaloniaMouseDriver(TopLevel window, Control parent)
|
||||
{
|
||||
_widget = parent;
|
||||
_window = window;
|
||||
|
||||
_widget.PointerMoved += Parent_PointerMovedEvent;
|
||||
_widget.PointerPressed += Parent_PointerPressedEvent;
|
||||
_widget.PointerReleased += Parent_PointerReleasedEvent;
|
||||
_widget.PointerWheelChanged += Parent_PointerWheelChanged;
|
||||
|
||||
_window.PointerMoved += Parent_PointerMovedEvent;
|
||||
_window.PointerPressed += Parent_PointerPressedEvent;
|
||||
_window.PointerReleased += Parent_PointerReleasedEvent;
|
||||
_window.PointerWheelChanged += Parent_PointerWheelChanged;
|
||||
|
||||
PressedButtons = new bool[(int)MouseButton.Count];
|
||||
|
||||
_size = new Size((int)parent.Bounds.Width, (int)parent.Bounds.Height);
|
||||
|
||||
parent.GetObservable(Visual.BoundsProperty).Subscribe(Resized);
|
||||
}
|
||||
|
||||
public event Action<string> OnGamepadConnected
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
|
||||
public event Action<string> OnGamepadDisconnected
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
|
||||
private void Resized(Rect rect)
|
||||
{
|
||||
_size = new Size((int)rect.Width, (int)rect.Height);
|
||||
}
|
||||
|
||||
private void Parent_PointerWheelChanged(object o, PointerWheelEventArgs args)
|
||||
{
|
||||
Scroll = new Vector2((float)args.Delta.X, (float)args.Delta.Y);
|
||||
}
|
||||
|
||||
private void Parent_PointerReleasedEvent(object o, PointerReleasedEventArgs args)
|
||||
{
|
||||
uint button = (uint)args.InitialPressMouseButton - 1;
|
||||
|
||||
if ((uint)PressedButtons.Length > button)
|
||||
{
|
||||
PressedButtons[button] = false;
|
||||
}
|
||||
}
|
||||
private void Parent_PointerPressedEvent(object o, PointerPressedEventArgs args)
|
||||
{
|
||||
uint button = (uint)args.GetCurrentPoint(_widget).Properties.PointerUpdateKind;
|
||||
|
||||
if ((uint)PressedButtons.Length > button)
|
||||
{
|
||||
PressedButtons[button] = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void Parent_PointerMovedEvent(object o, PointerEventArgs args)
|
||||
{
|
||||
Point position = args.GetPosition(_widget);
|
||||
|
||||
CurrentPosition = new Vector2((float)position.X, (float)position.Y);
|
||||
}
|
||||
|
||||
public void SetMousePressed(MouseButton button)
|
||||
{
|
||||
if ((uint)PressedButtons.Length > (uint)button)
|
||||
{
|
||||
PressedButtons[(uint)button] = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetMouseReleased(MouseButton button)
|
||||
{
|
||||
if ((uint)PressedButtons.Length > (uint)button)
|
||||
{
|
||||
PressedButtons[(uint)button] = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPosition(double x, double y)
|
||||
{
|
||||
CurrentPosition = new Vector2((float)x, (float)y);
|
||||
}
|
||||
|
||||
public bool IsButtonPressed(MouseButton button)
|
||||
{
|
||||
if ((uint)PressedButtons.Length > (uint)button)
|
||||
{
|
||||
return PressedButtons[(uint)button];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public Size GetClientSize()
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
|
||||
public IGamepad GetGamepad(string id)
|
||||
{
|
||||
return new AvaloniaMouse(this);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isDisposed = true;
|
||||
|
||||
_widget.PointerMoved -= Parent_PointerMovedEvent;
|
||||
_widget.PointerPressed -= Parent_PointerPressedEvent;
|
||||
_widget.PointerReleased -= Parent_PointerReleasedEvent;
|
||||
_widget.PointerWheelChanged -= Parent_PointerWheelChanged;
|
||||
|
||||
_window.PointerMoved -= Parent_PointerMovedEvent;
|
||||
_window.PointerPressed -= Parent_PointerPressedEvent;
|
||||
_window.PointerReleased -= Parent_PointerReleasedEvent;
|
||||
_window.PointerWheelChanged -= Parent_PointerWheelChanged;
|
||||
|
||||
_widget = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
using Gdk;
|
||||
using Gtk;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GtkKey = Gdk.Key;
|
||||
|
||||
namespace Ryujinx.Input.GTK3
|
||||
{
|
||||
public class GTK3KeyboardDriver : IGamepadDriver
|
||||
{
|
||||
private readonly Widget _widget;
|
||||
private readonly HashSet<GtkKey> _pressedKeys;
|
||||
|
||||
public GTK3KeyboardDriver(Widget widget)
|
||||
{
|
||||
_widget = widget;
|
||||
_pressedKeys = new HashSet<GtkKey>();
|
||||
|
||||
_widget.KeyPressEvent += OnKeyPress;
|
||||
_widget.KeyReleaseEvent += OnKeyRelease;
|
||||
}
|
||||
|
||||
public string DriverName => "GTK3";
|
||||
|
||||
private static readonly string[] _keyboardIdentifers = new string[1] { "0" };
|
||||
|
||||
public ReadOnlySpan<string> GamepadsIds => _keyboardIdentifers;
|
||||
|
||||
public event Action<string> OnGamepadConnected
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
|
||||
public event Action<string> OnGamepadDisconnected
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_widget.KeyPressEvent -= OnKeyPress;
|
||||
_widget.KeyReleaseEvent -= OnKeyRelease;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
[GLib.ConnectBefore]
|
||||
protected void OnKeyPress(object sender, KeyPressEventArgs args)
|
||||
{
|
||||
GtkKey key = (GtkKey)Keyval.ToLower((uint)args.Event.Key);
|
||||
|
||||
_pressedKeys.Add(key);
|
||||
}
|
||||
|
||||
[GLib.ConnectBefore]
|
||||
protected void OnKeyRelease(object sender, KeyReleaseEventArgs args)
|
||||
{
|
||||
GtkKey key = (GtkKey)Keyval.ToLower((uint)args.Event.Key);
|
||||
|
||||
_pressedKeys.Remove(key);
|
||||
}
|
||||
|
||||
internal bool IsPressed(Key key)
|
||||
{
|
||||
if (key == Key.Unbound || key == Key.Unknown)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
GtkKey nativeKey = GTK3MappingHelper.ToGtkKey(key);
|
||||
|
||||
return _pressedKeys.Contains(nativeKey);
|
||||
}
|
||||
|
||||
public IGamepad GetGamepad(string id)
|
||||
{
|
||||
if (!_keyboardIdentifers[0].Equals(id))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new GTK3Keyboard(this, _keyboardIdentifers[0], "All keyboards");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,178 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using GtkKey = Gdk.Key;
|
||||
|
||||
namespace Ryujinx.Input.GTK3
|
||||
{
|
||||
public static class GTK3MappingHelper
|
||||
{
|
||||
private static readonly GtkKey[] _keyMapping = new GtkKey[(int)Key.Count]
|
||||
{
|
||||
// NOTE: invalid
|
||||
GtkKey.blank,
|
||||
|
||||
GtkKey.Shift_L,
|
||||
GtkKey.Shift_R,
|
||||
GtkKey.Control_L,
|
||||
GtkKey.Control_R,
|
||||
GtkKey.Alt_L,
|
||||
GtkKey.Alt_R,
|
||||
GtkKey.Super_L,
|
||||
GtkKey.Super_R,
|
||||
GtkKey.Menu,
|
||||
GtkKey.F1,
|
||||
GtkKey.F2,
|
||||
GtkKey.F3,
|
||||
GtkKey.F4,
|
||||
GtkKey.F5,
|
||||
GtkKey.F6,
|
||||
GtkKey.F7,
|
||||
GtkKey.F8,
|
||||
GtkKey.F9,
|
||||
GtkKey.F10,
|
||||
GtkKey.F11,
|
||||
GtkKey.F12,
|
||||
GtkKey.F13,
|
||||
GtkKey.F14,
|
||||
GtkKey.F15,
|
||||
GtkKey.F16,
|
||||
GtkKey.F17,
|
||||
GtkKey.F18,
|
||||
GtkKey.F19,
|
||||
GtkKey.F20,
|
||||
GtkKey.F21,
|
||||
GtkKey.F22,
|
||||
GtkKey.F23,
|
||||
GtkKey.F24,
|
||||
GtkKey.F25,
|
||||
GtkKey.F26,
|
||||
GtkKey.F27,
|
||||
GtkKey.F28,
|
||||
GtkKey.F29,
|
||||
GtkKey.F30,
|
||||
GtkKey.F31,
|
||||
GtkKey.F32,
|
||||
GtkKey.F33,
|
||||
GtkKey.F34,
|
||||
GtkKey.F35,
|
||||
GtkKey.Up,
|
||||
GtkKey.Down,
|
||||
GtkKey.Left,
|
||||
GtkKey.Right,
|
||||
GtkKey.Return,
|
||||
GtkKey.Escape,
|
||||
GtkKey.space,
|
||||
GtkKey.Tab,
|
||||
GtkKey.BackSpace,
|
||||
GtkKey.Insert,
|
||||
GtkKey.Delete,
|
||||
GtkKey.Page_Up,
|
||||
GtkKey.Page_Down,
|
||||
GtkKey.Home,
|
||||
GtkKey.End,
|
||||
GtkKey.Caps_Lock,
|
||||
GtkKey.Scroll_Lock,
|
||||
GtkKey.Print,
|
||||
GtkKey.Pause,
|
||||
GtkKey.Num_Lock,
|
||||
GtkKey.Clear,
|
||||
GtkKey.KP_0,
|
||||
GtkKey.KP_1,
|
||||
GtkKey.KP_2,
|
||||
GtkKey.KP_3,
|
||||
GtkKey.KP_4,
|
||||
GtkKey.KP_5,
|
||||
GtkKey.KP_6,
|
||||
GtkKey.KP_7,
|
||||
GtkKey.KP_8,
|
||||
GtkKey.KP_9,
|
||||
GtkKey.KP_Divide,
|
||||
GtkKey.KP_Multiply,
|
||||
GtkKey.KP_Subtract,
|
||||
GtkKey.KP_Add,
|
||||
GtkKey.KP_Decimal,
|
||||
GtkKey.KP_Enter,
|
||||
GtkKey.a,
|
||||
GtkKey.b,
|
||||
GtkKey.c,
|
||||
GtkKey.d,
|
||||
GtkKey.e,
|
||||
GtkKey.f,
|
||||
GtkKey.g,
|
||||
GtkKey.h,
|
||||
GtkKey.i,
|
||||
GtkKey.j,
|
||||
GtkKey.k,
|
||||
GtkKey.l,
|
||||
GtkKey.m,
|
||||
GtkKey.n,
|
||||
GtkKey.o,
|
||||
GtkKey.p,
|
||||
GtkKey.q,
|
||||
GtkKey.r,
|
||||
GtkKey.s,
|
||||
GtkKey.t,
|
||||
GtkKey.u,
|
||||
GtkKey.v,
|
||||
GtkKey.w,
|
||||
GtkKey.x,
|
||||
GtkKey.y,
|
||||
GtkKey.z,
|
||||
GtkKey.Key_0,
|
||||
GtkKey.Key_1,
|
||||
GtkKey.Key_2,
|
||||
GtkKey.Key_3,
|
||||
GtkKey.Key_4,
|
||||
GtkKey.Key_5,
|
||||
GtkKey.Key_6,
|
||||
GtkKey.Key_7,
|
||||
GtkKey.Key_8,
|
||||
GtkKey.Key_9,
|
||||
GtkKey.grave,
|
||||
GtkKey.grave,
|
||||
GtkKey.minus,
|
||||
GtkKey.plus,
|
||||
GtkKey.bracketleft,
|
||||
GtkKey.bracketright,
|
||||
GtkKey.semicolon,
|
||||
GtkKey.quoteright,
|
||||
GtkKey.comma,
|
||||
GtkKey.period,
|
||||
GtkKey.slash,
|
||||
GtkKey.backslash,
|
||||
|
||||
// NOTE: invalid
|
||||
GtkKey.blank,
|
||||
};
|
||||
|
||||
private static readonly Dictionary<GtkKey, Key> _gtkKeyMapping;
|
||||
|
||||
static GTK3MappingHelper()
|
||||
{
|
||||
var inputKeys = Enum.GetValues<Key>().SkipLast(1);
|
||||
|
||||
// GtkKey is not contiguous and quite large, so use a dictionary instead of an array.
|
||||
_gtkKeyMapping = new Dictionary<GtkKey, Key>();
|
||||
|
||||
foreach (var key in inputKeys)
|
||||
{
|
||||
var index = ToGtkKey(key);
|
||||
_gtkKeyMapping[index] = key;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static GtkKey ToGtkKey(Key key)
|
||||
{
|
||||
return _keyMapping[(int)key];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Key ToInputKey(GtkKey key)
|
||||
{
|
||||
return _gtkKeyMapping.GetValueOrDefault(key, Key.Unknown);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
using Gdk;
|
||||
using Gtk;
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using Size = System.Drawing.Size;
|
||||
|
||||
namespace Ryujinx.Input.GTK3
|
||||
{
|
||||
public class GTK3MouseDriver : IGamepadDriver
|
||||
{
|
||||
private Widget _widget;
|
||||
private bool _isDisposed;
|
||||
|
||||
public bool[] PressedButtons { get; }
|
||||
|
||||
public Vector2 CurrentPosition { get; private set; }
|
||||
public Vector2 Scroll { get; private set; }
|
||||
|
||||
public GTK3MouseDriver(Widget parent)
|
||||
{
|
||||
_widget = parent;
|
||||
|
||||
_widget.MotionNotifyEvent += Parent_MotionNotifyEvent;
|
||||
_widget.ButtonPressEvent += Parent_ButtonPressEvent;
|
||||
_widget.ButtonReleaseEvent += Parent_ButtonReleaseEvent;
|
||||
_widget.ScrollEvent += Parent_ScrollEvent;
|
||||
|
||||
PressedButtons = new bool[(int)MouseButton.Count];
|
||||
}
|
||||
|
||||
|
||||
[GLib.ConnectBefore]
|
||||
private void Parent_ScrollEvent(object o, ScrollEventArgs args)
|
||||
{
|
||||
Scroll = new Vector2((float)args.Event.X, (float)args.Event.Y);
|
||||
}
|
||||
|
||||
[GLib.ConnectBefore]
|
||||
private void Parent_ButtonReleaseEvent(object o, ButtonReleaseEventArgs args)
|
||||
{
|
||||
PressedButtons[args.Event.Button - 1] = false;
|
||||
}
|
||||
|
||||
[GLib.ConnectBefore]
|
||||
private void Parent_ButtonPressEvent(object o, ButtonPressEventArgs args)
|
||||
{
|
||||
PressedButtons[args.Event.Button - 1] = true;
|
||||
}
|
||||
|
||||
[GLib.ConnectBefore]
|
||||
private void Parent_MotionNotifyEvent(object o, MotionNotifyEventArgs args)
|
||||
{
|
||||
if (args.Event.Device.InputSource == InputSource.Mouse)
|
||||
{
|
||||
CurrentPosition = new Vector2((float)args.Event.X, (float)args.Event.Y);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsButtonPressed(MouseButton button)
|
||||
{
|
||||
return PressedButtons[(int)button];
|
||||
}
|
||||
|
||||
public Size GetClientSize()
|
||||
{
|
||||
return new Size(_widget.AllocatedWidth, _widget.AllocatedHeight);
|
||||
}
|
||||
|
||||
public string DriverName => "GTK3";
|
||||
|
||||
public event Action<string> OnGamepadConnected
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
|
||||
public event Action<string> OnGamepadDisconnected
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
|
||||
public ReadOnlySpan<string> GamepadsIds => new[] { "0" };
|
||||
|
||||
public IGamepad GetGamepad(string id)
|
||||
{
|
||||
return new GTK3Mouse(this);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
_isDisposed = true;
|
||||
|
||||
_widget.MotionNotifyEvent -= Parent_MotionNotifyEvent;
|
||||
_widget.ButtonPressEvent -= Parent_ButtonPressEvent;
|
||||
_widget.ButtonReleaseEvent -= Parent_ButtonReleaseEvent;
|
||||
|
||||
_widget = null;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue