SeedXRInputBindings.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEditor;
  4. using UnityEngine;
  5. [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("UnityEditor.XR.LegacyInputHelpers.Tests")]
  6. namespace UnityEditor.XR.LegacyInputHelpers
  7. {
  8. /// <summary>
  9. /// The SeedXRInputBindings class is used to populate the Input Asset with the cross platform bindings published by Unity for most XR Devices.
  10. /// </summary>
  11. public class SeedXRInputBindings
  12. {
  13. #region InputAxisDataAndConfig
  14. // Same as InputAxis.h
  15. internal class InputAxis
  16. {
  17. public string name = "";
  18. public string descriptiveName = "";
  19. public string descriptiveNegativeName = "";
  20. public string negativeButton = "";
  21. public string positiveButton = "";
  22. public string altNegativeButton = "";
  23. public string altPositiveButton = "";
  24. public float gravity = 0.0f;
  25. public float dead = 0.001f;
  26. public float sensitivity = 1.0f;
  27. public bool snap = false;
  28. public bool invert = false;
  29. public int type = 0;
  30. public int axis = 0;
  31. public int joyNum = 0;
  32. }
  33. //
  34. // NB: ALL AXIS VALUES WILL BE -1'd DURING PROCESSING, SO USE THE "REAL" AXIS VALUE
  35. //
  36. internal List<InputAxis> axisList = new List<InputAxis>
  37. {
  38. #region LeftHand
  39. //######################################################################################################################################
  40. // Left Hand
  41. //######################################################################################################################################
  42. // Axis Data
  43. new InputAxis()
  44. {
  45. name = "XRI_Left_Primary2DAxis_Vertical",
  46. descriptiveName = "Device joystick/touchpad horizontal motion",
  47. dead = 0.19f,
  48. axis = 2,
  49. type = 2,
  50. },
  51. new InputAxis()
  52. {
  53. name = "XRI_Left_Primary2DAxis_Horizontal",
  54. descriptiveName = "Device joystick/touchpad horizontal motion",
  55. dead = 0.19f,
  56. axis = 1,
  57. type = 2,
  58. },
  59. new InputAxis()
  60. {
  61. name = "XRI_Left_Secondary2DAxis_Vertical",
  62. descriptiveName = "Device joystick/touchpad horizontal motion.",
  63. dead = 0.19f,
  64. axis = 18,
  65. type = 2,
  66. },
  67. new InputAxis()
  68. {
  69. name = "XRI_Left_Secondary2DAxis_Horizontal",
  70. descriptiveName = "Device joystick/touchpad horizontal motion",
  71. dead = 0.19f,
  72. axis = 17,
  73. type = 2,
  74. },
  75. new InputAxis()
  76. {
  77. name = "XRI_Left_Trigger",
  78. descriptiveName = "Device trigger axis",
  79. axis = 9,
  80. type = 2,
  81. },
  82. new InputAxis()
  83. {
  84. name = "XRI_Left_Grip",
  85. descriptiveName = "Device grip axis",
  86. axis = 11,
  87. type = 2,
  88. },
  89. new InputAxis()
  90. {
  91. name = "XRI_Left_IndexTouch",
  92. descriptiveName = "Device index finger proximity touch axis.",
  93. dead = 0.19f,
  94. axis = 13,
  95. type = 2,
  96. },
  97. new InputAxis()
  98. {
  99. name = "XRI_Left_ThumbTouch",
  100. descriptiveName = "Device thumb proximity touch axis",
  101. dead = 0.19f,
  102. axis = 15,
  103. type = 2,
  104. },
  105. // Button Data
  106. new InputAxis()
  107. {
  108. name = "XRI_Left_PrimaryButton",
  109. descriptiveName = "Device primary button",
  110. positiveButton = "joystick button 2",
  111. gravity = 1000.0f,
  112. sensitivity = 1000.0f,
  113. type = 0,
  114. },
  115. new InputAxis()
  116. {
  117. name = "XRI_Left_SecondaryButton",
  118. descriptiveName = "Device secondary button",
  119. positiveButton = "joystick button 3",
  120. gravity = 1000.0f,
  121. sensitivity = 1000.0f,
  122. type = 0,
  123. },
  124. new InputAxis()
  125. {
  126. name = "XRI_Left_PrimaryTouch",
  127. descriptiveName = "Device primary touch",
  128. positiveButton = "joystick button 12",
  129. gravity = 0.0f,
  130. dead = 0.0f,
  131. sensitivity = 0.1f,
  132. type = 0,
  133. },
  134. new InputAxis()
  135. {
  136. name = "XRI_Left_SecondaryTouch",
  137. descriptiveName = "Device secondary button",
  138. positiveButton = "joystick button 13",
  139. gravity = 0.0f,
  140. dead = 0.0f,
  141. sensitivity = 0.1f,
  142. type = 0,
  143. },
  144. new InputAxis()
  145. {
  146. name = "XRI_Left_GripButton",
  147. descriptiveName = "Device grip button",
  148. positiveButton = "joystick button 4",
  149. gravity = 0.0f,
  150. dead = 0.0f,
  151. sensitivity = 0.1f,
  152. type = 0,
  153. },
  154. new InputAxis()
  155. {
  156. name = "XRI_Left_TriggerButton",
  157. descriptiveName = "Device trigger button",
  158. positiveButton = "joystick button 14",
  159. gravity = 0.0f,
  160. dead = 0.0f,
  161. sensitivity = 0.1f,
  162. type = 0,
  163. },
  164. new InputAxis()
  165. {
  166. name = "XRI_Left_MenuButton",
  167. descriptiveName = "Device menu button",
  168. positiveButton = "joystick button 6",
  169. gravity = 1000.0f,
  170. sensitivity = 1000.0f,
  171. type = 0,
  172. },
  173. new InputAxis()
  174. {
  175. name = "XRI_Left_Primary2DAxisClick",
  176. descriptiveName = "Device stick/touchpad click",
  177. positiveButton = "joystick button 8",
  178. gravity = 0.0f,
  179. dead = 0.0f,
  180. sensitivity = 0.1f,
  181. type = 0,
  182. },
  183. new InputAxis()
  184. {
  185. name = "XRI_Left_Primary2DAxisTouch",
  186. descriptiveName = "Device stick/touchpad touch",
  187. positiveButton = "joystick button 16",
  188. gravity = 0.0f,
  189. dead = 0.0f,
  190. sensitivity = 0.1f,
  191. type = 0,
  192. },
  193. new InputAxis()
  194. {
  195. name = "XRI_Left_Thumbrest",
  196. descriptiveName = "Device thumbrest",
  197. positiveButton = "joystick button 18",
  198. gravity = 0.0f,
  199. dead = 0.0f,
  200. sensitivity = 0.1f,
  201. type = 0,
  202. },
  203. #endregion
  204. #region RightHand
  205. //######################################################################################################################################
  206. // Right Hand
  207. //######################################################################################################################################
  208. new InputAxis()
  209. {
  210. name = "XRI_Right_Primary2DAxis_Vertical",
  211. descriptiveName = "Device joystick/touchpad horizontal motion",
  212. dead = 0.19f,
  213. axis = 5,
  214. type = 2,
  215. },
  216. new InputAxis()
  217. {
  218. name = "XRI_Right_Primary2DAxis_Horizontal",
  219. descriptiveName = "Device joystick/touchpad horizontal motion",
  220. dead = 0.19f,
  221. axis = 4,
  222. type = 2,
  223. },
  224. new InputAxis()
  225. {
  226. name = "XRI_Right_Secondary2DAxis_Vertical",
  227. descriptiveName = "Device joystick/touchpad horizontal motion.",
  228. dead = 0.19f,
  229. axis = 20,
  230. type = 2,
  231. },
  232. new InputAxis()
  233. {
  234. name = "XRI_Right_Secondary2DAxis_Horizontal",
  235. descriptiveName = "Device joystick/touchpad horizontal motion",
  236. dead = 0.19f,
  237. axis = 19,
  238. type = 2,
  239. },
  240. new InputAxis()
  241. {
  242. name = "XRI_Right_Trigger",
  243. descriptiveName = "Device trigger axis",
  244. axis = 10,
  245. type = 2,
  246. },
  247. new InputAxis()
  248. {
  249. name = "XRI_Right_Grip",
  250. descriptiveName = "Device grip axis",
  251. axis = 12,
  252. type = 2,
  253. },
  254. new InputAxis()
  255. {
  256. name = "XRI_Right_IndexTouch",
  257. descriptiveName = "Device index finger proximity touch axis.",
  258. dead = 0.19f,
  259. axis = 14,
  260. type = 2,
  261. },
  262. new InputAxis()
  263. {
  264. name = "XRI_Right_ThumbTouch",
  265. descriptiveName = "Device thumb proximity touch axis",
  266. dead = 0.19f,
  267. axis = 16,
  268. type = 2,
  269. },
  270. // Button Data
  271. new InputAxis()
  272. {
  273. name = "XRI_Right_PrimaryButton",
  274. descriptiveName = "Device primary button",
  275. positiveButton = "joystick button 0",
  276. gravity = 1000.0f,
  277. sensitivity = 1000.0f,
  278. type = 0,
  279. },
  280. new InputAxis()
  281. {
  282. name = "XRI_Right_SecondaryButton",
  283. descriptiveName = "Device secondary button",
  284. positiveButton = "joystick button 1",
  285. gravity = 1000.0f,
  286. sensitivity = 1000.0f,
  287. type = 0,
  288. },
  289. new InputAxis()
  290. {
  291. name = "XRI_Right_PrimaryTouch",
  292. descriptiveName = "Device primary touch",
  293. positiveButton = "joystick button 10",
  294. gravity = 0.0f,
  295. dead = 0.0f,
  296. sensitivity = 0.1f,
  297. type = 0,
  298. },
  299. new InputAxis()
  300. {
  301. name = "XRI_Right_SecondaryTouch",
  302. descriptiveName = "Device secondary button",
  303. positiveButton = "joystick button 11",
  304. gravity = 0.0f,
  305. dead = 0.0f,
  306. sensitivity = 0.1f,
  307. type = 0,
  308. },
  309. new InputAxis()
  310. {
  311. name = "XRI_Right_GripButton",
  312. descriptiveName = "Device grip button",
  313. positiveButton = "joystick button 5",
  314. gravity = 0.0f,
  315. dead = 0.0f,
  316. sensitivity = 0.1f,
  317. type = 0,
  318. },
  319. new InputAxis()
  320. {
  321. name = "XRI_Right_TriggerButton",
  322. descriptiveName = "Device trigger button",
  323. positiveButton = "joystick button 15",
  324. gravity = 0.0f,
  325. dead = 0.0f,
  326. sensitivity = 0.1f,
  327. type = 0,
  328. },
  329. new InputAxis()
  330. {
  331. name = "XRI_Right_MenuButton",
  332. descriptiveName = "Device menu button",
  333. positiveButton = "joystick button 7",
  334. gravity = 1000.0f,
  335. sensitivity = 1000.0f,
  336. type = 0,
  337. },
  338. new InputAxis()
  339. {
  340. name = "XRI_Right_Primary2DAxisClick",
  341. descriptiveName = "Device stick/touchpad click",
  342. positiveButton = "joystick button 9",
  343. gravity = 0.0f,
  344. dead = 0.0f,
  345. sensitivity = 0.1f,
  346. type = 0,
  347. },
  348. new InputAxis()
  349. {
  350. name = "XRI_Right_Primary2DAxisTouch",
  351. descriptiveName = "Device stick/touchpad touch",
  352. positiveButton = "joystick button 17",
  353. gravity = 0.0f,
  354. dead = 0.0f,
  355. sensitivity = 0.1f,
  356. type = 0,
  357. },
  358. new InputAxis()
  359. {
  360. name = "XRI_Right_Thumbrest",
  361. descriptiveName = "Device thumbrest",
  362. positiveButton = "joystick button 19",
  363. gravity = 0.0f,
  364. dead = 0.0f,
  365. sensitivity = 0.1f,
  366. type = 0,
  367. },
  368. #endregion
  369. #region UGuiRequired
  370. //######################################################################################################################################
  371. // UGui Required
  372. //######################################################################################################################################
  373. new InputAxis()
  374. {
  375. name = "Submit",
  376. descriptiveName = "Submit",
  377. positiveButton = "joystick button 0",
  378. gravity = 0.0f,
  379. dead = 0.0f,
  380. sensitivity = 0.1f,
  381. type = 0,
  382. },
  383. new InputAxis()
  384. {
  385. name = "Cancel",
  386. descriptiveName = "Cancel",
  387. positiveButton = "joystick button 1",
  388. gravity = 0.0f,
  389. dead = 0.0f,
  390. sensitivity = 0.1f,
  391. type = 0,
  392. },
  393. new InputAxis()
  394. {
  395. name = "Horizontal",
  396. descriptiveName = "Horizontal",
  397. dead = 0.19f,
  398. axis = 4,
  399. type = 2,
  400. },
  401. new InputAxis()
  402. {
  403. name = "Vertical",
  404. descriptiveName = "Vertical",
  405. dead = 0.19f,
  406. axis = 5,
  407. type = 2,
  408. },
  409. #endregion
  410. //######################################################################################################################################
  411. // Combined Trigger
  412. //######################################################################################################################################
  413. #region Combined
  414. new InputAxis()
  415. {
  416. name = "XRI_Combined_Trigger",
  417. descriptiveName = "Combined Trigger",
  418. dead = 0.19f,
  419. axis = 3,
  420. type = 2,
  421. },
  422. new InputAxis()
  423. {
  424. name = "XRI_DPad_Vertical",
  425. descriptiveName = "Device directional pad. These values are replicated l/r",
  426. axis = 7,
  427. type = 2,
  428. },
  429. new InputAxis()
  430. {
  431. name = "XRI_DPad_Horizontal",
  432. descriptiveName = "Device directional pad. These values are replicated l/r",
  433. axis = 6,
  434. type = 2,
  435. },
  436. #endregion
  437. };
  438. internal struct BindingData
  439. {
  440. public int newDataIndex;
  441. public int inputManagerIndex;
  442. public bool exists;
  443. }
  444. #endregion
  445. ///<summary>
  446. /// Menu option which will allow users to seed the automatic bindings for the legacy input system.
  447. ///</summary>
  448. [MenuItem("Assets/Seed XR Input Bindings")]
  449. static public void GenerateXRBindingsMenuItem()
  450. {
  451. SeedXRInputBindings sxrib = new SeedXRInputBindings();
  452. sxrib.GenerateXRBindings();
  453. SettingsService.OpenProjectSettings("Project/Input");
  454. }
  455. /// <summary>
  456. /// Main entrypoint for generating the XR Bindings and adding them to the Input Asset. The Custom uGUI editor calls this function when the user wishes to
  457. /// seed the Input Asset with XR bindings.
  458. /// </summary>
  459. public void GenerateXRBindings()
  460. {
  461. // seed map of axis data so we can whitewash against existing.
  462. Dictionary<string, BindingData> axisMap = new Dictionary<string, BindingData>();
  463. for (int i = 0; i < axisList.Count; ++i)
  464. {
  465. axisMap.Add(axisList[i].name, new BindingData() { newDataIndex = i, exists = false, inputManagerIndex = -1 });
  466. if (axisList[i].axis > 0)
  467. {
  468. axisList[i].axis--;
  469. }
  470. }
  471. // load the input asset
  472. var inputManagerAsset = AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/InputManager.asset")[0];
  473. if (inputManagerAsset != null)
  474. {
  475. var serializedObject = new SerializedObject(inputManagerAsset);
  476. var inputManagerCurrentData = serializedObject.FindProperty("m_Axes");
  477. if (inputManagerCurrentData != null)
  478. {
  479. List<InputAxis> currentInputData = new List<InputAxis>();
  480. LoadExistingDataAndCheckAgainstNewData(inputManagerCurrentData, ref axisMap, ref currentInputData);
  481. serializedObject.ApplyModifiedProperties();
  482. ApplyDataToInputManager(currentInputData, axisList, axisMap, ref inputManagerCurrentData);
  483. serializedObject.ApplyModifiedProperties();
  484. AssetDatabase.Refresh();
  485. }
  486. }
  487. }
  488. #region InternalProcessingCode
  489. internal void ApplyDataToInputManager(List<InputAxis> inputManagerData, List<InputAxis> newData, Dictionary<string, BindingData> newDataMap, ref SerializedProperty arrayRoot)
  490. {
  491. // likely will be larger than we need, but that's ok. it'll be big enough for all the data which is worst case
  492. arrayRoot.arraySize = inputManagerData.Count + newData.Count;
  493. int arrayIndex = inputManagerData.Count;
  494. // write everything that doesn't clash from our new data
  495. for (int i = 0; i < newData.Count; ++i)
  496. {
  497. BindingData bindingData;
  498. if (newDataMap.TryGetValue(newData[i].name, out bindingData))
  499. {
  500. if (bindingData.exists == true)
  501. {
  502. continue;
  503. }
  504. }
  505. var axisEntry = arrayRoot.GetArrayElementAtIndex(arrayIndex);
  506. WriteDataToInputAxis(newData[i], ref axisEntry);
  507. arrayIndex++;
  508. }
  509. arrayRoot.arraySize = arrayIndex;
  510. }
  511. internal void WriteDataToInputAxis(InputAxis sourceData, ref SerializedProperty serializedProperty)
  512. {
  513. var iteratorProperty = serializedProperty.Copy();
  514. iteratorProperty.Next(true);
  515. do
  516. {
  517. switch (iteratorProperty.name)
  518. {
  519. case "m_Name":
  520. iteratorProperty.stringValue = sourceData.name;
  521. break;
  522. case "descriptiveName":
  523. iteratorProperty.stringValue = sourceData.descriptiveName;
  524. break;
  525. case "descriptiveNegativeName":
  526. iteratorProperty.stringValue = sourceData.descriptiveNegativeName;
  527. break;
  528. case "negativeButton":
  529. iteratorProperty.stringValue = sourceData.negativeButton;
  530. break;
  531. case "positiveButton":
  532. iteratorProperty.stringValue = sourceData.positiveButton;
  533. break;
  534. case "altNegativeButton":
  535. iteratorProperty.stringValue = sourceData.altNegativeButton;
  536. break;
  537. case "altPositiveButton":
  538. iteratorProperty.stringValue = sourceData.altPositiveButton;
  539. break;
  540. case "gravity":
  541. iteratorProperty.floatValue = sourceData.gravity;
  542. break;
  543. case "dead":
  544. iteratorProperty.floatValue = sourceData.dead;
  545. break;
  546. case "sensitivity":
  547. iteratorProperty.floatValue = sourceData.sensitivity;
  548. break;
  549. case "snap":
  550. iteratorProperty.boolValue = sourceData.snap;
  551. break;
  552. case "invert":
  553. iteratorProperty.boolValue = sourceData.invert;
  554. break;
  555. case "type":
  556. iteratorProperty.intValue = sourceData.type;
  557. break;
  558. case "axis":
  559. iteratorProperty.intValue = sourceData.axis;
  560. break;
  561. case "joyNum":
  562. iteratorProperty.intValue = sourceData.joyNum;
  563. break;
  564. }
  565. } while (iteratorProperty.Next(false));
  566. }
  567. internal void LoadExistingDataAndCheckAgainstNewData(SerializedProperty arrayRoot, ref Dictionary<string, BindingData> newDataMap, ref List<InputAxis> existingData)
  568. {
  569. existingData.Clear();
  570. for (int i = 0; i < arrayRoot.arraySize; ++i)
  571. {
  572. InputAxis readData = new InputAxis();
  573. var axisEntry = arrayRoot.GetArrayElementAtIndex(i);
  574. var iteratorProperty = axisEntry.Copy();
  575. iteratorProperty.Next(true);
  576. do
  577. {
  578. switch (iteratorProperty.name)
  579. {
  580. case "m_Name":
  581. readData.name = iteratorProperty.stringValue;
  582. BindingData bindingData;
  583. if (newDataMap.TryGetValue(readData.name, out bindingData))
  584. {
  585. // using TryGetElement returns a copy, not very useful.
  586. bindingData.exists = true;
  587. bindingData.inputManagerIndex = i;
  588. newDataMap[readData.name] = bindingData;
  589. }
  590. break;
  591. case "descriptiveName":
  592. readData.descriptiveName = iteratorProperty.stringValue;
  593. break;
  594. case "descriptiveNegativeName":
  595. readData.descriptiveNegativeName = iteratorProperty.stringValue;
  596. break;
  597. case "negativeButton":
  598. readData.negativeButton = iteratorProperty.stringValue;
  599. break;
  600. case "positiveButton":
  601. readData.positiveButton = iteratorProperty.stringValue;
  602. break;
  603. case "altNegativeButton":
  604. readData.altNegativeButton = iteratorProperty.stringValue;
  605. break;
  606. case "altPositiveButton":
  607. readData.altPositiveButton = iteratorProperty.stringValue;
  608. break;
  609. case "gravity":
  610. readData.gravity = iteratorProperty.floatValue;
  611. break;
  612. case "dead":
  613. readData.dead = iteratorProperty.floatValue;
  614. break;
  615. case "sensitivity":
  616. readData.sensitivity = iteratorProperty.floatValue;
  617. break;
  618. case "snap":
  619. readData.snap = iteratorProperty.boolValue;
  620. break;
  621. case "invert":
  622. readData.invert = iteratorProperty.boolValue;
  623. break;
  624. case "type":
  625. readData.type = iteratorProperty.intValue;
  626. break;
  627. case "axis":
  628. readData.axis = iteratorProperty.intValue;
  629. break;
  630. case "joyNum":
  631. readData.joyNum = iteratorProperty.intValue;
  632. break;
  633. }
  634. } while (iteratorProperty.Next(false));
  635. existingData.Add(readData);
  636. }
  637. }
  638. #endregion
  639. }
  640. }