AvaloniaKeyboard.cs
1 using Ryujinx.Common.Configuration.Hid; 2 using Ryujinx.Common.Configuration.Hid.Keyboard; 3 using Ryujinx.Input; 4 using System; 5 using System.Collections.Generic; 6 using System.Numerics; 7 using ConfigKey = Ryujinx.Common.Configuration.Hid.Key; 8 using Key = Ryujinx.Input.Key; 9 10 namespace Ryujinx.Ava.Input 11 { 12 internal class AvaloniaKeyboard : IKeyboard 13 { 14 private readonly List<ButtonMappingEntry> _buttonsUserMapping; 15 private readonly AvaloniaKeyboardDriver _driver; 16 private StandardKeyboardInputConfig _configuration; 17 18 private readonly object _userMappingLock = new(); 19 20 public string Id { get; } 21 public string Name { get; } 22 23 public bool IsConnected => true; 24 public GamepadFeaturesFlag Features => GamepadFeaturesFlag.None; 25 26 private class ButtonMappingEntry 27 { 28 public readonly Key From; 29 public readonly GamepadButtonInputId To; 30 31 public ButtonMappingEntry(GamepadButtonInputId to, Key from) 32 { 33 To = to; 34 From = from; 35 } 36 } 37 38 public AvaloniaKeyboard(AvaloniaKeyboardDriver driver, string id, string name) 39 { 40 _buttonsUserMapping = new List<ButtonMappingEntry>(); 41 42 _driver = driver; 43 Id = id; 44 Name = name; 45 } 46 47 public KeyboardStateSnapshot GetKeyboardStateSnapshot() 48 { 49 return IKeyboard.GetStateSnapshot(this); 50 } 51 52 public GamepadStateSnapshot GetMappedStateSnapshot() 53 { 54 KeyboardStateSnapshot rawState = GetKeyboardStateSnapshot(); 55 GamepadStateSnapshot result = default; 56 57 lock (_userMappingLock) 58 { 59 if (_configuration == null) 60 { 61 return result; 62 } 63 64 foreach (ButtonMappingEntry entry in _buttonsUserMapping) 65 { 66 if (entry.From == Key.Unknown || entry.From == Key.Unbound || entry.To == GamepadButtonInputId.Unbound) 67 { 68 continue; 69 } 70 71 // NOTE: Do not touch state of the button already pressed. 72 if (!result.IsPressed(entry.To)) 73 { 74 result.SetPressed(entry.To, rawState.IsPressed(entry.From)); 75 } 76 } 77 78 (short leftStickX, short leftStickY) = GetStickValues(ref rawState, _configuration.LeftJoyconStick); 79 (short rightStickX, short rightStickY) = GetStickValues(ref rawState, _configuration.RightJoyconStick); 80 81 result.SetStick(StickInputId.Left, ConvertRawStickValue(leftStickX), ConvertRawStickValue(leftStickY)); 82 result.SetStick(StickInputId.Right, ConvertRawStickValue(rightStickX), ConvertRawStickValue(rightStickY)); 83 } 84 85 return result; 86 } 87 88 public GamepadStateSnapshot GetStateSnapshot() 89 { 90 throw new NotSupportedException(); 91 } 92 93 public (float, float) GetStick(StickInputId inputId) 94 { 95 throw new NotSupportedException(); 96 } 97 98 public bool IsPressed(GamepadButtonInputId inputId) 99 { 100 throw new NotSupportedException(); 101 } 102 103 public bool IsPressed(Key key) 104 { 105 try 106 { 107 return _driver.IsPressed(key); 108 } 109 catch 110 { 111 return false; 112 } 113 } 114 115 public void SetConfiguration(InputConfig configuration) 116 { 117 lock (_userMappingLock) 118 { 119 _configuration = (StandardKeyboardInputConfig)configuration; 120 121 _buttonsUserMapping.Clear(); 122 123 #pragma warning disable IDE0055 // Disable formatting 124 // Left JoyCon 125 _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick, (Key)_configuration.LeftJoyconStick.StickButton)); 126 _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp, (Key)_configuration.LeftJoycon.DpadUp)); 127 _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadDown, (Key)_configuration.LeftJoycon.DpadDown)); 128 _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadLeft, (Key)_configuration.LeftJoycon.DpadLeft)); 129 _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadRight, (Key)_configuration.LeftJoycon.DpadRight)); 130 _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Minus, (Key)_configuration.LeftJoycon.ButtonMinus)); 131 _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftShoulder, (Key)_configuration.LeftJoycon.ButtonL)); 132 _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftTrigger, (Key)_configuration.LeftJoycon.ButtonZl)); 133 _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger0, (Key)_configuration.LeftJoycon.ButtonSr)); 134 _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger0, (Key)_configuration.LeftJoycon.ButtonSl)); 135 136 // Right JoyCon 137 _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightStick, (Key)_configuration.RightJoyconStick.StickButton)); 138 _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.A, (Key)_configuration.RightJoycon.ButtonA)); 139 _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.B, (Key)_configuration.RightJoycon.ButtonB)); 140 _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.X, (Key)_configuration.RightJoycon.ButtonX)); 141 _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Y, (Key)_configuration.RightJoycon.ButtonY)); 142 _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Plus, (Key)_configuration.RightJoycon.ButtonPlus)); 143 _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightShoulder, (Key)_configuration.RightJoycon.ButtonR)); 144 _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightTrigger, (Key)_configuration.RightJoycon.ButtonZr)); 145 _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger1, (Key)_configuration.RightJoycon.ButtonSr)); 146 _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger1, (Key)_configuration.RightJoycon.ButtonSl)); 147 #pragma warning restore IDE0055 148 } 149 } 150 151 public void SetTriggerThreshold(float triggerThreshold) { } 152 153 public void Rumble(float lowFrequency, float highFrequency, uint durationMs) { } 154 155 public Vector3 GetMotionData(MotionInputId inputId) => Vector3.Zero; 156 157 private static float ConvertRawStickValue(short value) 158 { 159 const float ConvertRate = 1.0f / (short.MaxValue + 0.5f); 160 161 return value * ConvertRate; 162 } 163 164 private static (short, short) GetStickValues(ref KeyboardStateSnapshot snapshot, JoyconConfigKeyboardStick<ConfigKey> stickConfig) 165 { 166 short stickX = 0; 167 short stickY = 0; 168 169 if (snapshot.IsPressed((Key)stickConfig.StickUp)) 170 { 171 stickY += 1; 172 } 173 174 if (snapshot.IsPressed((Key)stickConfig.StickDown)) 175 { 176 stickY -= 1; 177 } 178 179 if (snapshot.IsPressed((Key)stickConfig.StickRight)) 180 { 181 stickX += 1; 182 } 183 184 if (snapshot.IsPressed((Key)stickConfig.StickLeft)) 185 { 186 stickX -= 1; 187 } 188 189 Vector2 stick = new(stickX, stickY); 190 191 stick = Vector2.Normalize(stick); 192 193 return ((short)(stick.X * short.MaxValue), (short)(stick.Y * short.MaxValue)); 194 } 195 196 public void Clear() 197 { 198 _driver?.Clear(); 199 } 200 201 public void Dispose() { } 202 } 203 }