ControllerWindow.cs 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925
  1. using Gtk;
  2. using OpenTK.Input;
  3. using Ryujinx.Common.Configuration.Hid;
  4. using Ryujinx.Common.Utilities;
  5. using Ryujinx.Configuration;
  6. using Ryujinx.HLE.FileSystem;
  7. using System;
  8. using System.IO;
  9. using System.Reflection;
  10. using System.Text.Json;
  11. using System.Threading;
  12. using GUI = Gtk.Builder.ObjectAttribute;
  13. using Key = Ryujinx.Configuration.Hid.Key;
  14. namespace Ryujinx.Ui
  15. {
  16. public class ControllerWindow : Window
  17. {
  18. private PlayerIndex _playerIndex;
  19. private InputConfig _inputConfig;
  20. private bool _isWaitingForInput;
  21. private VirtualFileSystem _virtualFileSystem;
  22. #pragma warning disable CS0649, IDE0044
  23. [GUI] Adjustment _controllerDeadzoneLeft;
  24. [GUI] Adjustment _controllerDeadzoneRight;
  25. [GUI] Adjustment _controllerTriggerThreshold;
  26. [GUI] ComboBoxText _inputDevice;
  27. [GUI] ComboBoxText _profile;
  28. [GUI] ToggleButton _refreshInputDevicesButton;
  29. [GUI] Box _settingsBox;
  30. [GUI] Grid _leftStickKeyboard;
  31. [GUI] Grid _leftStickController;
  32. [GUI] Box _deadZoneLeftBox;
  33. [GUI] Grid _rightStickKeyboard;
  34. [GUI] Grid _rightStickController;
  35. [GUI] Box _deadZoneRightBox;
  36. [GUI] Grid _leftSideTriggerBox;
  37. [GUI] Grid _rightSideTriggerBox;
  38. [GUI] Box _triggerThresholdBox;
  39. [GUI] ComboBoxText _controllerType;
  40. [GUI] ToggleButton _lStickX;
  41. [GUI] CheckButton _invertLStickX;
  42. [GUI] ToggleButton _lStickY;
  43. [GUI] CheckButton _invertLStickY;
  44. [GUI] ToggleButton _lStickUp;
  45. [GUI] ToggleButton _lStickDown;
  46. [GUI] ToggleButton _lStickLeft;
  47. [GUI] ToggleButton _lStickRight;
  48. [GUI] ToggleButton _lStickButton;
  49. [GUI] ToggleButton _dpadUp;
  50. [GUI] ToggleButton _dpadDown;
  51. [GUI] ToggleButton _dpadLeft;
  52. [GUI] ToggleButton _dpadRight;
  53. [GUI] ToggleButton _minus;
  54. [GUI] ToggleButton _l;
  55. [GUI] ToggleButton _zL;
  56. [GUI] ToggleButton _rStickX;
  57. [GUI] CheckButton _invertRStickX;
  58. [GUI] ToggleButton _rStickY;
  59. [GUI] CheckButton _invertRStickY;
  60. [GUI] ToggleButton _rStickUp;
  61. [GUI] ToggleButton _rStickDown;
  62. [GUI] ToggleButton _rStickLeft;
  63. [GUI] ToggleButton _rStickRight;
  64. [GUI] ToggleButton _rStickButton;
  65. [GUI] ToggleButton _a;
  66. [GUI] ToggleButton _b;
  67. [GUI] ToggleButton _x;
  68. [GUI] ToggleButton _y;
  69. [GUI] ToggleButton _plus;
  70. [GUI] ToggleButton _r;
  71. [GUI] ToggleButton _zR;
  72. [GUI] ToggleButton _lSl;
  73. [GUI] ToggleButton _lSr;
  74. [GUI] ToggleButton _rSl;
  75. [GUI] ToggleButton _rSr;
  76. [GUI] Image _controllerImage;
  77. #pragma warning restore CS0649, IDE0044
  78. public ControllerWindow(PlayerIndex controllerId, VirtualFileSystem virtualFileSystem) : this(new Builder("Ryujinx.Ui.ControllerWindow.glade"), controllerId, virtualFileSystem) { }
  79. private ControllerWindow(Builder builder, PlayerIndex controllerId, VirtualFileSystem virtualFileSystem) : base(builder.GetObject("_controllerWin").Handle)
  80. {
  81. builder.Autoconnect(this);
  82. this.Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png");
  83. _playerIndex = controllerId;
  84. _virtualFileSystem = virtualFileSystem;
  85. _inputConfig = ConfigurationState.Instance.Hid.InputConfig.Value.Find(inputConfig => inputConfig.PlayerIndex == _playerIndex);
  86. //Bind Events
  87. _lStickX.Clicked += Button_Pressed;
  88. _lStickY.Clicked += Button_Pressed;
  89. _lStickUp.Clicked += Button_Pressed;
  90. _lStickDown.Clicked += Button_Pressed;
  91. _lStickLeft.Clicked += Button_Pressed;
  92. _lStickRight.Clicked += Button_Pressed;
  93. _lStickButton.Clicked += Button_Pressed;
  94. _dpadUp.Clicked += Button_Pressed;
  95. _dpadDown.Clicked += Button_Pressed;
  96. _dpadLeft.Clicked += Button_Pressed;
  97. _dpadRight.Clicked += Button_Pressed;
  98. _minus.Clicked += Button_Pressed;
  99. _l.Clicked += Button_Pressed;
  100. _zL.Clicked += Button_Pressed;
  101. _lSl.Clicked += Button_Pressed;
  102. _lSr.Clicked += Button_Pressed;
  103. _rStickX.Clicked += Button_Pressed;
  104. _rStickY.Clicked += Button_Pressed;
  105. _rStickUp.Clicked += Button_Pressed;
  106. _rStickDown.Clicked += Button_Pressed;
  107. _rStickLeft.Clicked += Button_Pressed;
  108. _rStickRight.Clicked += Button_Pressed;
  109. _rStickButton.Clicked += Button_Pressed;
  110. _a.Clicked += Button_Pressed;
  111. _b.Clicked += Button_Pressed;
  112. _x.Clicked += Button_Pressed;
  113. _y.Clicked += Button_Pressed;
  114. _plus.Clicked += Button_Pressed;
  115. _r.Clicked += Button_Pressed;
  116. _zR.Clicked += Button_Pressed;
  117. _rSl.Clicked += Button_Pressed;
  118. _rSr.Clicked += Button_Pressed;
  119. // Setup current values
  120. UpdateInputDeviceList();
  121. SetAvailableOptions();
  122. ClearValues();
  123. if (_inputDevice.ActiveId != null) SetCurrentValues();
  124. }
  125. private void UpdateInputDeviceList()
  126. {
  127. _inputDevice.RemoveAll();
  128. _inputDevice.Append("disabled", "Disabled");
  129. _inputDevice.SetActiveId("disabled");
  130. _inputDevice.Append($"keyboard/{KeyboardConfig.AllKeyboardsIndex}", "All keyboards");
  131. for (int i = 0; i < 20; i++)
  132. {
  133. if (KeyboardController.GetKeyboardState(i + 1).IsConnected)
  134. _inputDevice.Append($"keyboard/{i + 1}", $"Keyboard/{i + 1}");
  135. if (GamePad.GetState(i).IsConnected)
  136. _inputDevice.Append($"controller/{i}", $"Controller/{i} ({GamePad.GetName(i)})");
  137. }
  138. switch (_inputConfig)
  139. {
  140. case KeyboardConfig keyboard:
  141. _inputDevice.SetActiveId($"keyboard/{keyboard.Index}");
  142. break;
  143. case ControllerConfig controller:
  144. _inputDevice.SetActiveId($"controller/{controller.Index}");
  145. break;
  146. }
  147. }
  148. private void SetAvailableOptions()
  149. {
  150. if (_inputDevice.ActiveId != null && _inputDevice.ActiveId.StartsWith("keyboard"))
  151. {
  152. this.ShowAll();
  153. _leftStickController.Hide();
  154. _rightStickController.Hide();
  155. _deadZoneLeftBox.Hide();
  156. _deadZoneRightBox.Hide();
  157. _triggerThresholdBox.Hide();
  158. }
  159. else if (_inputDevice.ActiveId != null && _inputDevice.ActiveId.StartsWith("controller"))
  160. {
  161. this.ShowAll();
  162. _leftStickKeyboard.Hide();
  163. _rightStickKeyboard.Hide();
  164. }
  165. else
  166. {
  167. _settingsBox.Hide();
  168. }
  169. ClearValues();
  170. }
  171. private void SetCurrentValues()
  172. {
  173. SetControllerSpecificFields();
  174. SetProfiles();
  175. if (_inputDevice.ActiveId.StartsWith("keyboard") && _inputConfig is KeyboardConfig)
  176. {
  177. SetValues(_inputConfig);
  178. }
  179. else if (_inputDevice.ActiveId.StartsWith("controller") && _inputConfig is ControllerConfig)
  180. {
  181. SetValues(_inputConfig);
  182. }
  183. }
  184. private void SetControllerSpecificFields()
  185. {
  186. _leftSideTriggerBox.Hide();
  187. _rightSideTriggerBox.Hide();
  188. switch (_controllerType.ActiveId)
  189. {
  190. case "JoyconLeft":
  191. _leftSideTriggerBox.Show();
  192. break;
  193. case "JoyconRight":
  194. _rightSideTriggerBox.Show();
  195. break;
  196. }
  197. switch (_controllerType.ActiveId)
  198. {
  199. case "ProController":
  200. _controllerImage.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.ProCon.svg", 400, 400);
  201. break;
  202. case "JoyconLeft":
  203. _controllerImage.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.JoyConLeft.svg", 400, 400);
  204. break;
  205. case "JoyconRight":
  206. _controllerImage.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.JoyConRight.svg", 400, 400);
  207. break;
  208. default:
  209. _controllerImage.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.JoyConPair.svg", 400, 400);
  210. break;
  211. }
  212. }
  213. private void ClearValues()
  214. {
  215. _lStickX.Label = "Unbound";
  216. _lStickY.Label = "Unbound";
  217. _lStickUp.Label = "Unbound";
  218. _lStickDown.Label = "Unbound";
  219. _lStickLeft.Label = "Unbound";
  220. _lStickRight.Label = "Unbound";
  221. _lStickButton.Label = "Unbound";
  222. _dpadUp.Label = "Unbound";
  223. _dpadDown.Label = "Unbound";
  224. _dpadLeft.Label = "Unbound";
  225. _dpadRight.Label = "Unbound";
  226. _minus.Label = "Unbound";
  227. _l.Label = "Unbound";
  228. _zL.Label = "Unbound";
  229. _lSl.Label = "Unbound";
  230. _lSr.Label = "Unbound";
  231. _rStickX.Label = "Unbound";
  232. _rStickY.Label = "Unbound";
  233. _rStickUp.Label = "Unbound";
  234. _rStickDown.Label = "Unbound";
  235. _rStickLeft.Label = "Unbound";
  236. _rStickRight.Label = "Unbound";
  237. _rStickButton.Label = "Unbound";
  238. _a.Label = "Unbound";
  239. _b.Label = "Unbound";
  240. _x.Label = "Unbound";
  241. _y.Label = "Unbound";
  242. _plus.Label = "Unbound";
  243. _r.Label = "Unbound";
  244. _zR.Label = "Unbound";
  245. _rSl.Label = "Unbound";
  246. _rSr.Label = "Unbound";
  247. _controllerDeadzoneLeft.Value = 0;
  248. _controllerDeadzoneRight.Value = 0;
  249. _controllerTriggerThreshold.Value = 0;
  250. }
  251. private void SetValues(InputConfig config)
  252. {
  253. switch (config)
  254. {
  255. case KeyboardConfig keyboardConfig:
  256. _controllerType.SetActiveId(keyboardConfig.ControllerType.ToString());
  257. _lStickUp.Label = keyboardConfig.LeftJoycon.StickUp.ToString();
  258. _lStickDown.Label = keyboardConfig.LeftJoycon.StickDown.ToString();
  259. _lStickLeft.Label = keyboardConfig.LeftJoycon.StickLeft.ToString();
  260. _lStickRight.Label = keyboardConfig.LeftJoycon.StickRight.ToString();
  261. _lStickButton.Label = keyboardConfig.LeftJoycon.StickButton.ToString();
  262. _dpadUp.Label = keyboardConfig.LeftJoycon.DPadUp.ToString();
  263. _dpadDown.Label = keyboardConfig.LeftJoycon.DPadDown.ToString();
  264. _dpadLeft.Label = keyboardConfig.LeftJoycon.DPadLeft.ToString();
  265. _dpadRight.Label = keyboardConfig.LeftJoycon.DPadRight.ToString();
  266. _minus.Label = keyboardConfig.LeftJoycon.ButtonMinus.ToString();
  267. _l.Label = keyboardConfig.LeftJoycon.ButtonL.ToString();
  268. _zL.Label = keyboardConfig.LeftJoycon.ButtonZl.ToString();
  269. _lSl.Label = keyboardConfig.LeftJoycon.ButtonSl.ToString();
  270. _lSr.Label = keyboardConfig.LeftJoycon.ButtonSr.ToString();
  271. _rStickUp.Label = keyboardConfig.RightJoycon.StickUp.ToString();
  272. _rStickDown.Label = keyboardConfig.RightJoycon.StickDown.ToString();
  273. _rStickLeft.Label = keyboardConfig.RightJoycon.StickLeft.ToString();
  274. _rStickRight.Label = keyboardConfig.RightJoycon.StickRight.ToString();
  275. _rStickButton.Label = keyboardConfig.RightJoycon.StickButton.ToString();
  276. _a.Label = keyboardConfig.RightJoycon.ButtonA.ToString();
  277. _b.Label = keyboardConfig.RightJoycon.ButtonB.ToString();
  278. _x.Label = keyboardConfig.RightJoycon.ButtonX.ToString();
  279. _y.Label = keyboardConfig.RightJoycon.ButtonY.ToString();
  280. _plus.Label = keyboardConfig.RightJoycon.ButtonPlus.ToString();
  281. _r.Label = keyboardConfig.RightJoycon.ButtonR.ToString();
  282. _zR.Label = keyboardConfig.RightJoycon.ButtonZr.ToString();
  283. _rSl.Label = keyboardConfig.RightJoycon.ButtonSl.ToString();
  284. _rSr.Label = keyboardConfig.RightJoycon.ButtonSr.ToString();
  285. break;
  286. case ControllerConfig controllerConfig:
  287. _controllerType.SetActiveId(controllerConfig.ControllerType.ToString());
  288. _lStickX.Label = controllerConfig.LeftJoycon.StickX.ToString();
  289. _invertLStickX.Active = controllerConfig.LeftJoycon.InvertStickX;
  290. _lStickY.Label = controllerConfig.LeftJoycon.StickY.ToString();
  291. _invertLStickY.Active = controllerConfig.LeftJoycon.InvertStickY;
  292. _lStickButton.Label = controllerConfig.LeftJoycon.StickButton.ToString();
  293. _dpadUp.Label = controllerConfig.LeftJoycon.DPadUp.ToString();
  294. _dpadDown.Label = controllerConfig.LeftJoycon.DPadDown.ToString();
  295. _dpadLeft.Label = controllerConfig.LeftJoycon.DPadLeft.ToString();
  296. _dpadRight.Label = controllerConfig.LeftJoycon.DPadRight.ToString();
  297. _minus.Label = controllerConfig.LeftJoycon.ButtonMinus.ToString();
  298. _l.Label = controllerConfig.LeftJoycon.ButtonL.ToString();
  299. _zL.Label = controllerConfig.LeftJoycon.ButtonZl.ToString();
  300. _lSl.Label = controllerConfig.LeftJoycon.ButtonSl.ToString();
  301. _lSr.Label = controllerConfig.LeftJoycon.ButtonSr.ToString();
  302. _rStickX.Label = controllerConfig.RightJoycon.StickX.ToString();
  303. _invertRStickX.Active = controllerConfig.RightJoycon.InvertStickX;
  304. _rStickY.Label = controllerConfig.RightJoycon.StickY.ToString();
  305. _invertRStickY.Active = controllerConfig.RightJoycon.InvertStickY;
  306. _rStickButton.Label = controllerConfig.RightJoycon.StickButton.ToString();
  307. _a.Label = controllerConfig.RightJoycon.ButtonA.ToString();
  308. _b.Label = controllerConfig.RightJoycon.ButtonB.ToString();
  309. _x.Label = controllerConfig.RightJoycon.ButtonX.ToString();
  310. _y.Label = controllerConfig.RightJoycon.ButtonY.ToString();
  311. _plus.Label = controllerConfig.RightJoycon.ButtonPlus.ToString();
  312. _r.Label = controllerConfig.RightJoycon.ButtonR.ToString();
  313. _zR.Label = controllerConfig.RightJoycon.ButtonZr.ToString();
  314. _rSl.Label = controllerConfig.RightJoycon.ButtonSl.ToString();
  315. _rSr.Label = controllerConfig.RightJoycon.ButtonSr.ToString();
  316. _controllerDeadzoneLeft.Value = controllerConfig.DeadzoneLeft;
  317. _controllerDeadzoneRight.Value = controllerConfig.DeadzoneRight;
  318. _controllerTriggerThreshold.Value = controllerConfig.TriggerThreshold;
  319. break;
  320. }
  321. }
  322. private InputConfig GetValues()
  323. {
  324. if (_inputDevice.ActiveId.StartsWith("keyboard"))
  325. {
  326. Enum.TryParse(_lStickUp.Label, out Key lStickUp);
  327. Enum.TryParse(_lStickDown.Label, out Key lStickDown);
  328. Enum.TryParse(_lStickLeft.Label, out Key lStickLeft);
  329. Enum.TryParse(_lStickRight.Label, out Key lStickRight);
  330. Enum.TryParse(_lStickButton.Label, out Key lStickButton);
  331. Enum.TryParse(_dpadUp.Label, out Key lDPadUp);
  332. Enum.TryParse(_dpadDown.Label, out Key lDPadDown);
  333. Enum.TryParse(_dpadLeft.Label, out Key lDPadLeft);
  334. Enum.TryParse(_dpadRight.Label, out Key lDPadRight);
  335. Enum.TryParse(_minus.Label, out Key lButtonMinus);
  336. Enum.TryParse(_l.Label, out Key lButtonL);
  337. Enum.TryParse(_zL.Label, out Key lButtonZl);
  338. Enum.TryParse(_lSl.Label, out Key lButtonSl);
  339. Enum.TryParse(_lSr.Label, out Key lButtonSr);
  340. Enum.TryParse(_rStickUp.Label, out Key rStickUp);
  341. Enum.TryParse(_rStickDown.Label, out Key rStickDown);
  342. Enum.TryParse(_rStickLeft.Label, out Key rStickLeft);
  343. Enum.TryParse(_rStickRight.Label, out Key rStickRight);
  344. Enum.TryParse(_rStickButton.Label, out Key rStickButton);
  345. Enum.TryParse(_a.Label, out Key rButtonA);
  346. Enum.TryParse(_b.Label, out Key rButtonB);
  347. Enum.TryParse(_x.Label, out Key rButtonX);
  348. Enum.TryParse(_y.Label, out Key rButtonY);
  349. Enum.TryParse(_plus.Label, out Key rButtonPlus);
  350. Enum.TryParse(_r.Label, out Key rButtonR);
  351. Enum.TryParse(_zR.Label, out Key rButtonZr);
  352. Enum.TryParse(_rSl.Label, out Key rButtonSl);
  353. Enum.TryParse(_rSr.Label, out Key rButtonSr);
  354. return new KeyboardConfig
  355. {
  356. Index = int.Parse(_inputDevice.ActiveId.Split("/")[1]),
  357. ControllerType = Enum.Parse<ControllerType>(_controllerType.ActiveId),
  358. PlayerIndex = _playerIndex,
  359. LeftJoycon = new NpadKeyboardLeft
  360. {
  361. StickUp = lStickUp,
  362. StickDown = lStickDown,
  363. StickLeft = lStickLeft,
  364. StickRight = lStickRight,
  365. StickButton = lStickButton,
  366. DPadUp = lDPadUp,
  367. DPadDown = lDPadDown,
  368. DPadLeft = lDPadLeft,
  369. DPadRight = lDPadRight,
  370. ButtonMinus = lButtonMinus,
  371. ButtonL = lButtonL,
  372. ButtonZl = lButtonZl,
  373. ButtonSl = lButtonSl,
  374. ButtonSr = lButtonSr
  375. },
  376. RightJoycon = new NpadKeyboardRight
  377. {
  378. StickUp = rStickUp,
  379. StickDown = rStickDown,
  380. StickLeft = rStickLeft,
  381. StickRight = rStickRight,
  382. StickButton = rStickButton,
  383. ButtonA = rButtonA,
  384. ButtonB = rButtonB,
  385. ButtonX = rButtonX,
  386. ButtonY = rButtonY,
  387. ButtonPlus = rButtonPlus,
  388. ButtonR = rButtonR,
  389. ButtonZr = rButtonZr,
  390. ButtonSl = rButtonSl,
  391. ButtonSr = rButtonSr
  392. }
  393. };
  394. }
  395. if (_inputDevice.ActiveId.StartsWith("controller"))
  396. {
  397. Enum.TryParse(_lStickX.Label, out ControllerInputId lStickX);
  398. Enum.TryParse(_lStickY.Label, out ControllerInputId lStickY);
  399. Enum.TryParse(_lStickButton.Label, out ControllerInputId lStickButton);
  400. Enum.TryParse(_minus.Label, out ControllerInputId lButtonMinus);
  401. Enum.TryParse(_l.Label, out ControllerInputId lButtonL);
  402. Enum.TryParse(_zL.Label, out ControllerInputId lButtonZl);
  403. Enum.TryParse(_lSl.Label, out ControllerInputId lButtonSl);
  404. Enum.TryParse(_lSr.Label, out ControllerInputId lButtonSr);
  405. Enum.TryParse(_dpadUp.Label, out ControllerInputId lDPadUp);
  406. Enum.TryParse(_dpadDown.Label, out ControllerInputId lDPadDown);
  407. Enum.TryParse(_dpadLeft.Label, out ControllerInputId lDPadLeft);
  408. Enum.TryParse(_dpadRight.Label, out ControllerInputId lDPadRight);
  409. Enum.TryParse(_rStickX.Label, out ControllerInputId rStickX);
  410. Enum.TryParse(_rStickY.Label, out ControllerInputId rStickY);
  411. Enum.TryParse(_rStickButton.Label, out ControllerInputId rStickButton);
  412. Enum.TryParse(_a.Label, out ControllerInputId rButtonA);
  413. Enum.TryParse(_b.Label, out ControllerInputId rButtonB);
  414. Enum.TryParse(_x.Label, out ControllerInputId rButtonX);
  415. Enum.TryParse(_y.Label, out ControllerInputId rButtonY);
  416. Enum.TryParse(_plus.Label, out ControllerInputId rButtonPlus);
  417. Enum.TryParse(_r.Label, out ControllerInputId rButtonR);
  418. Enum.TryParse(_zR.Label, out ControllerInputId rButtonZr);
  419. Enum.TryParse(_rSl.Label, out ControllerInputId rButtonSl);
  420. Enum.TryParse(_rSr.Label, out ControllerInputId rButtonSr);
  421. return new ControllerConfig
  422. {
  423. Index = int.Parse(_inputDevice.ActiveId.Split("/")[1]),
  424. ControllerType = Enum.Parse<ControllerType>(_controllerType.ActiveId),
  425. PlayerIndex = _playerIndex,
  426. DeadzoneLeft = (float)_controllerDeadzoneLeft.Value,
  427. DeadzoneRight = (float)_controllerDeadzoneRight.Value,
  428. TriggerThreshold = (float)_controllerTriggerThreshold.Value,
  429. LeftJoycon = new NpadControllerLeft
  430. {
  431. InvertStickX = _invertLStickX.Active,
  432. StickX = lStickX,
  433. InvertStickY = _invertLStickY.Active,
  434. StickY = lStickY,
  435. StickButton = lStickButton,
  436. ButtonMinus = lButtonMinus,
  437. ButtonL = lButtonL,
  438. ButtonZl = lButtonZl,
  439. ButtonSl = lButtonSl,
  440. ButtonSr = lButtonSr,
  441. DPadUp = lDPadUp,
  442. DPadDown = lDPadDown,
  443. DPadLeft = lDPadLeft,
  444. DPadRight = lDPadRight
  445. },
  446. RightJoycon = new NpadControllerRight
  447. {
  448. InvertStickX = _invertRStickX.Active,
  449. StickX = rStickX,
  450. InvertStickY = _invertRStickY.Active,
  451. StickY = rStickY,
  452. StickButton = rStickButton,
  453. ButtonA = rButtonA,
  454. ButtonB = rButtonB,
  455. ButtonX = rButtonX,
  456. ButtonY = rButtonY,
  457. ButtonPlus = rButtonPlus,
  458. ButtonR = rButtonR,
  459. ButtonZr = rButtonZr,
  460. ButtonSl = rButtonSl,
  461. ButtonSr = rButtonSr
  462. }
  463. };
  464. }
  465. if (!_inputDevice.ActiveId.StartsWith("disabled"))
  466. {
  467. GtkDialog.CreateErrorDialog("Some fields entered where invalid and therefore your config was not saved.");
  468. }
  469. return null;
  470. }
  471. private static bool IsAnyKeyPressed(out Key pressedKey, int index)
  472. {
  473. KeyboardState keyboardState = KeyboardController.GetKeyboardState(index);
  474. foreach (Key key in Enum.GetValues(typeof(Key)))
  475. {
  476. if (keyboardState.IsKeyDown((OpenTK.Input.Key)key))
  477. {
  478. pressedKey = key;
  479. return true;
  480. }
  481. }
  482. pressedKey = Key.Unbound;
  483. return false;
  484. }
  485. private static bool IsAnyButtonPressed(out ControllerInputId pressedButton, int index, double triggerThreshold)
  486. {
  487. JoystickState joystickState = Joystick.GetState(index);
  488. JoystickCapabilities joystickCapabilities = Joystick.GetCapabilities(index);
  489. //Buttons
  490. for (int i = 0; i != joystickCapabilities.ButtonCount; i++)
  491. {
  492. if (joystickState.IsButtonDown(i))
  493. {
  494. Enum.TryParse($"Button{i}", out pressedButton);
  495. return true;
  496. }
  497. }
  498. //Axis
  499. for (int i = 0; i != joystickCapabilities.AxisCount; i++)
  500. {
  501. if (joystickState.GetAxis(i) > 0.5f && joystickState.GetAxis(i) > triggerThreshold)
  502. {
  503. Enum.TryParse($"Axis{i}", out pressedButton);
  504. return true;
  505. }
  506. }
  507. //Hats
  508. for (int i = 0; i != joystickCapabilities.HatCount; i++)
  509. {
  510. JoystickHatState hatState = joystickState.GetHat((JoystickHat)i);
  511. string pos = null;
  512. if (hatState.IsUp) pos = "Up";
  513. if (hatState.IsDown) pos = "Down";
  514. if (hatState.IsLeft) pos = "Left";
  515. if (hatState.IsRight) pos = "Right";
  516. if (pos == null) continue;
  517. Enum.TryParse($"Hat{i}{pos}", out pressedButton);
  518. return true;
  519. }
  520. pressedButton = ControllerInputId.Unbound;
  521. return false;
  522. }
  523. private string GetProfileBasePath()
  524. {
  525. string path = System.IO.Path.Combine(_virtualFileSystem.GetBasePath(), "profiles");
  526. if (_inputDevice.ActiveId.StartsWith("keyboard"))
  527. {
  528. path = System.IO.Path.Combine(path, "keyboard");
  529. }
  530. else if (_inputDevice.ActiveId.StartsWith("controller"))
  531. {
  532. path = System.IO.Path.Combine(path, "controller");
  533. }
  534. return path;
  535. }
  536. //Events
  537. private void InputDevice_Changed(object sender, EventArgs args)
  538. {
  539. SetAvailableOptions();
  540. SetControllerSpecificFields();
  541. if (_inputDevice.ActiveId != null) SetProfiles();
  542. }
  543. private void Controller_Changed(object sender, EventArgs args)
  544. {
  545. SetControllerSpecificFields();
  546. }
  547. private void RefreshInputDevicesButton_Pressed(object sender, EventArgs args)
  548. {
  549. UpdateInputDeviceList();
  550. _refreshInputDevicesButton.SetStateFlags(0, true);
  551. }
  552. private void Button_Pressed(object sender, EventArgs args)
  553. {
  554. if (_isWaitingForInput)
  555. {
  556. return;
  557. }
  558. _isWaitingForInput = true;
  559. Thread inputThread = new Thread(() =>
  560. {
  561. Button button = (ToggleButton)sender;
  562. if (_inputDevice.ActiveId.StartsWith("keyboard"))
  563. {
  564. Key pressedKey;
  565. int index = int.Parse(_inputDevice.ActiveId.Split("/")[1]);
  566. while (!IsAnyKeyPressed(out pressedKey, index))
  567. {
  568. if (Mouse.GetState().IsAnyButtonDown || Keyboard.GetState().IsKeyDown(OpenTK.Input.Key.Escape))
  569. {
  570. Application.Invoke(delegate
  571. {
  572. button.SetStateFlags(0, true);
  573. });
  574. _isWaitingForInput = false;
  575. return;
  576. }
  577. }
  578. Application.Invoke(delegate
  579. {
  580. button.Label = pressedKey.ToString();
  581. button.SetStateFlags(0, true);
  582. });
  583. }
  584. else if (_inputDevice.ActiveId.StartsWith("controller"))
  585. {
  586. ControllerInputId pressedButton;
  587. int index = int.Parse(_inputDevice.ActiveId.Split("/")[1]);
  588. while (!IsAnyButtonPressed(out pressedButton, index, _controllerTriggerThreshold.Value))
  589. {
  590. if (Mouse.GetState().IsAnyButtonDown || Keyboard.GetState().IsAnyKeyDown)
  591. {
  592. Application.Invoke(delegate
  593. {
  594. button.SetStateFlags(0, true);
  595. });
  596. _isWaitingForInput = false;
  597. return;
  598. }
  599. }
  600. Application.Invoke(delegate
  601. {
  602. button.Label = pressedButton.ToString();
  603. button.SetStateFlags(0, true);
  604. });
  605. }
  606. _isWaitingForInput = false;
  607. });
  608. inputThread.Name = "GUI.InputThread";
  609. inputThread.IsBackground = true;
  610. inputThread.Start();
  611. }
  612. private void SetProfiles()
  613. {
  614. string basePath = GetProfileBasePath();
  615. if (!Directory.Exists(basePath))
  616. {
  617. Directory.CreateDirectory(basePath);
  618. }
  619. _profile.RemoveAll();
  620. _profile.Append("default", "Default");
  621. foreach (string profile in Directory.GetFiles(basePath, "*.*", SearchOption.AllDirectories))
  622. {
  623. _profile.Append(System.IO.Path.GetFileName(profile), System.IO.Path.GetFileNameWithoutExtension(profile));
  624. }
  625. }
  626. private void ProfileLoad_Activated(object sender, EventArgs args)
  627. {
  628. ((ToggleButton)sender).SetStateFlags(0, true);
  629. if (_inputDevice.ActiveId == "disabled" || _profile.ActiveId == null) return;
  630. InputConfig config = null;
  631. int pos = _profile.Active;
  632. if (_profile.ActiveId == "default")
  633. {
  634. if (_inputDevice.ActiveId.StartsWith("keyboard"))
  635. {
  636. config = new KeyboardConfig
  637. {
  638. Index = 0,
  639. ControllerType = ControllerType.JoyconPair,
  640. LeftJoycon = new NpadKeyboardLeft
  641. {
  642. StickUp = Key.W,
  643. StickDown = Key.S,
  644. StickLeft = Key.A,
  645. StickRight = Key.D,
  646. StickButton = Key.F,
  647. DPadUp = Key.Up,
  648. DPadDown = Key.Down,
  649. DPadLeft = Key.Left,
  650. DPadRight = Key.Right,
  651. ButtonMinus = Key.Minus,
  652. ButtonL = Key.E,
  653. ButtonZl = Key.Q,
  654. ButtonSl = Key.Unbound,
  655. ButtonSr = Key.Unbound
  656. },
  657. RightJoycon = new NpadKeyboardRight
  658. {
  659. StickUp = Key.I,
  660. StickDown = Key.K,
  661. StickLeft = Key.J,
  662. StickRight = Key.L,
  663. StickButton = Key.H,
  664. ButtonA = Key.Z,
  665. ButtonB = Key.X,
  666. ButtonX = Key.C,
  667. ButtonY = Key.V,
  668. ButtonPlus = Key.Plus,
  669. ButtonR = Key.U,
  670. ButtonZr = Key.O,
  671. ButtonSl = Key.Unbound,
  672. ButtonSr = Key.Unbound
  673. }
  674. };
  675. }
  676. else if (_inputDevice.ActiveId.StartsWith("controller"))
  677. {
  678. config = new ControllerConfig
  679. {
  680. Index = 0,
  681. ControllerType = ControllerType.ProController,
  682. DeadzoneLeft = 0.1f,
  683. DeadzoneRight = 0.1f,
  684. TriggerThreshold = 0.5f,
  685. LeftJoycon = new NpadControllerLeft
  686. {
  687. StickX = ControllerInputId.Axis0,
  688. StickY = ControllerInputId.Axis1,
  689. StickButton = ControllerInputId.Button8,
  690. DPadUp = ControllerInputId.Hat0Up,
  691. DPadDown = ControllerInputId.Hat0Down,
  692. DPadLeft = ControllerInputId.Hat0Left,
  693. DPadRight = ControllerInputId.Hat0Right,
  694. ButtonMinus = ControllerInputId.Button6,
  695. ButtonL = ControllerInputId.Button4,
  696. ButtonZl = ControllerInputId.Axis2,
  697. ButtonSl = ControllerInputId.Unbound,
  698. ButtonSr = ControllerInputId.Unbound,
  699. InvertStickX = false,
  700. InvertStickY = false
  701. },
  702. RightJoycon = new NpadControllerRight
  703. {
  704. StickX = ControllerInputId.Axis3,
  705. StickY = ControllerInputId.Axis4,
  706. StickButton = ControllerInputId.Button9,
  707. ButtonA = ControllerInputId.Button1,
  708. ButtonB = ControllerInputId.Button0,
  709. ButtonX = ControllerInputId.Button3,
  710. ButtonY = ControllerInputId.Button2,
  711. ButtonPlus = ControllerInputId.Button7,
  712. ButtonR = ControllerInputId.Button5,
  713. ButtonZr = ControllerInputId.Axis5,
  714. ButtonSl = ControllerInputId.Unbound,
  715. ButtonSr = ControllerInputId.Unbound,
  716. InvertStickX = false,
  717. InvertStickY = false
  718. }
  719. };
  720. }
  721. }
  722. else
  723. {
  724. string path = System.IO.Path.Combine(GetProfileBasePath(), _profile.ActiveId);
  725. if (!File.Exists(path))
  726. {
  727. if (pos >= 0)
  728. {
  729. _profile.Remove(pos);
  730. }
  731. return;
  732. }
  733. try
  734. {
  735. using (Stream stream = File.OpenRead(path))
  736. {
  737. config = JsonHelper.Deserialize<ControllerConfig>(stream);
  738. }
  739. }
  740. catch (JsonException)
  741. {
  742. try
  743. {
  744. using (Stream stream = File.OpenRead(path))
  745. {
  746. config = JsonHelper.Deserialize<KeyboardConfig>(stream);
  747. }
  748. }
  749. catch { }
  750. }
  751. }
  752. SetValues(config);
  753. }
  754. private void ProfileAdd_Activated(object sender, EventArgs args)
  755. {
  756. ((ToggleButton)sender).SetStateFlags(0, true);
  757. if (_inputDevice.ActiveId == "disabled") return;
  758. InputConfig inputConfig = GetValues();
  759. ProfileDialog profileDialog = new ProfileDialog();
  760. if (inputConfig == null) return;
  761. if (profileDialog.Run() == (int)ResponseType.Ok)
  762. {
  763. string path = System.IO.Path.Combine(GetProfileBasePath(), profileDialog.FileName);
  764. string jsonString;
  765. if (inputConfig is KeyboardConfig keyboardConfig)
  766. {
  767. jsonString = JsonHelper.Serialize(keyboardConfig, true);
  768. }
  769. else
  770. {
  771. jsonString = JsonHelper.Serialize(inputConfig as ControllerConfig, true);
  772. }
  773. File.WriteAllText(path, jsonString);
  774. }
  775. profileDialog.Dispose();
  776. SetProfiles();
  777. }
  778. private void ProfileRemove_Activated(object sender, EventArgs args)
  779. {
  780. ((ToggleButton) sender).SetStateFlags(0, true);
  781. if (_inputDevice.ActiveId == "disabled" || _profile.ActiveId == "default" || _profile.ActiveId == null) return;
  782. MessageDialog confirmDialog = GtkDialog.CreateConfirmationDialog("Deleting Profile", "This action is irreversible, are your sure you want to continue?");
  783. if (confirmDialog.Run() == (int)ResponseType.Yes)
  784. {
  785. string path = System.IO.Path.Combine(GetProfileBasePath(), _profile.ActiveId);
  786. if (File.Exists(path))
  787. {
  788. File.Delete(path);
  789. }
  790. SetProfiles();
  791. }
  792. }
  793. private void SaveToggle_Activated(object sender, EventArgs args)
  794. {
  795. InputConfig inputConfig = GetValues();
  796. if (_inputConfig == null && inputConfig != null)
  797. {
  798. ConfigurationState.Instance.Hid.InputConfig.Value.Add(inputConfig);
  799. }
  800. else
  801. {
  802. if (_inputDevice.ActiveId == "disabled")
  803. {
  804. ConfigurationState.Instance.Hid.InputConfig.Value.Remove(_inputConfig);
  805. }
  806. else if (inputConfig != null)
  807. {
  808. int index = ConfigurationState.Instance.Hid.InputConfig.Value.IndexOf(_inputConfig);
  809. ConfigurationState.Instance.Hid.InputConfig.Value[index] = inputConfig;
  810. }
  811. }
  812. MainWindow.SaveConfig();
  813. Dispose();
  814. }
  815. private void CloseToggle_Activated(object sender, EventArgs args)
  816. {
  817. Dispose();
  818. }
  819. }
  820. }