SDL2Keyboard.cs 15 KB

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