using System; using System.Collections.Generic; using System.Linq; using Unity.WebRTC; using Unity.Collections.LowLevel.Unsafe; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.LowLevel; using UnityEngine.InputSystem.Utilities; namespace Unity.RenderStreaming.InputSystem { using InputSystem = UnityEngine.InputSystem.InputSystem; /// /// /// class Receiver : InputManager, IDisposable { public override event Action onMessage; public new event Action onDeviceChange; public new event Action onLayoutChange; private RTCDataChannel _channel; private readonly List _remoteDevices = new List(); private readonly Dictionary _remoteLayouts = new Dictionary(); private readonly List _registeredRemoteLayout = new List(); private InputPositionCorrector _corrector; private Action _onEvent; /// /// /// public bool EnableInputPositionCorrection { set; get; } /// /// /// /// public Receiver(RTCDataChannel channel) { _channel = channel ?? throw new ArgumentNullException("channel is null"); _channel.OnMessage += OnMessage; _onEvent = (InputEventPtr ptr, InputDevice device) => { base.QueueEvent(ptr); }; _corrector = new InputPositionCorrector(_onEvent); } ~Receiver() { this.Dispose(); } public void Dispose() { RemoveAllRemoteDevices(); RemoveAllRemoteLayouts(); } private void OnMessage(byte[] bytes) { MessageSerializer.Deserialize(bytes, out var message); onMessage?.Invoke(message); } /// /// /// public override ReadOnlyArray devices { get { // note:: InputRemoting class rejects remote devices when sending device information to the remote peer. // Avoid to get assert "Device being sent to remotes should be a local device, not a remote one" return new ReadOnlyArray(); } } /// /// /// public override IEnumerable layouts { get { return Enumerable.Empty(); } } /// /// /// public ReadOnlyArray remoteDevices { get { return new ReadOnlyArray(_remoteDevices.ToArray()); } } public ReadOnlyArray remoteLayouts { get { return new ReadOnlyArray(_remoteLayouts.Keys.ToArray()); } } /// /// /// public void RemoveAllRemoteDevices() { while (_remoteDevices.Count > 0) { RemoveDevice(_remoteDevices[0]); } } public void RemoveAllRemoteLayouts() { while (_remoteLayouts.Count > 0) { RemoveLayout(_remoteLayouts.First().Key); } } public override InputDevice AddDevice(string layout, string name = null, string variants = null) { if (InputSystem.ListLayouts().Count(_ => _ == layout) == 0) { if (!_remoteLayouts.TryGetValue(layout, out string json)) throw new InvalidOperationException(); base.RegisterControlLayout(json, layout); _registeredRemoteLayout.Add(layout); } var device = base.AddDevice(layout, name, variants); _remoteDevices.Add(device); onDeviceChange?.Invoke(device, InputDeviceChange.Added); return device; } public override void RemoveDevice(InputDevice device) { base.RemoveDevice(device); _remoteDevices.Remove(device); onDeviceChange?.Invoke(device, InputDeviceChange.Removed); } public override void RegisterControlLayout(string json, string name = null, bool isOverride = false) { // todo(kazuki):: not call base class // base.RegisterControlLayout(json, name, isOverride); _remoteLayouts.Add(name, json); onLayoutChange?.Invoke(name, InputControlLayoutChange.Added); } public override void RemoveLayout(string name) { if(_registeredRemoteLayout.Contains(name)) { base.RemoveLayout(name); _registeredRemoteLayout.Remove(name); } _remoteLayouts.Remove(name); onLayoutChange?.Invoke(name, InputControlLayoutChange.Removed); } public override void QueueEvent(InputEventPtr ptr) { InputDevice device = InputSystem.GetDeviceById(ptr.deviceId); // mapping sender coordinate system to receiver one. if (EnableInputPositionCorrection && device is Pointer && ptr.IsA()) { _corrector.Invoke(ptr, device); } else { base.QueueEvent(ptr); } } /// /// /// /// Texture Size. /// Region of the texture in world coordinate system. public void CalculateInputRegion(Rect inputRegion, Rect outputRegion) { _corrector.inputRegion = inputRegion; _corrector.outputRegion = outputRegion; } } } // #endif