NpadController.cs 24 KB

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