Brak opisu
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

InputRemoting.cs 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791
  1. using System;
  2. using System.Linq;
  3. using System.Text;
  4. using Unity.Collections.LowLevel.Unsafe;
  5. using UnityEngine.InputSystem.Layouts;
  6. using UnityEngine.InputSystem.LowLevel;
  7. using UnityEngine.InputSystem.Utilities;
  8. ////TODO: show remote device IDs in the debugger
  9. ////TODO: remote timestamps need to be translated to local timestamps; doesn't make sense for remote events getting
  10. //// processed on the local timeline as is when the originating timeline may be quite different
  11. ////TODO: support actions
  12. ////TODO: support input users
  13. ////TODO: text input events
  14. ////TODO: support remoting of device commands
  15. ////TODO: Reuse memory allocated for messages instead of allocating separately for each message.
  16. ////REVIEW: it seems that the various XXXMsg struct should be public; ATM doesn't seem like working with the message interface is practical
  17. ////REVIEW: the namespacing mechanism for layouts which changes base layouts means that layouts can't be played
  18. //// around with on the editor side but will only be changed once they're updated in the player
  19. namespace UnityEngine.InputSystem
  20. {
  21. /// <summary>
  22. /// Makes the activity and data of an InputManager observable in message form.
  23. /// </summary>
  24. /// <remarks>
  25. /// Can act as both the sender and receiver of these message so the flow is fully bidirectional,
  26. /// i.e. the InputManager on either end can mirror its layouts, devices, and events over
  27. /// to the other end. This permits streaming input not just from the player to the editor but
  28. /// also feeding input from the editor back into the player.
  29. ///
  30. /// Remoting sits entirely on top of the input system as an optional piece of functionality.
  31. /// In development players and the editor, we enable it automatically but in non-development
  32. /// players it has to be explicitly requested by the user.
  33. ///
  34. /// To see devices and input from players in the editor, open the Input Debugger through
  35. /// "Windows >> Input Debugger".
  36. /// </remarks>
  37. /// <seealso cref="InputSystem.remoting"/>
  38. public sealed class InputRemoting : IObservable<InputRemoting.Message>, IObserver<InputRemoting.Message>
  39. {
  40. /// <summary>
  41. /// Enumeration of possible types of messages exchanged between two InputRemoting instances.
  42. /// </summary>
  43. public enum MessageType
  44. {
  45. Connect,
  46. Disconnect,
  47. NewLayout,
  48. NewDevice,
  49. NewEvents,
  50. RemoveDevice,
  51. RemoveLayout, // Not used ATM.
  52. ChangeUsages,
  53. StartSending,
  54. StopSending,
  55. }
  56. /// <summary>
  57. /// A message exchanged between two InputRemoting instances.
  58. /// </summary>
  59. public struct Message
  60. {
  61. /// <summary>
  62. /// For messages coming in, numeric ID of the sender of the message. For messages
  63. /// going out, numeric ID of the targeted receiver of the message.
  64. /// </summary>
  65. public int participantId;
  66. public MessageType type;
  67. public byte[] data;
  68. }
  69. public bool sending
  70. {
  71. get => (m_Flags & Flags.Sending) == Flags.Sending;
  72. private set
  73. {
  74. if (value)
  75. m_Flags |= Flags.Sending;
  76. else
  77. m_Flags &= ~Flags.Sending;
  78. }
  79. }
  80. internal InputRemoting(InputManager manager, bool startSendingOnConnect = false)
  81. {
  82. if (manager == null)
  83. throw new ArgumentNullException(nameof(manager));
  84. m_LocalManager = manager;
  85. if (startSendingOnConnect)
  86. m_Flags |= Flags.StartSendingOnConnect;
  87. //when listening for newly added layouts, must filter out ones we've added from remote
  88. }
  89. /// <summary>
  90. /// Start sending messages for data and activity in the local input system
  91. /// to observers.
  92. /// </summary>
  93. /// <seealso cref="sending"/>
  94. /// <seealso cref="StopSending"/>
  95. public void StartSending()
  96. {
  97. if (sending)
  98. return;
  99. ////TODO: send events in bulk rather than one-by-one
  100. m_LocalManager.onEvent += SendEvent;
  101. m_LocalManager.onDeviceChange += SendDeviceChange;
  102. m_LocalManager.onLayoutChange += SendLayoutChange;
  103. sending = true;
  104. SendInitialMessages();
  105. }
  106. public void StopSending()
  107. {
  108. if (!sending)
  109. return;
  110. m_LocalManager.onEvent -= SendEvent;
  111. m_LocalManager.onDeviceChange -= SendDeviceChange;
  112. m_LocalManager.onLayoutChange -= SendLayoutChange;
  113. sending = false;
  114. }
  115. void IObserver<Message>.OnNext(Message msg)
  116. {
  117. switch (msg.type)
  118. {
  119. case MessageType.Connect:
  120. ConnectMsg.Process(this);
  121. break;
  122. case MessageType.Disconnect:
  123. DisconnectMsg.Process(this, msg);
  124. break;
  125. case MessageType.NewLayout:
  126. NewLayoutMsg.Process(this, msg);
  127. break;
  128. case MessageType.NewDevice:
  129. NewDeviceMsg.Process(this, msg);
  130. break;
  131. case MessageType.NewEvents:
  132. NewEventsMsg.Process(this, msg);
  133. break;
  134. case MessageType.ChangeUsages:
  135. ChangeUsageMsg.Process(this, msg);
  136. break;
  137. case MessageType.RemoveDevice:
  138. RemoveDeviceMsg.Process(this, msg);
  139. break;
  140. case MessageType.StartSending:
  141. StartSendingMsg.Process(this);
  142. break;
  143. case MessageType.StopSending:
  144. StopSendingMsg.Process(this);
  145. break;
  146. }
  147. }
  148. void IObserver<Message>.OnError(Exception error)
  149. {
  150. }
  151. void IObserver<Message>.OnCompleted()
  152. {
  153. }
  154. public IDisposable Subscribe(IObserver<Message> observer)
  155. {
  156. if (observer == null)
  157. throw new ArgumentNullException(nameof(observer));
  158. var subscriber = new Subscriber {owner = this, observer = observer};
  159. ArrayHelpers.Append(ref m_Subscribers, subscriber);
  160. return subscriber;
  161. }
  162. private void SendInitialMessages()
  163. {
  164. SendAllGeneratedLayouts();
  165. SendAllDevices();
  166. }
  167. private void SendAllGeneratedLayouts()
  168. {
  169. foreach (var entry in m_LocalManager.m_Layouts.layoutBuilders)
  170. SendLayout(entry.Key);
  171. }
  172. private void SendLayout(string layoutName)
  173. {
  174. if (m_Subscribers == null)
  175. return;
  176. var message = NewLayoutMsg.Create(this, layoutName);
  177. if (message != null)
  178. Send(message.Value);
  179. }
  180. private void SendAllDevices()
  181. {
  182. var devices = m_LocalManager.devices;
  183. foreach (var device in devices)
  184. SendDevice(device);
  185. }
  186. private void SendDevice(InputDevice device)
  187. {
  188. if (m_Subscribers == null)
  189. return;
  190. // Don't mirror remote devices to other remotes.
  191. if (device.remote)
  192. return;
  193. var newDeviceMessage = NewDeviceMsg.Create(device);
  194. Send(newDeviceMessage);
  195. // Send current state. We do this here in this case as the device
  196. // may have been added some time ago and thus have already received events.
  197. var stateEventMessage = NewEventsMsg.CreateStateEvent(device);
  198. Send(stateEventMessage);
  199. }
  200. private unsafe void SendEvent(InputEventPtr eventPtr, InputDevice device)
  201. {
  202. if (m_Subscribers == null)
  203. return;
  204. ////REVIEW: we probably want to have better control over this and allow producing local events
  205. //// against remote devices which *are* indeed sent across the wire
  206. // Don't send events that came in from remote devices.
  207. if (device != null && device.remote)
  208. return;
  209. var message = NewEventsMsg.Create(eventPtr.data, 1);
  210. Send(message);
  211. }
  212. private void SendDeviceChange(InputDevice device, InputDeviceChange change)
  213. {
  214. if (m_Subscribers == null)
  215. return;
  216. // Don't mirror remote devices to other remotes.
  217. if (device.remote)
  218. return;
  219. Message msg;
  220. switch (change)
  221. {
  222. case InputDeviceChange.Added:
  223. msg = NewDeviceMsg.Create(device);
  224. break;
  225. case InputDeviceChange.Removed:
  226. msg = RemoveDeviceMsg.Create(device);
  227. break;
  228. case InputDeviceChange.UsageChanged:
  229. msg = ChangeUsageMsg.Create(device);
  230. break;
  231. ////FIXME: This creates a double reset event in case the reset itself happens from a reset event that we are also remoting at the same time.
  232. case InputDeviceChange.SoftReset:
  233. msg = NewEventsMsg.CreateResetEvent(device, false);
  234. break;
  235. case InputDeviceChange.HardReset:
  236. msg = NewEventsMsg.CreateResetEvent(device, true);
  237. break;
  238. default:
  239. return;
  240. }
  241. Send(msg);
  242. }
  243. private void SendLayoutChange(string layout, InputControlLayoutChange change)
  244. {
  245. if (m_Subscribers == null)
  246. return;
  247. // Ignore changes made to layouts that aren't generated. We don't send those over
  248. // the wire.
  249. if (!m_LocalManager.m_Layouts.IsGeneratedLayout(new InternedString(layout)))
  250. return;
  251. // We're only interested in new generated layouts popping up or existing ones
  252. // getting replaced.
  253. if (change != InputControlLayoutChange.Added && change != InputControlLayoutChange.Replaced)
  254. return;
  255. var message = NewLayoutMsg.Create(this, layout);
  256. if (message != null)
  257. Send(message.Value);
  258. }
  259. private void Send(Message msg)
  260. {
  261. foreach (var subscriber in m_Subscribers)
  262. subscriber.observer.OnNext(msg);
  263. }
  264. private int FindOrCreateSenderRecord(int senderId)
  265. {
  266. // Try to find existing.
  267. if (m_Senders != null)
  268. {
  269. var senderCount = m_Senders.Length;
  270. for (var i = 0; i < senderCount; ++i)
  271. if (m_Senders[i].senderId == senderId)
  272. return i;
  273. }
  274. // Create new.
  275. var sender = new RemoteSender
  276. {
  277. senderId = senderId,
  278. };
  279. return ArrayHelpers.Append(ref m_Senders, sender);
  280. }
  281. private static InternedString BuildLayoutNamespace(int senderId)
  282. {
  283. return new InternedString($"Remote::{senderId}");
  284. }
  285. private int FindLocalDeviceId(int remoteDeviceId, int senderIndex)
  286. {
  287. var localDevices = m_Senders[senderIndex].devices;
  288. if (localDevices != null)
  289. {
  290. var numLocalDevices = localDevices.Length;
  291. for (var i = 0; i < numLocalDevices; ++i)
  292. {
  293. if (localDevices[i].remoteId == remoteDeviceId)
  294. return localDevices[i].localId;
  295. }
  296. }
  297. return InputDevice.InvalidDeviceId;
  298. }
  299. private InputDevice TryGetDeviceByRemoteId(int remoteDeviceId, int senderIndex)
  300. {
  301. var localId = FindLocalDeviceId(remoteDeviceId, senderIndex);
  302. return m_LocalManager.TryGetDeviceById(localId);
  303. }
  304. internal InputManager manager => m_LocalManager;
  305. private Flags m_Flags;
  306. private InputManager m_LocalManager; // Input system we mirror input from and to.
  307. private Subscriber[] m_Subscribers; // Receivers we send input to.
  308. private RemoteSender[] m_Senders; // Senders we receive input from.
  309. [Flags]
  310. private enum Flags
  311. {
  312. Sending = 1 << 0,
  313. StartSendingOnConnect = 1 << 1
  314. }
  315. // Data we keep about a unique sender that we receive input data
  316. // from. We keep track of the layouts and devices we added to
  317. // the local system.
  318. [Serializable]
  319. internal struct RemoteSender
  320. {
  321. public int senderId;
  322. public InternedString[] layouts; // Each item is the unqualified name of the layout (without namespace)
  323. public RemoteInputDevice[] devices;
  324. }
  325. [Serializable]
  326. internal struct RemoteInputDevice
  327. {
  328. public int remoteId; // Device ID used by sender.
  329. public int localId; // Device ID used by us in local system.
  330. public InputDeviceDescription description;
  331. }
  332. internal class Subscriber : IDisposable
  333. {
  334. public InputRemoting owner;
  335. public IObserver<Message> observer;
  336. public void Dispose()
  337. {
  338. ArrayHelpers.Erase(ref owner.m_Subscribers, this);
  339. }
  340. }
  341. private static class ConnectMsg
  342. {
  343. public static void Process(InputRemoting receiver)
  344. {
  345. if (receiver.sending)
  346. receiver.SendInitialMessages();
  347. else if ((receiver.m_Flags & Flags.StartSendingOnConnect) == Flags.StartSendingOnConnect)
  348. receiver.StartSending();
  349. }
  350. }
  351. private static class StartSendingMsg
  352. {
  353. public static void Process(InputRemoting receiver)
  354. {
  355. receiver.StartSending();
  356. }
  357. }
  358. private static class StopSendingMsg
  359. {
  360. public static void Process(InputRemoting receiver)
  361. {
  362. receiver.StopSending();
  363. }
  364. }
  365. public void RemoveRemoteDevices(int participantId)
  366. {
  367. var senderIndex = FindOrCreateSenderRecord(participantId);
  368. // Remove devices added by remote.
  369. var devices = m_Senders[senderIndex].devices;
  370. if (devices != null)
  371. {
  372. foreach (var remoteDevice in devices)
  373. {
  374. var device = m_LocalManager.TryGetDeviceById(remoteDevice.localId);
  375. if (device != null)
  376. m_LocalManager.RemoveDevice(device);
  377. }
  378. }
  379. ArrayHelpers.EraseAt(ref m_Senders, senderIndex);
  380. }
  381. private static class DisconnectMsg
  382. {
  383. public static void Process(InputRemoting receiver, Message msg)
  384. {
  385. Debug.Log("DisconnectMsg.Process");
  386. receiver.RemoveRemoteDevices(msg.participantId);
  387. receiver.StopSending();
  388. }
  389. }
  390. // Tell remote input system that there's a new layout.
  391. private static class NewLayoutMsg
  392. {
  393. [Serializable]
  394. public struct Data
  395. {
  396. public string name;
  397. public string layoutJson;
  398. public bool isOverride;
  399. }
  400. public static Message? Create(InputRemoting sender, string layoutName)
  401. {
  402. // Try to load the layout. Ignore the layout if it couldn't
  403. // be loaded.
  404. InputControlLayout layout;
  405. try
  406. {
  407. layout = sender.m_LocalManager.TryLoadControlLayout(new InternedString(layoutName));
  408. if (layout == null)
  409. {
  410. Debug.Log(string.Format(
  411. "Could not find layout '{0}' meant to be sent through remote connection; this should not happen",
  412. layoutName));
  413. return null;
  414. }
  415. }
  416. catch (Exception exception)
  417. {
  418. Debug.Log($"Could not load layout '{layoutName}'; not sending to remote listeners (exception: {exception})");
  419. return null;
  420. }
  421. var data = new Data
  422. {
  423. name = layoutName,
  424. layoutJson = layout.ToJson(),
  425. isOverride = layout.isOverride
  426. };
  427. return new Message
  428. {
  429. type = MessageType.NewLayout,
  430. data = SerializeData(data)
  431. };
  432. }
  433. public static void Process(InputRemoting receiver, Message msg)
  434. {
  435. var data = DeserializeData<Data>(msg.data);
  436. var senderIndex = receiver.FindOrCreateSenderRecord(msg.participantId);
  437. var internedLayoutName = new InternedString(data.name);
  438. receiver.m_LocalManager.RegisterControlLayout(data.layoutJson, data.name, data.isOverride);
  439. ArrayHelpers.Append(ref receiver.m_Senders[senderIndex].layouts, internedLayoutName);
  440. }
  441. }
  442. // Tell remote input system that there's a new device.
  443. private static class NewDeviceMsg
  444. {
  445. [Serializable]
  446. public struct Data
  447. {
  448. public string name;
  449. public string layout;
  450. public int deviceId;
  451. public string[] usages;
  452. public InputDeviceDescription description;
  453. }
  454. public static Message Create(InputDevice device)
  455. {
  456. Debug.Assert(!device.remote, "Device being sent to remotes should be a local device, not a remote one");
  457. var data = new Data
  458. {
  459. name = device.name,
  460. layout = device.layout,
  461. deviceId = device.deviceId,
  462. description = device.description,
  463. usages = device.usages.Select(x => x.ToString()).ToArray()
  464. };
  465. return new Message
  466. {
  467. type = MessageType.NewDevice,
  468. data = SerializeData(data)
  469. };
  470. }
  471. public static void Process(InputRemoting receiver, Message msg)
  472. {
  473. var senderIndex = receiver.FindOrCreateSenderRecord(msg.participantId);
  474. var data = DeserializeData<Data>(msg.data);
  475. // Make sure we haven't already seen the device.
  476. var devices = receiver.m_Senders[senderIndex].devices;
  477. if (devices != null)
  478. {
  479. foreach (var entry in devices)
  480. if (entry.remoteId == data.deviceId)
  481. {
  482. Debug.LogError(string.Format(
  483. "Already received device with id {0} (layout '{1}', description '{3}) from remote {2}",
  484. data.deviceId,
  485. data.layout, msg.participantId, data.description));
  486. return;
  487. }
  488. }
  489. // Create device.
  490. InputDevice device;
  491. try
  492. {
  493. ////REVIEW: this gives remote devices names the same way that local devices receive them; should we make remote status visible in the name?
  494. var internedLayoutName = new InternedString(data.layout);
  495. device = receiver.m_LocalManager.AddDevice(internedLayoutName, data.name);
  496. device.m_ParticipantId = msg.participantId;
  497. }
  498. catch (Exception exception)
  499. {
  500. Debug.LogError(
  501. $"Could not create remote device '{data.description}' with layout '{data.layout}' locally (exception: {exception})");
  502. return;
  503. }
  504. ////FIXME: Setting this here like so means none of this is visible during onDeviceChange
  505. device.m_Description = data.description;
  506. device.m_DeviceFlags |= InputDevice.DeviceFlags.Remote;
  507. foreach (var usage in data.usages)
  508. receiver.m_LocalManager.AddDeviceUsage(device, new InternedString(usage));
  509. // Remember it.
  510. var record = new RemoteInputDevice
  511. {
  512. remoteId = data.deviceId,
  513. localId = device.deviceId,
  514. description = data.description,
  515. };
  516. ArrayHelpers.Append(ref receiver.m_Senders[senderIndex].devices, record);
  517. }
  518. }
  519. // Tell remote system there's new input events.
  520. private static class NewEventsMsg
  521. {
  522. public static unsafe Message CreateResetEvent(InputDevice device, bool isHardReset)
  523. {
  524. var resetEvent = DeviceResetEvent.Create(device.deviceId, isHardReset);
  525. return Create((InputEvent*)UnsafeUtility.AddressOf(ref resetEvent), 1);
  526. }
  527. public static unsafe Message CreateStateEvent(InputDevice device)
  528. {
  529. using (StateEvent.From(device, out var eventPtr))
  530. return Create(eventPtr.data, 1);
  531. }
  532. public static unsafe Message Create(InputEvent* events, int eventCount)
  533. {
  534. // Find total size of event buffer we need.
  535. var totalSize = 0u;
  536. var eventPtr = new InputEventPtr(events);
  537. for (var i = 0; i < eventCount; ++i, eventPtr = eventPtr.Next())
  538. totalSize = totalSize.AlignToMultipleOf(4) + eventPtr.sizeInBytes;
  539. // Copy event data to buffer. Would be nice if we didn't have to do that
  540. // but unfortunately we need a byte[] and can't just pass the 'events' IntPtr
  541. // directly.
  542. var data = new byte[totalSize];
  543. fixed(byte* dataPtr = data)
  544. {
  545. UnsafeUtility.MemCpy(dataPtr, events, totalSize);
  546. }
  547. // Done.
  548. return new Message
  549. {
  550. type = MessageType.NewEvents,
  551. data = data
  552. };
  553. }
  554. public static unsafe void Process(InputRemoting receiver, Message msg)
  555. {
  556. var manager = receiver.m_LocalManager;
  557. fixed(byte* dataPtr = msg.data)
  558. {
  559. var dataEndPtr = new IntPtr(dataPtr + msg.data.Length);
  560. var eventCount = 0;
  561. var eventPtr = new InputEventPtr((InputEvent*)dataPtr);
  562. var senderIndex = receiver.FindOrCreateSenderRecord(msg.participantId);
  563. // Don't use IntPtr.ToInt64() function, on 32 bit systems, the pointer is first converted to Int32 and then casted to Int64
  564. // Thus for big pointer value, you might get a negative value even though the pointer value will be less than Int64.MaxValue
  565. while ((void*)eventPtr.data < dataEndPtr.ToPointer())
  566. {
  567. // Patch up device ID to refer to local device and send event.
  568. var remoteDeviceId = eventPtr.deviceId;
  569. var localDeviceId = receiver.FindLocalDeviceId(remoteDeviceId, senderIndex);
  570. eventPtr.deviceId = localDeviceId;
  571. if (localDeviceId != InputDevice.InvalidDeviceId)
  572. {
  573. ////TODO: add API to send events in bulk rather than one by one
  574. manager.QueueEvent(eventPtr);
  575. }
  576. ++eventCount;
  577. eventPtr = eventPtr.Next();
  578. }
  579. }
  580. }
  581. }
  582. private static class ChangeUsageMsg
  583. {
  584. [Serializable]
  585. public struct Data
  586. {
  587. public int deviceId;
  588. public string[] usages;
  589. }
  590. public static Message Create(InputDevice device)
  591. {
  592. var data = new Data
  593. {
  594. deviceId = device.deviceId,
  595. usages = device.usages.Select(x => x.ToString()).ToArray()
  596. };
  597. return new Message
  598. {
  599. type = MessageType.ChangeUsages,
  600. data = SerializeData(data)
  601. };
  602. }
  603. public static void Process(InputRemoting receiver, Message msg)
  604. {
  605. var senderIndex = receiver.FindOrCreateSenderRecord(msg.participantId);
  606. var data = DeserializeData<Data>(msg.data);
  607. var device = receiver.TryGetDeviceByRemoteId(data.deviceId, senderIndex);
  608. if (device != null)
  609. {
  610. foreach (var deviceUsage in device.usages)
  611. {
  612. if (!data.usages.Contains(deviceUsage))
  613. receiver.m_LocalManager.RemoveDeviceUsage(device, new InternedString(deviceUsage));
  614. }
  615. foreach (var dataUsage in data.usages)
  616. {
  617. var internedDataUsage = new InternedString(dataUsage);
  618. if (!device.usages.Contains(internedDataUsage))
  619. receiver.m_LocalManager.AddDeviceUsage(device, new InternedString(dataUsage));
  620. }
  621. }
  622. }
  623. }
  624. private static class RemoveDeviceMsg
  625. {
  626. public static Message Create(InputDevice device)
  627. {
  628. return new Message
  629. {
  630. type = MessageType.RemoveDevice,
  631. data = BitConverter.GetBytes(device.deviceId)
  632. };
  633. }
  634. public static void Process(InputRemoting receiver, Message msg)
  635. {
  636. var senderIndex = receiver.FindOrCreateSenderRecord(msg.participantId);
  637. var remoteDeviceId = BitConverter.ToInt32(msg.data, 0);
  638. var device = receiver.TryGetDeviceByRemoteId(remoteDeviceId, senderIndex);
  639. if (device != null)
  640. receiver.m_LocalManager.RemoveDevice(device);
  641. }
  642. }
  643. private static byte[] SerializeData<TData>(TData data)
  644. {
  645. var json = JsonUtility.ToJson(data);
  646. return Encoding.UTF8.GetBytes(json);
  647. }
  648. private static TData DeserializeData<TData>(byte[] data)
  649. {
  650. var json = Encoding.UTF8.GetString(data);
  651. return JsonUtility.FromJson<TData>(json);
  652. }
  653. #if UNITY_EDITOR || DEVELOPMENT_BUILD
  654. // State we want to take across domain reloads. We can only take some of the
  655. // state across. Subscriptions will be lost and have to be manually restored.
  656. [Serializable]
  657. internal struct SerializedState
  658. {
  659. public int senderId;
  660. public RemoteSender[] senders;
  661. // We can't take these across domain reloads but we want to take them across
  662. // InputSystem.Save/Restore.
  663. [NonSerialized] public Subscriber[] subscribers;
  664. }
  665. internal SerializedState SaveState()
  666. {
  667. return new SerializedState
  668. {
  669. senders = m_Senders,
  670. subscribers = m_Subscribers
  671. };
  672. }
  673. internal void RestoreState(SerializedState state, InputManager manager)
  674. {
  675. m_LocalManager = manager;
  676. m_Senders = state.senders;
  677. }
  678. #endif
  679. }
  680. }