SDL2Keyboard.cs 15 KB

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