NpadController.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. using Ryujinx.Common;
  2. using Ryujinx.Common.Configuration.Hid;
  3. using Ryujinx.Common.Configuration.Hid.Controller;
  4. using Ryujinx.Common.Configuration.Hid.Controller.Motion;
  5. using Ryujinx.HLE.HOS.Services.Hid;
  6. using System;
  7. using System.Numerics;
  8. using System.Runtime.CompilerServices;
  9. using CemuHookClient = Ryujinx.Input.Motion.CemuHook.Client;
  10. using ConfigControllerType = Ryujinx.Common.Configuration.Hid.ControllerType;
  11. namespace Ryujinx.Input.HLE
  12. {
  13. public class NpadController : IDisposable
  14. {
  15. private class HLEButtonMappingEntry
  16. {
  17. public readonly GamepadButtonInputId DriverInputId;
  18. public readonly ControllerKeys HLEInput;
  19. public HLEButtonMappingEntry(GamepadButtonInputId driverInputId, ControllerKeys hleInput)
  20. {
  21. DriverInputId = driverInputId;
  22. HLEInput = hleInput;
  23. }
  24. }
  25. private static readonly HLEButtonMappingEntry[] _hleButtonMapping = new HLEButtonMappingEntry[]
  26. {
  27. new HLEButtonMappingEntry(GamepadButtonInputId.A, ControllerKeys.A),
  28. new HLEButtonMappingEntry(GamepadButtonInputId.B, ControllerKeys.B),
  29. new HLEButtonMappingEntry(GamepadButtonInputId.X, ControllerKeys.X),
  30. new HLEButtonMappingEntry(GamepadButtonInputId.Y, ControllerKeys.Y),
  31. new HLEButtonMappingEntry(GamepadButtonInputId.LeftStick, ControllerKeys.LStick),
  32. new HLEButtonMappingEntry(GamepadButtonInputId.RightStick, ControllerKeys.RStick),
  33. new HLEButtonMappingEntry(GamepadButtonInputId.LeftShoulder, ControllerKeys.L),
  34. new HLEButtonMappingEntry(GamepadButtonInputId.RightShoulder, ControllerKeys.R),
  35. new HLEButtonMappingEntry(GamepadButtonInputId.LeftTrigger, ControllerKeys.Zl),
  36. new HLEButtonMappingEntry(GamepadButtonInputId.RightTrigger, ControllerKeys.Zr),
  37. new HLEButtonMappingEntry(GamepadButtonInputId.DpadUp, ControllerKeys.DpadUp),
  38. new HLEButtonMappingEntry(GamepadButtonInputId.DpadDown, ControllerKeys.DpadDown),
  39. new HLEButtonMappingEntry(GamepadButtonInputId.DpadLeft, ControllerKeys.DpadLeft),
  40. new HLEButtonMappingEntry(GamepadButtonInputId.DpadRight, ControllerKeys.DpadRight),
  41. new HLEButtonMappingEntry(GamepadButtonInputId.Minus, ControllerKeys.Minus),
  42. new HLEButtonMappingEntry(GamepadButtonInputId.Plus, ControllerKeys.Plus),
  43. new HLEButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger0, ControllerKeys.SlLeft),
  44. new HLEButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger0, ControllerKeys.SrLeft),
  45. new HLEButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger1, ControllerKeys.SlRight),
  46. new HLEButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger1, ControllerKeys.SrRight),
  47. };
  48. private class HLEKeyboardMappingEntry
  49. {
  50. public readonly Key TargetKey;
  51. public readonly byte Target;
  52. public HLEKeyboardMappingEntry(Key targetKey, byte target)
  53. {
  54. TargetKey = targetKey;
  55. Target = target;
  56. }
  57. }
  58. private static readonly HLEKeyboardMappingEntry[] KeyMapping = new HLEKeyboardMappingEntry[]
  59. {
  60. new HLEKeyboardMappingEntry(Key.A, 0x4),
  61. new HLEKeyboardMappingEntry(Key.B, 0x5),
  62. new HLEKeyboardMappingEntry(Key.C, 0x6),
  63. new HLEKeyboardMappingEntry(Key.D, 0x7),
  64. new HLEKeyboardMappingEntry(Key.E, 0x8),
  65. new HLEKeyboardMappingEntry(Key.F, 0x9),
  66. new HLEKeyboardMappingEntry(Key.G, 0xA),
  67. new HLEKeyboardMappingEntry(Key.H, 0xB),
  68. new HLEKeyboardMappingEntry(Key.I, 0xC),
  69. new HLEKeyboardMappingEntry(Key.J, 0xD),
  70. new HLEKeyboardMappingEntry(Key.K, 0xE),
  71. new HLEKeyboardMappingEntry(Key.L, 0xF),
  72. new HLEKeyboardMappingEntry(Key.M, 0x10),
  73. new HLEKeyboardMappingEntry(Key.N, 0x11),
  74. new HLEKeyboardMappingEntry(Key.O, 0x12),
  75. new HLEKeyboardMappingEntry(Key.P, 0x13),
  76. new HLEKeyboardMappingEntry(Key.Q, 0x14),
  77. new HLEKeyboardMappingEntry(Key.R, 0x15),
  78. new HLEKeyboardMappingEntry(Key.S, 0x16),
  79. new HLEKeyboardMappingEntry(Key.T, 0x17),
  80. new HLEKeyboardMappingEntry(Key.U, 0x18),
  81. new HLEKeyboardMappingEntry(Key.V, 0x19),
  82. new HLEKeyboardMappingEntry(Key.W, 0x1A),
  83. new HLEKeyboardMappingEntry(Key.X, 0x1B),
  84. new HLEKeyboardMappingEntry(Key.Y, 0x1C),
  85. new HLEKeyboardMappingEntry(Key.Z, 0x1D),
  86. new HLEKeyboardMappingEntry(Key.Number1, 0x1E),
  87. new HLEKeyboardMappingEntry(Key.Number2, 0x1F),
  88. new HLEKeyboardMappingEntry(Key.Number3, 0x20),
  89. new HLEKeyboardMappingEntry(Key.Number4, 0x21),
  90. new HLEKeyboardMappingEntry(Key.Number5, 0x22),
  91. new HLEKeyboardMappingEntry(Key.Number6, 0x23),
  92. new HLEKeyboardMappingEntry(Key.Number7, 0x24),
  93. new HLEKeyboardMappingEntry(Key.Number8, 0x25),
  94. new HLEKeyboardMappingEntry(Key.Number9, 0x26),
  95. new HLEKeyboardMappingEntry(Key.Number0, 0x27),
  96. new HLEKeyboardMappingEntry(Key.Enter, 0x28),
  97. new HLEKeyboardMappingEntry(Key.Escape, 0x29),
  98. new HLEKeyboardMappingEntry(Key.BackSpace, 0x2A),
  99. new HLEKeyboardMappingEntry(Key.Tab, 0x2B),
  100. new HLEKeyboardMappingEntry(Key.Space, 0x2C),
  101. new HLEKeyboardMappingEntry(Key.Minus, 0x2D),
  102. new HLEKeyboardMappingEntry(Key.Plus, 0x2E),
  103. new HLEKeyboardMappingEntry(Key.BracketLeft, 0x2F),
  104. new HLEKeyboardMappingEntry(Key.BracketRight, 0x30),
  105. new HLEKeyboardMappingEntry(Key.BackSlash, 0x31),
  106. new HLEKeyboardMappingEntry(Key.Tilde, 0x32),
  107. new HLEKeyboardMappingEntry(Key.Semicolon, 0x33),
  108. new HLEKeyboardMappingEntry(Key.Quote, 0x34),
  109. new HLEKeyboardMappingEntry(Key.Grave, 0x35),
  110. new HLEKeyboardMappingEntry(Key.Comma, 0x36),
  111. new HLEKeyboardMappingEntry(Key.Period, 0x37),
  112. new HLEKeyboardMappingEntry(Key.Slash, 0x38),
  113. new HLEKeyboardMappingEntry(Key.CapsLock, 0x39),
  114. new HLEKeyboardMappingEntry(Key.F1, 0x3a),
  115. new HLEKeyboardMappingEntry(Key.F2, 0x3b),
  116. new HLEKeyboardMappingEntry(Key.F3, 0x3c),
  117. new HLEKeyboardMappingEntry(Key.F4, 0x3d),
  118. new HLEKeyboardMappingEntry(Key.F5, 0x3e),
  119. new HLEKeyboardMappingEntry(Key.F6, 0x3f),
  120. new HLEKeyboardMappingEntry(Key.F7, 0x40),
  121. new HLEKeyboardMappingEntry(Key.F8, 0x41),
  122. new HLEKeyboardMappingEntry(Key.F9, 0x42),
  123. new HLEKeyboardMappingEntry(Key.F10, 0x43),
  124. new HLEKeyboardMappingEntry(Key.F11, 0x44),
  125. new HLEKeyboardMappingEntry(Key.F12, 0x45),
  126. new HLEKeyboardMappingEntry(Key.PrintScreen, 0x46),
  127. new HLEKeyboardMappingEntry(Key.ScrollLock, 0x47),
  128. new HLEKeyboardMappingEntry(Key.Pause, 0x48),
  129. new HLEKeyboardMappingEntry(Key.Insert, 0x49),
  130. new HLEKeyboardMappingEntry(Key.Home, 0x4A),
  131. new HLEKeyboardMappingEntry(Key.PageUp, 0x4B),
  132. new HLEKeyboardMappingEntry(Key.Delete, 0x4C),
  133. new HLEKeyboardMappingEntry(Key.End, 0x4D),
  134. new HLEKeyboardMappingEntry(Key.PageDown, 0x4E),
  135. new HLEKeyboardMappingEntry(Key.Right, 0x4F),
  136. new HLEKeyboardMappingEntry(Key.Left, 0x50),
  137. new HLEKeyboardMappingEntry(Key.Down, 0x51),
  138. new HLEKeyboardMappingEntry(Key.Up, 0x52),
  139. new HLEKeyboardMappingEntry(Key.NumLock, 0x53),
  140. new HLEKeyboardMappingEntry(Key.KeypadDivide, 0x54),
  141. new HLEKeyboardMappingEntry(Key.KeypadMultiply, 0x55),
  142. new HLEKeyboardMappingEntry(Key.KeypadSubtract, 0x56),
  143. new HLEKeyboardMappingEntry(Key.KeypadAdd, 0x57),
  144. new HLEKeyboardMappingEntry(Key.KeypadEnter, 0x58),
  145. new HLEKeyboardMappingEntry(Key.Keypad1, 0x59),
  146. new HLEKeyboardMappingEntry(Key.Keypad2, 0x5A),
  147. new HLEKeyboardMappingEntry(Key.Keypad3, 0x5B),
  148. new HLEKeyboardMappingEntry(Key.Keypad4, 0x5C),
  149. new HLEKeyboardMappingEntry(Key.Keypad5, 0x5D),
  150. new HLEKeyboardMappingEntry(Key.Keypad6, 0x5E),
  151. new HLEKeyboardMappingEntry(Key.Keypad7, 0x5F),
  152. new HLEKeyboardMappingEntry(Key.Keypad8, 0x60),
  153. new HLEKeyboardMappingEntry(Key.Keypad9, 0x61),
  154. new HLEKeyboardMappingEntry(Key.Keypad0, 0x62),
  155. new HLEKeyboardMappingEntry(Key.KeypadDecimal, 0x63),
  156. new HLEKeyboardMappingEntry(Key.F13, 0x68),
  157. new HLEKeyboardMappingEntry(Key.F14, 0x69),
  158. new HLEKeyboardMappingEntry(Key.F15, 0x6A),
  159. new HLEKeyboardMappingEntry(Key.F16, 0x6B),
  160. new HLEKeyboardMappingEntry(Key.F17, 0x6C),
  161. new HLEKeyboardMappingEntry(Key.F18, 0x6D),
  162. new HLEKeyboardMappingEntry(Key.F19, 0x6E),
  163. new HLEKeyboardMappingEntry(Key.F20, 0x6F),
  164. new HLEKeyboardMappingEntry(Key.F21, 0x70),
  165. new HLEKeyboardMappingEntry(Key.F22, 0x71),
  166. new HLEKeyboardMappingEntry(Key.F23, 0x72),
  167. new HLEKeyboardMappingEntry(Key.F24, 0x73),
  168. new HLEKeyboardMappingEntry(Key.ControlLeft, 0xE0),
  169. new HLEKeyboardMappingEntry(Key.ShiftLeft, 0xE1),
  170. new HLEKeyboardMappingEntry(Key.AltLeft, 0xE2),
  171. new HLEKeyboardMappingEntry(Key.WinLeft, 0xE3),
  172. new HLEKeyboardMappingEntry(Key.ControlRight, 0xE4),
  173. new HLEKeyboardMappingEntry(Key.ShiftRight, 0xE5),
  174. new HLEKeyboardMappingEntry(Key.AltRight, 0xE6),
  175. new HLEKeyboardMappingEntry(Key.WinRight, 0xE7),
  176. };
  177. private static readonly HLEKeyboardMappingEntry[] KeyModifierMapping = new HLEKeyboardMappingEntry[]
  178. {
  179. new HLEKeyboardMappingEntry(Key.ControlLeft, 0),
  180. new HLEKeyboardMappingEntry(Key.ShiftLeft, 1),
  181. new HLEKeyboardMappingEntry(Key.AltLeft, 2),
  182. new HLEKeyboardMappingEntry(Key.WinLeft, 3),
  183. new HLEKeyboardMappingEntry(Key.ControlRight, 4),
  184. new HLEKeyboardMappingEntry(Key.ShiftRight, 5),
  185. new HLEKeyboardMappingEntry(Key.AltRight, 6),
  186. new HLEKeyboardMappingEntry(Key.WinRight, 7),
  187. new HLEKeyboardMappingEntry(Key.CapsLock, 8),
  188. new HLEKeyboardMappingEntry(Key.ScrollLock, 9),
  189. new HLEKeyboardMappingEntry(Key.NumLock, 10),
  190. };
  191. private bool _isValid;
  192. private string _id;
  193. private MotionInput _motionInput;
  194. private IGamepad _gamepad;
  195. private InputConfig _config;
  196. public IGamepadDriver GamepadDriver { get; private set; }
  197. public GamepadStateSnapshot State { get; private set; }
  198. public string Id => _id;
  199. private CemuHookClient _cemuHookClient;
  200. public NpadController(CemuHookClient cemuHookClient)
  201. {
  202. State = default;
  203. _id = null;
  204. _isValid = false;
  205. _cemuHookClient = cemuHookClient;
  206. }
  207. public bool UpdateDriverConfiguration(IGamepadDriver gamepadDriver, InputConfig config)
  208. {
  209. GamepadDriver = gamepadDriver;
  210. _gamepad?.Dispose();
  211. _id = config.Id;
  212. _gamepad = GamepadDriver.GetGamepad(_id);
  213. _isValid = _gamepad != null;
  214. UpdateUserConfiguration(config);
  215. return _isValid;
  216. }
  217. public void UpdateUserConfiguration(InputConfig config)
  218. {
  219. if (config is StandardControllerInputConfig controllerConfig)
  220. {
  221. bool needsMotionInputUpdate = _config == null || (_config is StandardControllerInputConfig oldControllerConfig &&
  222. (oldControllerConfig.Motion.EnableMotion != controllerConfig.Motion.EnableMotion) &&
  223. (oldControllerConfig.Motion.MotionBackend != controllerConfig.Motion.MotionBackend));
  224. if (needsMotionInputUpdate)
  225. {
  226. UpdateMotionInput(controllerConfig.Motion);
  227. }
  228. }
  229. else
  230. {
  231. // Non-controller doesn't have motions.
  232. _motionInput = null;
  233. }
  234. _config = config;
  235. if (_isValid)
  236. {
  237. _gamepad.SetConfiguration(config);
  238. }
  239. }
  240. private void UpdateMotionInput(MotionConfigController motionConfig)
  241. {
  242. if (motionConfig.MotionBackend != MotionInputBackendType.CemuHook)
  243. {
  244. _motionInput = new MotionInput();
  245. }
  246. else
  247. {
  248. _motionInput = null;
  249. }
  250. }
  251. public void Update()
  252. {
  253. if (_isValid && GamepadDriver != null)
  254. {
  255. State = _gamepad.GetMappedStateSnapshot();
  256. if (_config is StandardControllerInputConfig controllerConfig && controllerConfig.Motion.EnableMotion)
  257. {
  258. if (controllerConfig.Motion.MotionBackend == MotionInputBackendType.GamepadDriver)
  259. {
  260. if (_gamepad.Features.HasFlag(GamepadFeaturesFlag.Motion))
  261. {
  262. Vector3 accelerometer = _gamepad.GetMotionData(MotionInputId.Accelerometer);
  263. Vector3 gyroscope = _gamepad.GetMotionData(MotionInputId.Gyroscope);
  264. accelerometer = new Vector3(accelerometer.X, -accelerometer.Z, accelerometer.Y);
  265. gyroscope = new Vector3(gyroscope.X, gyroscope.Z, gyroscope.Y);
  266. _motionInput.Update(accelerometer, gyroscope, (ulong)PerformanceCounter.ElapsedNanoseconds / 1000, controllerConfig.Motion.Sensitivity, (float)controllerConfig.Motion.GyroDeadzone);
  267. }
  268. }
  269. else if (controllerConfig.Motion.MotionBackend == MotionInputBackendType.CemuHook && controllerConfig.Motion is CemuHookMotionConfigController cemuControllerConfig)
  270. {
  271. int clientId = (int)controllerConfig.PlayerIndex;
  272. // First of all ensure we are registered
  273. _cemuHookClient.RegisterClient(clientId, cemuControllerConfig.DsuServerHost, cemuControllerConfig.DsuServerPort);
  274. // Then request data
  275. _cemuHookClient.RequestData(clientId, cemuControllerConfig.Slot);
  276. if (controllerConfig.ControllerType == ConfigControllerType.JoyconPair && !cemuControllerConfig.MirrorInput)
  277. {
  278. _cemuHookClient.RequestData(clientId, cemuControllerConfig.AltSlot);
  279. }
  280. // Finally, get motion input data
  281. _cemuHookClient.TryGetData(clientId, cemuControllerConfig.Slot, out _motionInput);
  282. }
  283. }
  284. }
  285. else
  286. {
  287. // Reset states
  288. State = default;
  289. _motionInput = null;
  290. }
  291. }
  292. private static short ClampAxis(float value)
  293. {
  294. if (value <= -short.MaxValue)
  295. {
  296. return -short.MaxValue;
  297. }
  298. else
  299. {
  300. return (short)(value * short.MaxValue);
  301. }
  302. }
  303. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  304. private static JoystickPosition ApplyDeadzone(float x, float y, float deadzone)
  305. {
  306. return new JoystickPosition
  307. {
  308. Dx = ClampAxis(MathF.Abs(x) > deadzone ? x : 0.0f),
  309. Dy = ClampAxis(MathF.Abs(y) > deadzone ? y : 0.0f)
  310. };
  311. }
  312. public GamepadInput GetHLEInputState()
  313. {
  314. GamepadInput state = new GamepadInput();
  315. // First update all buttons
  316. foreach (HLEButtonMappingEntry entry in _hleButtonMapping)
  317. {
  318. if (State.IsPressed(entry.DriverInputId))
  319. {
  320. state.Buttons |= entry.HLEInput;
  321. }
  322. }
  323. if (_gamepad is IKeyboard)
  324. {
  325. (float leftAxisX, float leftAxisY) = State.GetStick(StickInputId.Left);
  326. (float rightAxisX, float rightAxisY) = State.GetStick(StickInputId.Right);
  327. state.LStick = new JoystickPosition
  328. {
  329. Dx = ClampAxis(leftAxisX),
  330. Dy = ClampAxis(leftAxisY)
  331. };
  332. state.RStick = new JoystickPosition
  333. {
  334. Dx = ClampAxis(rightAxisX),
  335. Dy = ClampAxis(rightAxisY)
  336. };
  337. }
  338. else if (_config is StandardControllerInputConfig controllerConfig)
  339. {
  340. (float leftAxisX, float leftAxisY) = State.GetStick(StickInputId.Left);
  341. (float rightAxisX, float rightAxisY) = State.GetStick(StickInputId.Right);
  342. state.LStick = ApplyDeadzone(leftAxisX, leftAxisY, controllerConfig.DeadzoneLeft);
  343. state.RStick = ApplyDeadzone(rightAxisX, rightAxisY, controllerConfig.DeadzoneRight);
  344. }
  345. return state;
  346. }
  347. public SixAxisInput GetHLEMotionState()
  348. {
  349. float[] orientationForHLE = new float[9];
  350. Vector3 gyroscope;
  351. Vector3 accelerometer;
  352. Vector3 rotation;
  353. if (_motionInput != null)
  354. {
  355. gyroscope = Truncate(_motionInput.Gyroscrope * 0.0027f, 3);
  356. accelerometer = Truncate(_motionInput.Accelerometer, 3);
  357. rotation = Truncate(_motionInput.Rotation * 0.0027f, 3);
  358. Matrix4x4 orientation = _motionInput.GetOrientation();
  359. orientationForHLE[0] = Math.Clamp(orientation.M11, -1f, 1f);
  360. orientationForHLE[1] = Math.Clamp(orientation.M12, -1f, 1f);
  361. orientationForHLE[2] = Math.Clamp(orientation.M13, -1f, 1f);
  362. orientationForHLE[3] = Math.Clamp(orientation.M21, -1f, 1f);
  363. orientationForHLE[4] = Math.Clamp(orientation.M22, -1f, 1f);
  364. orientationForHLE[5] = Math.Clamp(orientation.M23, -1f, 1f);
  365. orientationForHLE[6] = Math.Clamp(orientation.M31, -1f, 1f);
  366. orientationForHLE[7] = Math.Clamp(orientation.M32, -1f, 1f);
  367. orientationForHLE[8] = Math.Clamp(orientation.M33, -1f, 1f);
  368. }
  369. else
  370. {
  371. gyroscope = new Vector3();
  372. accelerometer = new Vector3();
  373. rotation = new Vector3();
  374. }
  375. return new SixAxisInput()
  376. {
  377. Accelerometer = accelerometer,
  378. Gyroscope = gyroscope,
  379. Rotation = rotation,
  380. Orientation = orientationForHLE
  381. };
  382. }
  383. private static Vector3 Truncate(Vector3 value, int decimals)
  384. {
  385. float power = MathF.Pow(10, decimals);
  386. value.X = float.IsNegative(value.X) ? MathF.Ceiling(value.X * power) / power : MathF.Floor(value.X * power) / power;
  387. value.Y = float.IsNegative(value.Y) ? MathF.Ceiling(value.Y * power) / power : MathF.Floor(value.Y * power) / power;
  388. value.Z = float.IsNegative(value.Z) ? MathF.Ceiling(value.Z * power) / power : MathF.Floor(value.Z * power) / power;
  389. return value;
  390. }
  391. public KeyboardInput? GetHLEKeyboardInput()
  392. {
  393. if (_gamepad is IKeyboard keyboard)
  394. {
  395. KeyboardStateSnapshot keyboardState = keyboard.GetKeyboardStateSnapshot();
  396. KeyboardInput hidKeyboard = new KeyboardInput
  397. {
  398. Modifier = 0,
  399. Keys = new ulong[0x4]
  400. };
  401. foreach (HLEKeyboardMappingEntry entry in KeyMapping)
  402. {
  403. ulong value = keyboardState.IsPressed(entry.TargetKey) ? 1UL : 0UL;
  404. hidKeyboard.Keys[entry.Target / 0x40] |= (value << (entry.Target % 0x40));
  405. }
  406. foreach (HLEKeyboardMappingEntry entry in KeyModifierMapping)
  407. {
  408. int value = keyboardState.IsPressed(entry.TargetKey) ? 1 : 0;
  409. hidKeyboard.Modifier |= value << entry.Target;
  410. }
  411. return hidKeyboard;
  412. }
  413. return null;
  414. }
  415. protected virtual void Dispose(bool disposing)
  416. {
  417. if (disposing)
  418. {
  419. _gamepad?.Dispose();
  420. }
  421. }
  422. public void Dispose()
  423. {
  424. Dispose(true);
  425. }
  426. }
  427. }