SDL2Keyboard.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. using Ryujinx.Common.Configuration.Hid;
  2. using Ryujinx.Common.Configuration.Hid.Keyboard;
  3. using Ryujinx.Common.Logging;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Numerics;
  7. using System.Runtime.CompilerServices;
  8. using System.Threading;
  9. using static SDL2.SDL;
  10. using ConfigKey = Ryujinx.Common.Configuration.Hid.Key;
  11. namespace Ryujinx.Input.SDL2
  12. {
  13. class SDL2Keyboard : IKeyboard
  14. {
  15. private readonly record struct ButtonMappingEntry(GamepadButtonInputId To, Key From)
  16. {
  17. public bool IsValid => To is not GamepadButtonInputId.Unbound && From is not Key.Unbound;
  18. }
  19. private readonly Lock _userMappingLock = new();
  20. #pragma warning disable IDE0052 // Remove unread private member
  21. private readonly SDL2KeyboardDriver _driver;
  22. #pragma warning restore IDE0052
  23. private StandardKeyboardInputConfig _configuration;
  24. private readonly List<ButtonMappingEntry> _buttonsUserMapping;
  25. private static readonly SDL_Keycode[] _keysDriverMapping = new SDL_Keycode[(int)Key.Count]
  26. {
  27. // INVALID
  28. SDL_Keycode.SDLK_0,
  29. // Presented as modifiers, so invalid here.
  30. SDL_Keycode.SDLK_0,
  31. SDL_Keycode.SDLK_0,
  32. SDL_Keycode.SDLK_0,
  33. SDL_Keycode.SDLK_0,
  34. SDL_Keycode.SDLK_0,
  35. SDL_Keycode.SDLK_0,
  36. SDL_Keycode.SDLK_0,
  37. SDL_Keycode.SDLK_0,
  38. SDL_Keycode.SDLK_0,
  39. SDL_Keycode.SDLK_F1,
  40. SDL_Keycode.SDLK_F2,
  41. SDL_Keycode.SDLK_F3,
  42. SDL_Keycode.SDLK_F4,
  43. SDL_Keycode.SDLK_F5,
  44. SDL_Keycode.SDLK_F6,
  45. SDL_Keycode.SDLK_F7,
  46. SDL_Keycode.SDLK_F8,
  47. SDL_Keycode.SDLK_F9,
  48. SDL_Keycode.SDLK_F10,
  49. SDL_Keycode.SDLK_F11,
  50. SDL_Keycode.SDLK_F12,
  51. SDL_Keycode.SDLK_F13,
  52. SDL_Keycode.SDLK_F14,
  53. SDL_Keycode.SDLK_F15,
  54. SDL_Keycode.SDLK_F16,
  55. SDL_Keycode.SDLK_F17,
  56. SDL_Keycode.SDLK_F18,
  57. SDL_Keycode.SDLK_F19,
  58. SDL_Keycode.SDLK_F20,
  59. SDL_Keycode.SDLK_F21,
  60. SDL_Keycode.SDLK_F22,
  61. SDL_Keycode.SDLK_F23,
  62. SDL_Keycode.SDLK_F24,
  63. SDL_Keycode.SDLK_0,
  64. SDL_Keycode.SDLK_0,
  65. SDL_Keycode.SDLK_0,
  66. SDL_Keycode.SDLK_0,
  67. SDL_Keycode.SDLK_0,
  68. SDL_Keycode.SDLK_0,
  69. SDL_Keycode.SDLK_0,
  70. SDL_Keycode.SDLK_0,
  71. SDL_Keycode.SDLK_0,
  72. SDL_Keycode.SDLK_0,
  73. SDL_Keycode.SDLK_0,
  74. SDL_Keycode.SDLK_UP,
  75. SDL_Keycode.SDLK_DOWN,
  76. SDL_Keycode.SDLK_LEFT,
  77. SDL_Keycode.SDLK_RIGHT,
  78. SDL_Keycode.SDLK_RETURN,
  79. SDL_Keycode.SDLK_ESCAPE,
  80. SDL_Keycode.SDLK_SPACE,
  81. SDL_Keycode.SDLK_TAB,
  82. SDL_Keycode.SDLK_BACKSPACE,
  83. SDL_Keycode.SDLK_INSERT,
  84. SDL_Keycode.SDLK_DELETE,
  85. SDL_Keycode.SDLK_PAGEUP,
  86. SDL_Keycode.SDLK_PAGEDOWN,
  87. SDL_Keycode.SDLK_HOME,
  88. SDL_Keycode.SDLK_END,
  89. SDL_Keycode.SDLK_CAPSLOCK,
  90. SDL_Keycode.SDLK_SCROLLLOCK,
  91. SDL_Keycode.SDLK_PRINTSCREEN,
  92. SDL_Keycode.SDLK_PAUSE,
  93. SDL_Keycode.SDLK_NUMLOCKCLEAR,
  94. SDL_Keycode.SDLK_CLEAR,
  95. SDL_Keycode.SDLK_KP_0,
  96. SDL_Keycode.SDLK_KP_1,
  97. SDL_Keycode.SDLK_KP_2,
  98. SDL_Keycode.SDLK_KP_3,
  99. SDL_Keycode.SDLK_KP_4,
  100. SDL_Keycode.SDLK_KP_5,
  101. SDL_Keycode.SDLK_KP_6,
  102. SDL_Keycode.SDLK_KP_7,
  103. SDL_Keycode.SDLK_KP_8,
  104. SDL_Keycode.SDLK_KP_9,
  105. SDL_Keycode.SDLK_KP_DIVIDE,
  106. SDL_Keycode.SDLK_KP_MULTIPLY,
  107. SDL_Keycode.SDLK_KP_MINUS,
  108. SDL_Keycode.SDLK_KP_PLUS,
  109. SDL_Keycode.SDLK_KP_DECIMAL,
  110. SDL_Keycode.SDLK_KP_ENTER,
  111. SDL_Keycode.SDLK_a,
  112. SDL_Keycode.SDLK_b,
  113. SDL_Keycode.SDLK_c,
  114. SDL_Keycode.SDLK_d,
  115. SDL_Keycode.SDLK_e,
  116. SDL_Keycode.SDLK_f,
  117. SDL_Keycode.SDLK_g,
  118. SDL_Keycode.SDLK_h,
  119. SDL_Keycode.SDLK_i,
  120. SDL_Keycode.SDLK_j,
  121. SDL_Keycode.SDLK_k,
  122. SDL_Keycode.SDLK_l,
  123. SDL_Keycode.SDLK_m,
  124. SDL_Keycode.SDLK_n,
  125. SDL_Keycode.SDLK_o,
  126. SDL_Keycode.SDLK_p,
  127. SDL_Keycode.SDLK_q,
  128. SDL_Keycode.SDLK_r,
  129. SDL_Keycode.SDLK_s,
  130. SDL_Keycode.SDLK_t,
  131. SDL_Keycode.SDLK_u,
  132. SDL_Keycode.SDLK_v,
  133. SDL_Keycode.SDLK_w,
  134. SDL_Keycode.SDLK_x,
  135. SDL_Keycode.SDLK_y,
  136. SDL_Keycode.SDLK_z,
  137. SDL_Keycode.SDLK_0,
  138. SDL_Keycode.SDLK_1,
  139. SDL_Keycode.SDLK_2,
  140. SDL_Keycode.SDLK_3,
  141. SDL_Keycode.SDLK_4,
  142. SDL_Keycode.SDLK_5,
  143. SDL_Keycode.SDLK_6,
  144. SDL_Keycode.SDLK_7,
  145. SDL_Keycode.SDLK_8,
  146. SDL_Keycode.SDLK_9,
  147. SDL_Keycode.SDLK_BACKQUOTE,
  148. SDL_Keycode.SDLK_BACKQUOTE,
  149. SDL_Keycode.SDLK_MINUS,
  150. SDL_Keycode.SDLK_PLUS,
  151. SDL_Keycode.SDLK_LEFTBRACKET,
  152. SDL_Keycode.SDLK_RIGHTBRACKET,
  153. SDL_Keycode.SDLK_SEMICOLON,
  154. SDL_Keycode.SDLK_QUOTE,
  155. SDL_Keycode.SDLK_COMMA,
  156. SDL_Keycode.SDLK_PERIOD,
  157. SDL_Keycode.SDLK_SLASH,
  158. SDL_Keycode.SDLK_BACKSLASH,
  159. // Invalids
  160. SDL_Keycode.SDLK_0,
  161. };
  162. public SDL2Keyboard(SDL2KeyboardDriver driver, string id, string name)
  163. {
  164. _driver = driver;
  165. Id = id;
  166. Name = name;
  167. _buttonsUserMapping = new List<ButtonMappingEntry>();
  168. }
  169. private bool HasConfiguration => _configuration != null;
  170. public string Id { get; }
  171. public string Name { get; }
  172. public bool IsConnected => true;
  173. public GamepadFeaturesFlag Features => GamepadFeaturesFlag.None;
  174. public void Dispose()
  175. {
  176. // No operations
  177. }
  178. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  179. private static int ToSDL2Scancode(Key key)
  180. {
  181. if (key >= Key.Unknown && key <= Key.Menu)
  182. {
  183. return -1;
  184. }
  185. return (int)SDL_GetScancodeFromKey(_keysDriverMapping[(int)key]);
  186. }
  187. private static SDL_Keymod GetKeyboardModifierMask(Key key)
  188. {
  189. return key switch
  190. {
  191. Key.ShiftLeft => SDL_Keymod.KMOD_LSHIFT,
  192. Key.ShiftRight => SDL_Keymod.KMOD_RSHIFT,
  193. Key.ControlLeft => SDL_Keymod.KMOD_LCTRL,
  194. Key.ControlRight => SDL_Keymod.KMOD_RCTRL,
  195. Key.AltLeft => SDL_Keymod.KMOD_LALT,
  196. Key.AltRight => SDL_Keymod.KMOD_RALT,
  197. Key.WinLeft => SDL_Keymod.KMOD_LGUI,
  198. Key.WinRight => SDL_Keymod.KMOD_RGUI,
  199. // NOTE: Menu key isn't supported by SDL2.
  200. _ => SDL_Keymod.KMOD_NONE,
  201. };
  202. }
  203. public KeyboardStateSnapshot GetKeyboardStateSnapshot()
  204. {
  205. ReadOnlySpan<byte> rawKeyboardState;
  206. SDL_Keymod rawKeyboardModifierState = SDL_GetModState();
  207. unsafe
  208. {
  209. nint statePtr = SDL_GetKeyboardState(out int numKeys);
  210. rawKeyboardState = new ReadOnlySpan<byte>((byte*)statePtr, numKeys);
  211. }
  212. bool[] keysState = new bool[(int)Key.Count];
  213. for (Key key = 0; key < Key.Count; key++)
  214. {
  215. int index = ToSDL2Scancode(key);
  216. if (index == -1)
  217. {
  218. SDL_Keymod modifierMask = GetKeyboardModifierMask(key);
  219. if (modifierMask == SDL_Keymod.KMOD_NONE)
  220. {
  221. continue;
  222. }
  223. keysState[(int)key] = (rawKeyboardModifierState & modifierMask) == modifierMask;
  224. }
  225. else
  226. {
  227. keysState[(int)key] = rawKeyboardState[index] == 1;
  228. }
  229. }
  230. return new KeyboardStateSnapshot(keysState);
  231. }
  232. private static float ConvertRawStickValue(short value)
  233. {
  234. const float ConvertRate = 1.0f / (short.MaxValue + 0.5f);
  235. return value * ConvertRate;
  236. }
  237. private static (short, short) GetStickValues(ref KeyboardStateSnapshot snapshot, JoyconConfigKeyboardStick<ConfigKey> stickConfig)
  238. {
  239. short stickX = 0;
  240. short stickY = 0;
  241. if (snapshot.IsPressed((Key)stickConfig.StickUp))
  242. {
  243. stickY += 1;
  244. }
  245. if (snapshot.IsPressed((Key)stickConfig.StickDown))
  246. {
  247. stickY -= 1;
  248. }
  249. if (snapshot.IsPressed((Key)stickConfig.StickRight))
  250. {
  251. stickX += 1;
  252. }
  253. if (snapshot.IsPressed((Key)stickConfig.StickLeft))
  254. {
  255. stickX -= 1;
  256. }
  257. Vector2 stick = Vector2.Normalize(new Vector2(stickX, stickY));
  258. return ((short)(stick.X * short.MaxValue), (short)(stick.Y * short.MaxValue));
  259. }
  260. public GamepadStateSnapshot GetMappedStateSnapshot()
  261. {
  262. KeyboardStateSnapshot rawState = GetKeyboardStateSnapshot();
  263. GamepadStateSnapshot result = default;
  264. lock (_userMappingLock)
  265. {
  266. if (!HasConfiguration)
  267. {
  268. return result;
  269. }
  270. foreach (ButtonMappingEntry entry in _buttonsUserMapping)
  271. {
  272. if (entry.From == Key.Unknown || entry.From == Key.Unbound || entry.To == GamepadButtonInputId.Unbound)
  273. {
  274. continue;
  275. }
  276. // Do not touch state of button already pressed
  277. if (!result.IsPressed(entry.To))
  278. {
  279. result.SetPressed(entry.To, rawState.IsPressed(entry.From));
  280. }
  281. }
  282. (short leftStickX, short leftStickY) = GetStickValues(ref rawState, _configuration.LeftJoyconStick);
  283. (short rightStickX, short rightStickY) = GetStickValues(ref rawState, _configuration.RightJoyconStick);
  284. result.SetStick(StickInputId.Left, ConvertRawStickValue(leftStickX), ConvertRawStickValue(leftStickY));
  285. result.SetStick(StickInputId.Right, ConvertRawStickValue(rightStickX), ConvertRawStickValue(rightStickY));
  286. }
  287. return result;
  288. }
  289. public GamepadStateSnapshot GetStateSnapshot()
  290. {
  291. throw new NotSupportedException();
  292. }
  293. public (float, float) GetStick(StickInputId inputId)
  294. {
  295. throw new NotSupportedException();
  296. }
  297. public bool IsPressed(GamepadButtonInputId inputId)
  298. {
  299. throw new NotSupportedException();
  300. }
  301. public bool IsPressed(Key key)
  302. {
  303. // We only implement GetKeyboardStateSnapshot.
  304. throw new NotSupportedException();
  305. }
  306. public void SetConfiguration(InputConfig configuration)
  307. {
  308. lock (_userMappingLock)
  309. {
  310. _configuration = (StandardKeyboardInputConfig)configuration;
  311. // First clear the buttons mapping
  312. _buttonsUserMapping.Clear();
  313. // Then configure left joycon
  314. _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick, (Key)_configuration.LeftJoyconStick.StickButton));
  315. _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp, (Key)_configuration.LeftJoycon.DpadUp));
  316. _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadDown, (Key)_configuration.LeftJoycon.DpadDown));
  317. _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadLeft, (Key)_configuration.LeftJoycon.DpadLeft));
  318. _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadRight, (Key)_configuration.LeftJoycon.DpadRight));
  319. _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Minus, (Key)_configuration.LeftJoycon.ButtonMinus));
  320. _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftShoulder, (Key)_configuration.LeftJoycon.ButtonL));
  321. _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftTrigger, (Key)_configuration.LeftJoycon.ButtonZl));
  322. _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger0, (Key)_configuration.LeftJoycon.ButtonSr));
  323. _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger0, (Key)_configuration.LeftJoycon.ButtonSl));
  324. // Finally configure right joycon
  325. _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightStick, (Key)_configuration.RightJoyconStick.StickButton));
  326. _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.A, (Key)_configuration.RightJoycon.ButtonA));
  327. _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.B, (Key)_configuration.RightJoycon.ButtonB));
  328. _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.X, (Key)_configuration.RightJoycon.ButtonX));
  329. _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Y, (Key)_configuration.RightJoycon.ButtonY));
  330. _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Plus, (Key)_configuration.RightJoycon.ButtonPlus));
  331. _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightShoulder, (Key)_configuration.RightJoycon.ButtonR));
  332. _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightTrigger, (Key)_configuration.RightJoycon.ButtonZr));
  333. _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger1, (Key)_configuration.RightJoycon.ButtonSr));
  334. _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger1, (Key)_configuration.RightJoycon.ButtonSl));
  335. }
  336. }
  337. public void SetLed(uint packedRgb)
  338. {
  339. Logger.Info?.Print(LogClass.UI, "SetLed called on an SDL2Keyboard");
  340. }
  341. public void SetTriggerThreshold(float triggerThreshold)
  342. {
  343. // No operations
  344. }
  345. public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
  346. {
  347. // No operations
  348. }
  349. public Vector3 GetMotionData(MotionInputId inputId)
  350. {
  351. // No operations
  352. return Vector3.Zero;
  353. }
  354. }
  355. }