【m】插件上传
This commit is contained in:
111
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/ArrayHelpers.cs
vendored
Normal file
111
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/ArrayHelpers.cs
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
// note:: This script is using code snippets in InputSystem.
|
||||
// https://github.com/Unity-Technologies/InputSystem/blob/develop/Packages/com.unity.inputsystem/InputSystem/Utilities/ArrayHelpers.cs
|
||||
// todo(kazuki):: This script should be moved into the WebRTC package.
|
||||
// #if UNITY_WEBRTC_ENABLE_INPUT_SYSTEM
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
// namespace Unity.WebRTC.InputSystem
|
||||
namespace Unity.RenderStreaming
|
||||
{
|
||||
internal static class ArrayHelpers
|
||||
{
|
||||
public static int LengthSafe<TValue>(this TValue[] array)
|
||||
{
|
||||
if (array == null)
|
||||
return 0;
|
||||
return array.Length;
|
||||
}
|
||||
|
||||
public static int Append<TValue>(ref TValue[] array, TValue value)
|
||||
{
|
||||
if (array == null)
|
||||
{
|
||||
array = new TValue[1];
|
||||
array[0] = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
var length = array.Length;
|
||||
Array.Resize(ref array, length + 1);
|
||||
array[length] = value;
|
||||
return length;
|
||||
}
|
||||
|
||||
public static int Append<TValue>(ref TValue[] array, IEnumerable<TValue> values)
|
||||
{
|
||||
if (array == null)
|
||||
{
|
||||
array = values.ToArray();
|
||||
return 0;
|
||||
}
|
||||
|
||||
var oldLength = array.Length;
|
||||
var valueCount = values.Count();
|
||||
|
||||
Array.Resize(ref array, oldLength + valueCount);
|
||||
|
||||
var index = oldLength;
|
||||
foreach (var value in values)
|
||||
array[index++] = value;
|
||||
|
||||
return oldLength;
|
||||
}
|
||||
|
||||
public static int IndexOf<TValue>(TValue[] array, TValue value, int startIndex = 0, int count = -1)
|
||||
{
|
||||
if (array == null)
|
||||
return -1;
|
||||
|
||||
if (count < 0)
|
||||
count = array.Length - startIndex;
|
||||
var comparer = EqualityComparer<TValue>.Default;
|
||||
for (var i = startIndex; i < startIndex + count; ++i)
|
||||
if (comparer.Equals(array[i], value))
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static bool Erase<TValue>(ref TValue[] array, TValue value)
|
||||
{
|
||||
var index = IndexOf(array, value);
|
||||
if (index != -1)
|
||||
{
|
||||
EraseAt(ref array, index);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void EraseAt<TValue>(ref TValue[] array, int index)
|
||||
{
|
||||
Debug.Assert(array != null);
|
||||
Debug.Assert(index >= 0 && index < array.Length);
|
||||
|
||||
var length = array.Length;
|
||||
if (index == 0 && length == 1)
|
||||
{
|
||||
array = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (index < length - 1)
|
||||
Array.Copy(array, index + 1, array, index, length - index - 1);
|
||||
|
||||
Array.Resize(ref array, length - 1);
|
||||
}
|
||||
|
||||
public static void PutAtIfNotSet<TValue>(ref TValue[] array, int index, Func<TValue> valueFn)
|
||||
{
|
||||
if (array.LengthSafe() < index + 1)
|
||||
Array.Resize(ref array, index + 1);
|
||||
|
||||
if (EqualityComparer<TValue>.Default.Equals(array[index], default(TValue)))
|
||||
array[index] = valueFn();
|
||||
}
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
11
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/ArrayHelpers.cs.meta
vendored
Normal file
11
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/ArrayHelpers.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b8f0ece9173904d43a03d40edca9effb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
257
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/EmulateInputFieldEvent.cs
vendored
Normal file
257
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/EmulateInputFieldEvent.cs
vendored
Normal file
@@ -0,0 +1,257 @@
|
||||
using System.Collections.Generic;
|
||||
#if URS_USE_TEXTMESHPRO
|
||||
using TMPro;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.InputSystem.Controls;
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
|
||||
namespace Unity.RenderStreaming.InputSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// This partial class is for workaround to support Unity UI InputField.
|
||||
/// </summary>
|
||||
partial class Receiver
|
||||
{
|
||||
private static readonly Dictionary<int, KeyCode> s_KeyMap = new Dictionary<int, KeyCode>()
|
||||
{
|
||||
{ (int)Key.Backspace, KeyCode.Backspace },
|
||||
{ (int)Key.Tab, KeyCode.Tab },
|
||||
{ (int)Key.Enter, KeyCode.Return },
|
||||
{ (int)Key.Space, KeyCode.Space },
|
||||
{ (int)Key.Comma, KeyCode.Comma },
|
||||
{ (int)Key.Minus, KeyCode.Minus },
|
||||
{ (int)Key.Period, KeyCode.Period },
|
||||
{ (int)Key.Slash, KeyCode.Slash },
|
||||
{ (int)Key.Digit0, KeyCode.Alpha0 },
|
||||
{ (int)Key.Digit1, KeyCode.Alpha1 },
|
||||
{ (int)Key.Digit2, KeyCode.Alpha2 },
|
||||
{ (int)Key.Digit3, KeyCode.Alpha3 },
|
||||
{ (int)Key.Digit4, KeyCode.Alpha4 },
|
||||
{ (int)Key.Digit5, KeyCode.Alpha5 },
|
||||
{ (int)Key.Digit6, KeyCode.Alpha6 },
|
||||
{ (int)Key.Digit7, KeyCode.Alpha7 },
|
||||
{ (int)Key.Digit8, KeyCode.Alpha8 },
|
||||
{ (int)Key.Digit9, KeyCode.Alpha9 },
|
||||
{ (int)Key.Semicolon, KeyCode.Semicolon },
|
||||
{ (int)Key.Equals, KeyCode.Equals },
|
||||
{ (int)Key.LeftBracket, KeyCode.LeftBracket },
|
||||
{ (int)Key.Backslash, KeyCode.Backslash },
|
||||
{ (int)Key.RightBracket, KeyCode.RightBracket },
|
||||
{ (int)Key.Backquote, KeyCode.BackQuote },
|
||||
{ (int)Key.Quote, KeyCode.Quote },
|
||||
{ (int)Key.A, KeyCode.A },
|
||||
{ (int)Key.B, KeyCode.B },
|
||||
{ (int)Key.C, KeyCode.C },
|
||||
{ (int)Key.D, KeyCode.D },
|
||||
{ (int)Key.E, KeyCode.E },
|
||||
{ (int)Key.F, KeyCode.F },
|
||||
{ (int)Key.G, KeyCode.G },
|
||||
{ (int)Key.H, KeyCode.H },
|
||||
{ (int)Key.I, KeyCode.I },
|
||||
{ (int)Key.J, KeyCode.J },
|
||||
{ (int)Key.K, KeyCode.K },
|
||||
{ (int)Key.L, KeyCode.L },
|
||||
{ (int)Key.M, KeyCode.M },
|
||||
{ (int)Key.N, KeyCode.N },
|
||||
{ (int)Key.O, KeyCode.O },
|
||||
{ (int)Key.P, KeyCode.P },
|
||||
{ (int)Key.Q, KeyCode.Q },
|
||||
{ (int)Key.R, KeyCode.R },
|
||||
{ (int)Key.S, KeyCode.S },
|
||||
{ (int)Key.T, KeyCode.T },
|
||||
{ (int)Key.U, KeyCode.U },
|
||||
{ (int)Key.V, KeyCode.V },
|
||||
{ (int)Key.W, KeyCode.W },
|
||||
{ (int)Key.X, KeyCode.X },
|
||||
{ (int)Key.Y, KeyCode.Y },
|
||||
{ (int)Key.Z, KeyCode.Z },
|
||||
{ (int)Key.F1, KeyCode.F1 },
|
||||
{ (int)Key.F2, KeyCode.F2 },
|
||||
{ (int)Key.F3, KeyCode.F3 },
|
||||
{ (int)Key.F4, KeyCode.F4 },
|
||||
{ (int)Key.F5, KeyCode.F5 },
|
||||
{ (int)Key.F6, KeyCode.F6 },
|
||||
{ (int)Key.F7, KeyCode.F7 },
|
||||
{ (int)Key.F8, KeyCode.F8 },
|
||||
{ (int)Key.F9, KeyCode.F9 },
|
||||
{ (int)Key.F10, KeyCode.F10 },
|
||||
{ (int)Key.F11, KeyCode.F11 },
|
||||
{ (int)Key.F12, KeyCode.F12 },
|
||||
{ (int)Key.None, KeyCode.None },
|
||||
{ (int)Key.LeftArrow, KeyCode.LeftArrow },
|
||||
{ (int)Key.RightArrow, KeyCode.RightArrow },
|
||||
{ (int)Key.UpArrow, KeyCode.UpArrow },
|
||||
{ (int)Key.DownArrow, KeyCode.DownArrow },
|
||||
{ (int)Key.LeftShift, KeyCode.LeftShift },
|
||||
{ (int)Key.RightShift, KeyCode.RightShift },
|
||||
{ (int)Key.Delete, KeyCode.Delete },
|
||||
{ (int)Key.Escape, KeyCode.Escape },
|
||||
{ (int)Key.LeftAlt, KeyCode.LeftAlt },
|
||||
{ (int)Key.RightAlt, KeyCode.RightAlt },
|
||||
{ (int)Key.LeftApple, KeyCode.LeftApple },
|
||||
{ (int)Key.RightApple, KeyCode.RightApple }
|
||||
};
|
||||
|
||||
interface IInputField
|
||||
{
|
||||
void ProcessEvent(Event e);
|
||||
void ForceLabelUpdate();
|
||||
void AppendText(char character);
|
||||
}
|
||||
|
||||
class UGUIInputField : IInputField
|
||||
{
|
||||
InputField m_field;
|
||||
public UGUIInputField(InputField field)
|
||||
{
|
||||
m_field = field;
|
||||
}
|
||||
|
||||
public void ProcessEvent(Event e)
|
||||
{
|
||||
m_field.ProcessEvent(e);
|
||||
}
|
||||
public void ForceLabelUpdate()
|
||||
{
|
||||
m_field.ForceLabelUpdate();
|
||||
}
|
||||
public void AppendText(char character)
|
||||
{
|
||||
m_field.text += character;
|
||||
}
|
||||
}
|
||||
|
||||
#if URS_USE_TEXTMESHPRO
|
||||
class TMProInputField : IInputField
|
||||
{
|
||||
TMP_InputField m_field;
|
||||
public TMProInputField(TMP_InputField field)
|
||||
{
|
||||
m_field = field;
|
||||
}
|
||||
|
||||
public void ProcessEvent(Event e)
|
||||
{
|
||||
m_field.ProcessEvent(e);
|
||||
}
|
||||
public void ForceLabelUpdate()
|
||||
{
|
||||
m_field.ForceLabelUpdate();
|
||||
}
|
||||
public void AppendText(char character)
|
||||
{
|
||||
m_field.text += character;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
IInputField FindInputField(GameObject obj)
|
||||
{
|
||||
var field = obj.GetComponent<InputField>();
|
||||
if (field != null)
|
||||
return new UGUIInputField(field);
|
||||
|
||||
#if URS_USE_TEXTMESHPRO
|
||||
var tmpField = obj.GetComponent<TMP_InputField>();
|
||||
if (tmpField != null)
|
||||
return new TMProInputField(tmpField);
|
||||
#endif
|
||||
return null;
|
||||
}
|
||||
|
||||
(EventModifiers, KeyCode) GetEventModifiersAndKeyCode(InputEventPtr ptr)
|
||||
{
|
||||
EventModifiers modifiers = EventModifiers.None;
|
||||
KeyCode keyCode = KeyCode.None;
|
||||
foreach (var control in ptr.GetAllButtonPresses())
|
||||
{
|
||||
if (control is KeyControl keyControl)
|
||||
{
|
||||
var key = keyControl.keyCode;
|
||||
if (key == Key.LeftShift || key == Key.RightShift)
|
||||
{
|
||||
modifiers |= EventModifiers.Shift;
|
||||
}
|
||||
else if (key == Key.LeftCtrl || key == Key.RightCtrl)
|
||||
{
|
||||
modifiers |= EventModifiers.Control;
|
||||
}
|
||||
else if (key == Key.LeftAlt || key == Key.RightAlt)
|
||||
{
|
||||
modifiers |= EventModifiers.Alt;
|
||||
}
|
||||
else if (key == Key.LeftCommand || key == Key.RightCommand)
|
||||
{
|
||||
modifiers |= EventModifiers.Command;
|
||||
}
|
||||
else if (key == Key.CapsLock)
|
||||
{
|
||||
modifiers |= EventModifiers.CapsLock;
|
||||
}
|
||||
else if (s_KeyMap.TryGetValue((int)key, out var value))
|
||||
{
|
||||
keyCode = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (modifiers, keyCode);
|
||||
}
|
||||
|
||||
unsafe Event CreateEvent(InputEventPtr ptr)
|
||||
{
|
||||
var (modifiers, keyCode) = GetEventModifiersAndKeyCode(ptr);
|
||||
|
||||
if (ptr.type == TextEvent.Type)
|
||||
{
|
||||
var textEventPtr = (TextEvent*)ptr.ToPointer();
|
||||
var utf32Char = textEventPtr->character;
|
||||
if (utf32Char >= 0x10000)
|
||||
{
|
||||
// todo: not supported multibyte character.
|
||||
return null;
|
||||
}
|
||||
if (utf32Char < 0x100)
|
||||
{
|
||||
// ignore control
|
||||
if (char.IsControl((char)utf32Char))
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Event
|
||||
{
|
||||
type = EventType.KeyDown,
|
||||
character = (char)utf32Char,
|
||||
keyCode = keyCode,
|
||||
modifiers = modifiers
|
||||
};
|
||||
}
|
||||
|
||||
return new Event
|
||||
{
|
||||
type = EventType.KeyDown,
|
||||
keyCode = keyCode,
|
||||
modifiers = modifiers
|
||||
};
|
||||
}
|
||||
|
||||
private void EmulateInputFieldEvent(InputEventPtr ptr)
|
||||
{
|
||||
var obj = UnityEngine.EventSystems.EventSystem.current?.currentSelectedGameObject;
|
||||
if (obj == null)
|
||||
return;
|
||||
|
||||
var field = FindInputField(obj);
|
||||
if (field == null)
|
||||
return;
|
||||
Event e = CreateEvent(ptr);
|
||||
if (e != null)
|
||||
{
|
||||
field.ProcessEvent(e);
|
||||
field.ForceLabelUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a3d7722788597434b979a31af26668c1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.InputSystem.Layouts;
|
||||
|
||||
namespace Unity.RenderStreaming.InputSystem
|
||||
{
|
||||
// todo(kazuki)::Avoid to use reflection
|
||||
static class InputDeviceExtension
|
||||
{
|
||||
private static Type typeInputDevice;
|
||||
private static FieldInfo fieldInfoParticipantId;
|
||||
private static FieldInfo fieldInfoDescription;
|
||||
private static FieldInfo fieldInfoDeviceFlags;
|
||||
|
||||
static InputDeviceExtension()
|
||||
{
|
||||
typeInputDevice = typeof(InputDevice);
|
||||
fieldInfoParticipantId = typeInputDevice.GetField("m_ParticipantId",
|
||||
BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
fieldInfoDescription = typeInputDevice.GetField("m_Description",
|
||||
BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
fieldInfoDeviceFlags = typeInputDevice.GetField("m_DeviceFlags",
|
||||
BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
}
|
||||
|
||||
public static void SetParticipantId(this InputDevice device, int value)
|
||||
{
|
||||
fieldInfoParticipantId.SetValue(device, value);
|
||||
}
|
||||
|
||||
public static int GetParticipantId(this InputDevice device)
|
||||
{
|
||||
return (int)fieldInfoParticipantId.GetValue(device);
|
||||
}
|
||||
|
||||
public static void SetDescription(this InputDevice device, InputDeviceDescription value)
|
||||
{
|
||||
fieldInfoDescription.SetValue(device, value);
|
||||
}
|
||||
|
||||
public static void SetDeviceFlags(this InputDevice device, int value)
|
||||
{
|
||||
fieldInfoDeviceFlags.SetValue(device, value);
|
||||
}
|
||||
public static int GetDeviceFlags(this InputDevice device)
|
||||
{
|
||||
return (int)fieldInfoDeviceFlags.GetValue(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b9703223ad9b06848b11ed494a9871a8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Unity.RenderStreaming.InputSystem
|
||||
{
|
||||
#if UNITY_EDITOR && !INPUTSYSTEM_1_1_OR_NEWER
|
||||
// todo(kazuki)::Avoid to use reflection
|
||||
static class InputEditorUserSettings
|
||||
{
|
||||
private static Type type;
|
||||
private static PropertyInfo propertyLockInputToGameView;
|
||||
private static MethodInfo methodLoad;
|
||||
private static FieldInfo fieldFilePath;
|
||||
|
||||
static InputEditorUserSettings()
|
||||
{
|
||||
type = Type.GetType("UnityEngine.InputSystem.Editor.InputEditorUserSettings, Unity.InputSystem");
|
||||
propertyLockInputToGameView = type.GetProperty("lockInputToGameView");
|
||||
methodLoad = type.GetMethod("Load",
|
||||
BindingFlags.NonPublic | BindingFlags.Static);
|
||||
fieldFilePath = type.GetField("kSavePath",
|
||||
BindingFlags.NonPublic | BindingFlags.Static);
|
||||
}
|
||||
|
||||
public static bool lockInputToGameView
|
||||
{
|
||||
get { return (bool)propertyLockInputToGameView.GetValue(null); }
|
||||
set { propertyLockInputToGameView.SetValue(null, value); }
|
||||
}
|
||||
|
||||
public static void Load()
|
||||
{
|
||||
methodLoad.Invoke(null, null);
|
||||
}
|
||||
|
||||
public static void Delete()
|
||||
{
|
||||
string filePath = (string)fieldFilePath.GetValue(null);
|
||||
if(File.Exists(filePath))
|
||||
File.Delete(filePath);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b8555e3da10e49e99f0af56f4512955
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
178
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/InputManager.cs
vendored
Normal file
178
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/InputManager.cs
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.InputSystem.Layouts;
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
using UnityEngine.InputSystem.Utilities;
|
||||
|
||||
namespace Unity.RenderStreaming.InputSystem
|
||||
{
|
||||
using InputSystem = UnityEngine.InputSystem.InputSystem;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public interface IInputManager
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
event Action<InputRemoting.Message> onMessage;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
event Action<InputEventPtr, InputDevice> onEvent;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
event Action<InputDevice, InputDeviceChange> onDeviceChange;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
event Action<string, InputControlLayoutChange> onLayoutChange;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
ReadOnlyArray<InputDevice> devices { get; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
IEnumerable<string> layouts { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="deviceId"></param>
|
||||
/// <returns></returns>
|
||||
InputDevice GetDeviceById(int deviceId);
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="layout"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="variants"></param>
|
||||
/// <returns></returns>
|
||||
InputDevice AddDevice(string layout, string name = null, string variants = null);
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="device"></param>
|
||||
void RemoveDevice(InputDevice device);
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="device"></param>
|
||||
/// <param name="usage"></param>
|
||||
void AddDeviceUsage(InputDevice device, string usage);
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="device"></param>
|
||||
/// <param name="usage"></param>
|
||||
void RemoveDeviceUsage(InputDevice device, string usage);
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
InputControlLayout LoadLayout(string name);
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="json"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="matches"></param>
|
||||
void RegisterControlLayout(string json, string name = null, bool isOverride = false);
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
void RemoveLayout(string name);
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="eventPtr"></param>
|
||||
void QueueEvent(InputEventPtr eventPtr);
|
||||
}
|
||||
|
||||
public abstract class InputManager : IInputManager
|
||||
{
|
||||
//todo(kazuki):: remove warning CS0067
|
||||
#pragma warning disable 0067
|
||||
public virtual event Action<InputRemoting.Message> onMessage;
|
||||
public virtual event Action<InputEventPtr, InputDevice> onEvent;
|
||||
public virtual event Action<InputDevice, InputDeviceChange> onDeviceChange;
|
||||
public virtual event Action<string, InputControlLayoutChange> onLayoutChange;
|
||||
#pragma warning restore 0067
|
||||
|
||||
public virtual ReadOnlyArray<InputDevice> devices
|
||||
{
|
||||
get
|
||||
{
|
||||
return InputSystem.devices;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual IEnumerable<string> layouts
|
||||
{
|
||||
get
|
||||
{
|
||||
return InputSystem.ListLayouts();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual InputDevice GetDeviceById(int deviceId)
|
||||
{
|
||||
return InputSystem.GetDeviceById(deviceId);
|
||||
}
|
||||
|
||||
public virtual InputDevice AddDevice(string layout, string name = null, string variants = null)
|
||||
{
|
||||
foreach (var device_ in InputSystem.devices.Where(device => device.enabled))
|
||||
InputSystem.ResetDevice(device_);
|
||||
return InputSystem.AddDevice(layout, name, variants);
|
||||
}
|
||||
|
||||
public virtual void RemoveDevice(InputDevice device)
|
||||
{
|
||||
foreach (var device_ in InputSystem.devices.Where(device => device.enabled))
|
||||
InputSystem.ResetDevice(device_);
|
||||
InputSystem.RemoveDevice(device);
|
||||
}
|
||||
|
||||
public virtual void AddDeviceUsage(InputDevice device, string usage)
|
||||
{
|
||||
InputSystem.AddDeviceUsage(device, usage);
|
||||
}
|
||||
public virtual void RemoveDeviceUsage(InputDevice device, string usage)
|
||||
{
|
||||
InputSystem.RemoveDeviceUsage(device, usage);
|
||||
}
|
||||
|
||||
public virtual InputControlLayout LoadLayout(string name)
|
||||
{
|
||||
return InputSystem.LoadLayout(name);
|
||||
}
|
||||
|
||||
public virtual void RegisterControlLayout(string json, string name = null, bool isOverride = false)
|
||||
{
|
||||
if (isOverride)
|
||||
InputSystem.RegisterLayoutOverride(json, name);
|
||||
else
|
||||
InputSystem.RegisterLayout(json, name);
|
||||
}
|
||||
|
||||
public virtual void RemoveLayout(string name)
|
||||
{
|
||||
InputSystem.RemoveLayout(name);
|
||||
}
|
||||
|
||||
public virtual void QueueEvent(InputEventPtr eventPtr)
|
||||
{
|
||||
InputSystem.QueueEvent(eventPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
11
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/InputManager.cs.meta
vendored
Normal file
11
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/InputManager.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab747f6e991890d4996dd8a432b7bd5a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
861
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/InputRemoting.cs
vendored
Normal file
861
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/InputRemoting.cs
vendored
Normal file
@@ -0,0 +1,861 @@
|
||||
// note:: This script is using code snippets in InputSystem.
|
||||
// https://github.com/Unity-Technologies/InputSystem/blob/develop/Packages/com.unity.inputsystem/InputSystem/Devices/Remote/InputRemoting.cs
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.InputSystem.Layouts;
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
using UnityEngine.InputSystem.Utilities;
|
||||
|
||||
////TODO: show remote device IDs in the debugger
|
||||
|
||||
////TODO: remote timestamps need to be translated to local timestamps; doesn't make sense for remote events getting
|
||||
//// processed on the local timeline as is when the originating timeline may be quite different
|
||||
|
||||
////TODO: support actions
|
||||
|
||||
////TODO: support input users
|
||||
|
||||
////TODO: text input events
|
||||
|
||||
////REVIEW: it seems that the various XXXMsg struct should be public; ATM doesn't seem like working with the message interface is practical
|
||||
|
||||
////REVIEW: the namespacing mechanism for layouts which changes base layouts means that layouts can't be played
|
||||
//// around with on the editor side but will only be changed once they're updated in the player
|
||||
|
||||
namespace Unity.RenderStreaming.InputSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Makes the activity and data of an InputManager observable in message form.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Can act as both the sender and Receiver of these message so the flow is fully bidirectional,
|
||||
/// i.e. the InputManager on either end can mirror its layouts, devices, and events over
|
||||
/// to the other end. This permits streaming input not just from the player to the editor but
|
||||
/// also feeding input from the editor back into the player.
|
||||
///
|
||||
/// Remoting sits entirely on top of the input system as an optional piece of functionality.
|
||||
/// In development players and the editor, we enable it automatically but in non-development
|
||||
/// players it has to be explicitly requested by the user.
|
||||
///
|
||||
/// To see devices and input from players in the editor, open the Input Debugger through
|
||||
/// "Windows >> Input Debugger".
|
||||
/// </remarks>
|
||||
/// <seealso cref="InputSystem.remoting"/>
|
||||
/// \todo Reuse memory allocated for messages instead of allocating separately for each message.
|
||||
/// \todo Inteface to determine what to mirror from the local manager to the remote system.
|
||||
public sealed class InputRemoting : IObservable<InputRemoting.Message>, IObserver<InputRemoting.Message>
|
||||
{
|
||||
/// <summary>
|
||||
/// Enumeration of possible types of messages exchanged between two InputRemoting instances.
|
||||
/// </summary>
|
||||
public enum MessageType
|
||||
{
|
||||
Connect,
|
||||
Disconnect,
|
||||
NewLayout,
|
||||
NewDevice,
|
||||
NewEvents,
|
||||
RemoveDevice,
|
||||
RemoveLayout,
|
||||
ChangeUsages,
|
||||
StartSending,
|
||||
StopSending,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A message exchanged between two InputRemoting instances.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Message
|
||||
{
|
||||
/// <summary>
|
||||
/// For messages coming in, numeric ID of the sender of the message. For messages
|
||||
/// going out, numeric ID of the targeted Receiver of the message.
|
||||
/// </summary>
|
||||
public int participantId;
|
||||
public MessageType type;
|
||||
public byte[] data;
|
||||
}
|
||||
|
||||
public bool sending
|
||||
{
|
||||
get => (m_Flags & Flags.Sending) == Flags.Sending;
|
||||
private set
|
||||
{
|
||||
if (value)
|
||||
m_Flags |= Flags.Sending;
|
||||
else
|
||||
m_Flags &= ~Flags.Sending;
|
||||
}
|
||||
}
|
||||
|
||||
static InputRemoting()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
//
|
||||
// note: This lines are for avoiding issues when running the editor
|
||||
// on background. When moved the focus from the editor, input events
|
||||
// from another process are ignored.
|
||||
// Please attention behaviours are difference several platforms when
|
||||
// moving focus from Unity Editor.
|
||||
//
|
||||
// Additionally, The behaviour is changed Unity2021.2 later (using
|
||||
// InputSystem 1.1). Please see "Background behaviour".
|
||||
// https://docs.unity3d.com/Packages/com.unity.inputsystem@1.1/manual/Settings.html#background-behavior
|
||||
#if INPUTSYSTEM_1_1_OR_NEWER
|
||||
// todo(kazuki):
|
||||
#else
|
||||
// Make sure we're not affected by the user giving focus away from the
|
||||
// game view.
|
||||
//
|
||||
InputEditorUserSettings.lockInputToGameView = true;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
internal InputRemoting(IInputManager manager, bool startSendingOnConnect = false)
|
||||
{
|
||||
if (manager == null)
|
||||
throw new ArgumentNullException("manager");
|
||||
|
||||
m_LocalManager = manager;
|
||||
|
||||
if (startSendingOnConnect)
|
||||
m_Flags |= Flags.StartSendingOnConnect;
|
||||
|
||||
//when listening for newly added layouts, must filter out ones we've added from remote
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start sending messages for data and activity in the local input system
|
||||
/// to observers.
|
||||
/// </summary>
|
||||
/// <seealso cref="sending"/>
|
||||
/// <seealso cref="StopSending"/>
|
||||
public void StartSending()
|
||||
{
|
||||
if (sending)
|
||||
return;
|
||||
|
||||
////TODO: send events in bulk rather than one-by-one
|
||||
m_LocalManager.onMessage += Send;
|
||||
m_LocalManager.onEvent += SendEvent;
|
||||
m_LocalManager.onDeviceChange += SendDeviceChange;
|
||||
m_LocalManager.onLayoutChange += SendLayoutChange;
|
||||
|
||||
sending = true;
|
||||
|
||||
SendInitialMessages();
|
||||
}
|
||||
|
||||
public void StopSending()
|
||||
{
|
||||
if (!sending)
|
||||
return;
|
||||
|
||||
m_LocalManager.onMessage -= Send;
|
||||
m_LocalManager.onEvent -= SendEvent;
|
||||
m_LocalManager.onDeviceChange -= SendDeviceChange;
|
||||
m_LocalManager.onLayoutChange -= SendLayoutChange;
|
||||
|
||||
sending = false;
|
||||
}
|
||||
|
||||
void IObserver<Message>.OnNext(Message msg)
|
||||
{
|
||||
switch (msg.type)
|
||||
{
|
||||
case MessageType.Connect:
|
||||
ConnectMsg.Process(this);
|
||||
break;
|
||||
case MessageType.Disconnect:
|
||||
DisconnectMsg.Process(this, msg);
|
||||
break;
|
||||
case MessageType.NewLayout:
|
||||
NewLayoutMsg.Process(this, msg);
|
||||
break;
|
||||
case MessageType.RemoveLayout:
|
||||
RemoveLayoutMsg.Process(this, msg);
|
||||
break;
|
||||
case MessageType.NewDevice:
|
||||
NewDeviceMsg.Process(this, msg);
|
||||
break;
|
||||
case MessageType.NewEvents:
|
||||
NewEventsMsg.Process(this, msg);
|
||||
break;
|
||||
case MessageType.ChangeUsages:
|
||||
ChangeUsageMsg.Process(this, msg);
|
||||
break;
|
||||
case MessageType.RemoveDevice:
|
||||
RemoveDeviceMsg.Process(this, msg);
|
||||
break;
|
||||
case MessageType.StartSending:
|
||||
StartSendingMsg.Process(this);
|
||||
break;
|
||||
case MessageType.StopSending:
|
||||
StopSendingMsg.Process(this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void IObserver<Message>.OnError(Exception error)
|
||||
{
|
||||
}
|
||||
|
||||
void IObserver<Message>.OnCompleted()
|
||||
{
|
||||
}
|
||||
|
||||
public IDisposable Subscribe(IObserver<Message> observer)
|
||||
{
|
||||
if (observer == null)
|
||||
throw new ArgumentNullException("observer");
|
||||
|
||||
var subscriber = new Subscriber { owner = this, observer = observer };
|
||||
ArrayHelpers.Append(ref m_Subscribers, subscriber);
|
||||
|
||||
return subscriber;
|
||||
}
|
||||
|
||||
private void SendInitialMessages()
|
||||
{
|
||||
SendAllGeneratedLayouts();
|
||||
SendAllDevices();
|
||||
}
|
||||
|
||||
private void SendAllGeneratedLayouts()
|
||||
{
|
||||
// todo(kazuki)::
|
||||
// layputBuilders property is not published from InputSystem
|
||||
//
|
||||
//foreach (var entry in m_LocalManager.m_Layouts.layoutBuilders)
|
||||
// SendLayout(entry.Key);
|
||||
|
||||
foreach (var layout in m_LocalManager.layouts)
|
||||
SendLayout(layout);
|
||||
}
|
||||
|
||||
private void SendLayout(string layoutName)
|
||||
{
|
||||
if (m_Subscribers == null)
|
||||
return;
|
||||
|
||||
var message = NewLayoutMsg.Create(this, layoutName);
|
||||
if (message != null)
|
||||
Send(message.Value);
|
||||
}
|
||||
|
||||
private void SendAllDevices()
|
||||
{
|
||||
var devices = m_LocalManager.devices;
|
||||
foreach (var device in devices)
|
||||
SendDevice(device);
|
||||
}
|
||||
|
||||
private void SendDevice(InputDevice device)
|
||||
{
|
||||
if (m_Subscribers == null)
|
||||
return;
|
||||
|
||||
// Don't mirror remote devices to other remotes.
|
||||
if (device.remote)
|
||||
return;
|
||||
|
||||
var newDeviceMessage = NewDeviceMsg.Create(device);
|
||||
Send(newDeviceMessage);
|
||||
|
||||
// Send current state. We do this here in this case as the device
|
||||
// may have been added some time ago and thus have already received events.
|
||||
var stateEventMessage = NewEventsMsg.CreateStateEvent(device);
|
||||
Send(stateEventMessage);
|
||||
}
|
||||
|
||||
private unsafe void SendEvent(InputEventPtr eventPtr, InputDevice device)
|
||||
{
|
||||
if (m_Subscribers == null)
|
||||
return;
|
||||
|
||||
////REVIEW: we probably want to have better control over this and allow producing local events
|
||||
//// against remote devices which *are* indeed sent across the wire
|
||||
// Don't send events that came in from remote devices.
|
||||
if (device != null && device.remote)
|
||||
return;
|
||||
|
||||
var message = NewEventsMsg.Create(eventPtr.data, 1);
|
||||
Send(message);
|
||||
}
|
||||
|
||||
private void SendDeviceChange(InputDevice device, InputDeviceChange change)
|
||||
{
|
||||
if (m_Subscribers == null)
|
||||
return;
|
||||
|
||||
// Don't mirror remoted devices to other remotes.
|
||||
if (device.remote)
|
||||
return;
|
||||
|
||||
Message msg;
|
||||
switch (change)
|
||||
{
|
||||
case InputDeviceChange.Added:
|
||||
msg = NewDeviceMsg.Create(device);
|
||||
break;
|
||||
case InputDeviceChange.Removed:
|
||||
msg = RemoveDeviceMsg.Create(device);
|
||||
break;
|
||||
case InputDeviceChange.UsageChanged:
|
||||
msg = ChangeUsageMsg.Create(device);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
Send(msg);
|
||||
}
|
||||
|
||||
private void SendLayoutChange(string layout, InputControlLayoutChange change)
|
||||
{
|
||||
if (m_Subscribers == null)
|
||||
return;
|
||||
|
||||
Message msg;
|
||||
switch (change)
|
||||
{
|
||||
case InputControlLayoutChange.Added:
|
||||
case InputControlLayoutChange.Replaced:
|
||||
var message = NewLayoutMsg.Create(this, layout);
|
||||
if (message == null)
|
||||
return;
|
||||
msg = message.Value;
|
||||
break;
|
||||
case InputControlLayoutChange.Removed:
|
||||
msg = RemoveLayoutMsg.Create(layout);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
Send(msg);
|
||||
}
|
||||
|
||||
private void Send(Message msg)
|
||||
{
|
||||
foreach (var subscriber in m_Subscribers)
|
||||
subscriber.observer.OnNext(msg);
|
||||
}
|
||||
|
||||
////TODO: with C#7 this should be a ref return
|
||||
private int FindOrCreateSenderRecord(int senderId)
|
||||
{
|
||||
// Try to find existing.
|
||||
if (m_Senders != null)
|
||||
{
|
||||
var senderCount = m_Senders.Length;
|
||||
for (var i = 0; i < senderCount; ++i)
|
||||
if (m_Senders[i].senderId == senderId)
|
||||
return i;
|
||||
}
|
||||
|
||||
// Create new.
|
||||
var sender = new RemoteSender
|
||||
{
|
||||
senderId = senderId,
|
||||
};
|
||||
return ArrayHelpers.Append(ref m_Senders, sender);
|
||||
}
|
||||
|
||||
private int FindLocalDeviceId(int remoteDeviceId, int senderIndex)
|
||||
{
|
||||
var localDevices = m_Senders[senderIndex].devices;
|
||||
if (localDevices != null)
|
||||
{
|
||||
var numLocalDevices = localDevices.Length;
|
||||
|
||||
for (var i = 0; i < numLocalDevices; ++i)
|
||||
{
|
||||
if (localDevices[i].remoteId == remoteDeviceId)
|
||||
return localDevices[i].localId;
|
||||
}
|
||||
}
|
||||
|
||||
return InputDevice.InvalidDeviceId;
|
||||
}
|
||||
|
||||
private InputDevice TryGetDeviceByRemoteId(int remoteDeviceId, int senderIndex)
|
||||
{
|
||||
var localId = FindLocalDeviceId(remoteDeviceId, senderIndex);
|
||||
return m_LocalManager.GetDeviceById(localId);
|
||||
}
|
||||
|
||||
private Flags m_Flags;
|
||||
private IInputManager m_LocalManager; // Input system we mirror input from and to.
|
||||
private Subscriber[] m_Subscribers; // Receivers we send input to.
|
||||
private RemoteSender[] m_Senders; // Senders we receive input from.
|
||||
|
||||
[Flags]
|
||||
private enum Flags
|
||||
{
|
||||
Sending = 1 << 0,
|
||||
StartSendingOnConnect = 1 << 1
|
||||
}
|
||||
|
||||
// Data we keep about a unique sender that we receive input data
|
||||
// from. We keep track of the layouts and devices we added to
|
||||
// the local system.
|
||||
[Serializable]
|
||||
internal struct RemoteSender
|
||||
{
|
||||
public int senderId;
|
||||
public string[] layouts;
|
||||
public RemoteInputDevice[] devices;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal struct RemoteInputDevice
|
||||
{
|
||||
public int remoteId; // Device ID used by sender.
|
||||
public int localId; // Device ID used by us in local system.
|
||||
|
||||
public InputDeviceDescription description;
|
||||
}
|
||||
|
||||
internal class Subscriber : IDisposable
|
||||
{
|
||||
public InputRemoting owner;
|
||||
public IObserver<Message> observer;
|
||||
public void Dispose()
|
||||
{
|
||||
ArrayHelpers.Erase(ref owner.m_Subscribers, this);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ConnectMsg
|
||||
{
|
||||
public static void Process(InputRemoting Receiver)
|
||||
{
|
||||
if (Receiver.sending)
|
||||
{
|
||||
Receiver.SendAllDevices();
|
||||
}
|
||||
else if ((Receiver.m_Flags & Flags.StartSendingOnConnect) == Flags.StartSendingOnConnect)
|
||||
Receiver.StartSending();
|
||||
}
|
||||
}
|
||||
|
||||
private static class StartSendingMsg
|
||||
{
|
||||
public static void Process(InputRemoting Receiver)
|
||||
{
|
||||
Receiver.StartSending();
|
||||
}
|
||||
}
|
||||
|
||||
private static class StopSendingMsg
|
||||
{
|
||||
public static void Process(InputRemoting Receiver)
|
||||
{
|
||||
Receiver.StopSending();
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveRemoteDevices(int participantId)
|
||||
{
|
||||
var senderIndex = FindOrCreateSenderRecord(participantId);
|
||||
|
||||
// Remove devices added by remote.
|
||||
var devices = m_Senders[senderIndex].devices;
|
||||
if (devices != null)
|
||||
{
|
||||
foreach (var remoteDevice in devices)
|
||||
{
|
||||
var device = m_LocalManager.GetDeviceById(remoteDevice.localId);
|
||||
if (device != null)
|
||||
m_LocalManager.RemoveDevice(device);
|
||||
}
|
||||
}
|
||||
|
||||
////TODO: remove layouts added by remote
|
||||
ArrayHelpers.EraseAt(ref m_Senders, senderIndex);
|
||||
}
|
||||
|
||||
private static class DisconnectMsg
|
||||
{
|
||||
public static void Process(InputRemoting Receiver, Message msg)
|
||||
{
|
||||
Receiver.RemoveRemoteDevices(msg.participantId);
|
||||
Receiver.StopSending();
|
||||
}
|
||||
}
|
||||
|
||||
// Tell remote input system that there's a new layout.
|
||||
private static class NewLayoutMsg
|
||||
{
|
||||
[Serializable]
|
||||
public struct Data
|
||||
{
|
||||
public string name;
|
||||
public string layoutJson;
|
||||
public bool isOverride;
|
||||
}
|
||||
|
||||
public static Message? Create(InputRemoting sender, string layoutName)
|
||||
{
|
||||
// Try to load the layout. Ignore the layout if it couldn't
|
||||
// be loaded.
|
||||
InputControlLayout layout;
|
||||
try
|
||||
{
|
||||
layout = sender.m_LocalManager.LoadLayout(new InternedString(layoutName));
|
||||
if (layout == null)
|
||||
{
|
||||
RenderStreaming.Logger.Log(string.Format(
|
||||
"Could not find layout '{0}' meant to be sent through remote connection; this should not happen",
|
||||
layoutName));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
RenderStreaming.Logger.Log(string.Format(
|
||||
"Could not load layout '{0}'; not sending to remote listeners (exception: {1})", layoutName,
|
||||
exception));
|
||||
return null;
|
||||
}
|
||||
|
||||
var data = new Data
|
||||
{
|
||||
name = layoutName,
|
||||
layoutJson = layout.ToJson(),
|
||||
isOverride = layout.isOverride
|
||||
};
|
||||
|
||||
return new Message
|
||||
{
|
||||
type = MessageType.NewLayout,
|
||||
data = SerializeData(data)
|
||||
};
|
||||
}
|
||||
|
||||
public static void Process(InputRemoting Receiver, Message msg)
|
||||
{
|
||||
var data = DeserializeData<Data>(msg.data);
|
||||
var senderIndex = Receiver.FindOrCreateSenderRecord(msg.participantId);
|
||||
|
||||
var internedLayoutName = new InternedString(data.name);
|
||||
Receiver.m_LocalManager.RegisterControlLayout(data.layoutJson, data.name, data.isOverride);
|
||||
ArrayHelpers.Append(ref Receiver.m_Senders[senderIndex].layouts, internedLayoutName);
|
||||
}
|
||||
}
|
||||
|
||||
private static class RemoveLayoutMsg
|
||||
{
|
||||
public static Message Create(string layoutName)
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(layoutName);
|
||||
return new Message
|
||||
{
|
||||
type = MessageType.RemoveLayout,
|
||||
data = bytes
|
||||
};
|
||||
}
|
||||
|
||||
public static void Process(InputRemoting Receiver, Message msg)
|
||||
{
|
||||
////REVIEW: we probably don't want to do this blindly
|
||||
var layoutName = Encoding.UTF8.GetString(msg.data);
|
||||
Receiver.m_LocalManager.RemoveLayout(layoutName);
|
||||
}
|
||||
}
|
||||
|
||||
// Tell remote input system that there's a new device.
|
||||
private static class NewDeviceMsg
|
||||
{
|
||||
[Serializable]
|
||||
public struct Data
|
||||
{
|
||||
public string name;
|
||||
public string layout;
|
||||
public int deviceId;
|
||||
public string[] usages;
|
||||
public InputDeviceDescription description;
|
||||
}
|
||||
|
||||
public static Message Create(InputDevice device)
|
||||
{
|
||||
Debug.Assert(!device.remote, "Device being sent to remotes should be a local device, not a remote one");
|
||||
|
||||
var data = new Data
|
||||
{
|
||||
name = device.name,
|
||||
layout = device.layout,
|
||||
deviceId = device.deviceId,
|
||||
description = device.description,
|
||||
usages = device.usages.Select(x => x.ToString()).ToArray()
|
||||
};
|
||||
|
||||
var json = JsonUtility.ToJson(data);
|
||||
var bytes = Encoding.UTF8.GetBytes(json);
|
||||
|
||||
return new Message
|
||||
{
|
||||
type = MessageType.NewDevice,
|
||||
data = bytes
|
||||
};
|
||||
}
|
||||
|
||||
public static void Process(InputRemoting Receiver, Message msg)
|
||||
{
|
||||
var senderIndex = Receiver.FindOrCreateSenderRecord(msg.participantId);
|
||||
var data = DeserializeData<Data>(msg.data);
|
||||
|
||||
// Make sure we haven't already seen the device.
|
||||
var devices = Receiver.m_Senders[senderIndex].devices;
|
||||
if (devices != null)
|
||||
{
|
||||
foreach (var entry in devices)
|
||||
if (entry.remoteId == data.deviceId)
|
||||
{
|
||||
RenderStreaming.Logger.Log(LogType.Error, string.Format(
|
||||
"Already received device with id {0} (layout '{1}', description '{3}) from remote {2}",
|
||||
data.deviceId,
|
||||
data.layout, msg.participantId, data.description));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Create device.
|
||||
InputDevice device;
|
||||
try
|
||||
{
|
||||
////REVIEW: this gives remote devices names the same way that local devices receive them; should we make remote status visible in the name?
|
||||
device = Receiver.m_LocalManager.AddDevice(data.layout, data.name);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
RenderStreaming.Logger.Log(LogType.Error,
|
||||
$"Could not create remote device '{data.description}' with layout '{data.layout}' locally (exception: {exception})");
|
||||
return;
|
||||
}
|
||||
// todo(kazuki)::Avoid to use reflection
|
||||
// device.m_ParticipantId = msg.participantId;
|
||||
device.SetParticipantId(msg.participantId);
|
||||
|
||||
// todo(kazuki)::Avoid to use reflection
|
||||
// device.m_Description = data.description;
|
||||
// device.m_DeviceFlags |= InputDevice.DeviceFlags.Remote;
|
||||
device.SetDescription(data.description);
|
||||
|
||||
var deviceFlagsRemote = 1 << 3;
|
||||
device.SetDeviceFlags(device.GetDeviceFlags() | deviceFlagsRemote);
|
||||
|
||||
if (data.usages != null)
|
||||
foreach (var usage in data.usages)
|
||||
Receiver.m_LocalManager.AddDeviceUsage(device, usage);
|
||||
|
||||
// Remember it.
|
||||
var record = new RemoteInputDevice
|
||||
{
|
||||
remoteId = data.deviceId,
|
||||
localId = device.deviceId,
|
||||
description = data.description
|
||||
};
|
||||
ArrayHelpers.Append(ref Receiver.m_Senders[senderIndex].devices, record);
|
||||
}
|
||||
}
|
||||
|
||||
// Tell remote system there's new input events.
|
||||
private static class NewEventsMsg
|
||||
{
|
||||
// todo(kazuki):: not found DeviceResetEvent
|
||||
//public static unsafe Message CreateResetEvent(InputDevice device, bool isHardReset)
|
||||
//{
|
||||
// var resetEvent = DeviceResetEvent.Create(device.deviceId, isHardReset);
|
||||
// return Create((InputEvent*)UnsafeUtility.AddressOf(ref resetEvent), 1);
|
||||
//}
|
||||
|
||||
public static unsafe Message CreateStateEvent(InputDevice device)
|
||||
{
|
||||
using (StateEvent.From(device, out var eventPtr))
|
||||
return Create(eventPtr.data, 1);
|
||||
}
|
||||
|
||||
public static unsafe Message Create(InputEvent* events, int eventCount)
|
||||
{
|
||||
// Find total size of event buffer we need.
|
||||
var totalSize = 0u;
|
||||
var eventPtr = new InputEventPtr(events);
|
||||
for (var i = 0; i < eventCount; ++i, eventPtr = eventPtr.Next())
|
||||
{
|
||||
totalSize += eventPtr.sizeInBytes;
|
||||
}
|
||||
|
||||
// Copy event data to buffer. Would be nice if we didn't have to do that
|
||||
// but unfortunately we need a byte[] and can't just pass the 'events' IntPtr
|
||||
// directly.
|
||||
var data = new byte[totalSize];
|
||||
fixed (byte* dataPtr = data)
|
||||
{
|
||||
UnsafeUtility.MemCpy(dataPtr, events, totalSize);
|
||||
}
|
||||
|
||||
// Done.
|
||||
return new Message
|
||||
{
|
||||
type = MessageType.NewEvents,
|
||||
data = data
|
||||
};
|
||||
}
|
||||
|
||||
public static unsafe void Process(InputRemoting Receiver, Message msg)
|
||||
{
|
||||
var manager = Receiver.m_LocalManager;
|
||||
|
||||
fixed (byte* dataPtr = msg.data)
|
||||
{
|
||||
var dataEndPtr = new IntPtr(dataPtr + msg.data.Length);
|
||||
var eventCount = 0;
|
||||
var eventPtr = new InputEventPtr((InputEvent*)dataPtr);
|
||||
var senderIndex = Receiver.FindOrCreateSenderRecord(msg.participantId);
|
||||
|
||||
while ((Int64)eventPtr.data < dataEndPtr.ToInt64())
|
||||
{
|
||||
// Patch up device ID to refer to local device and send event.
|
||||
var remoteDeviceId = eventPtr.deviceId;
|
||||
var localDeviceId = Receiver.FindLocalDeviceId(remoteDeviceId, senderIndex);
|
||||
eventPtr.deviceId = localDeviceId;
|
||||
|
||||
if (localDeviceId != InputDevice.InvalidDeviceId)
|
||||
{
|
||||
////TODO: add API to send events in bulk rather than one by one
|
||||
manager.QueueEvent(eventPtr);
|
||||
}
|
||||
|
||||
++eventCount;
|
||||
eventPtr = eventPtr.Next();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ChangeUsageMsg
|
||||
{
|
||||
[Serializable]
|
||||
public struct Data
|
||||
{
|
||||
public int deviceId;
|
||||
public string[] usages;
|
||||
}
|
||||
|
||||
public static Message Create(InputDevice device)
|
||||
{
|
||||
var data = new Data
|
||||
{
|
||||
deviceId = device.deviceId,
|
||||
usages = device.usages.Select(x => x.ToString()).ToArray()
|
||||
};
|
||||
|
||||
return new Message
|
||||
{
|
||||
type = MessageType.ChangeUsages,
|
||||
data = SerializeData(data)
|
||||
};
|
||||
}
|
||||
|
||||
public static void Process(InputRemoting Receiver, Message msg)
|
||||
{
|
||||
var senderIndex = Receiver.FindOrCreateSenderRecord(msg.participantId);
|
||||
var data = DeserializeData<Data>(msg.data);
|
||||
|
||||
var device = Receiver.TryGetDeviceByRemoteId(data.deviceId, senderIndex);
|
||||
if (device != null)
|
||||
{
|
||||
foreach (var deviceUsage in device.usages)
|
||||
{
|
||||
if (!data.usages.Contains(deviceUsage))
|
||||
Receiver.m_LocalManager.RemoveDeviceUsage(device, new InternedString(deviceUsage));
|
||||
}
|
||||
|
||||
if (data.usages.Length == 1)
|
||||
Receiver.m_LocalManager.AddDeviceUsage(device, new InternedString(data.usages[0]));
|
||||
foreach (var dataUsage in data.usages)
|
||||
{
|
||||
var internedDataUsage = new InternedString(dataUsage);
|
||||
if (!device.usages.Contains(internedDataUsage))
|
||||
Receiver.m_LocalManager.AddDeviceUsage(device, new InternedString(dataUsage));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class RemoveDeviceMsg
|
||||
{
|
||||
public static Message Create(InputDevice device)
|
||||
{
|
||||
return new Message
|
||||
{
|
||||
type = MessageType.RemoveDevice,
|
||||
data = BitConverter.GetBytes(device.deviceId)
|
||||
};
|
||||
}
|
||||
|
||||
public static void Process(InputRemoting Receiver, Message msg)
|
||||
{
|
||||
var senderIndex = Receiver.FindOrCreateSenderRecord(msg.participantId);
|
||||
var remoteDeviceId = BitConverter.ToInt32(msg.data, 0);
|
||||
|
||||
var device = Receiver.TryGetDeviceByRemoteId(remoteDeviceId, senderIndex);
|
||||
if (device != null)
|
||||
Receiver.m_LocalManager.RemoveDevice(device);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] SerializeData<TData>(TData data)
|
||||
{
|
||||
var json = JsonUtility.ToJson(data);
|
||||
return Encoding.UTF8.GetBytes(json);
|
||||
}
|
||||
|
||||
private static TData DeserializeData<TData>(byte[] data)
|
||||
{
|
||||
var json = Encoding.UTF8.GetString(data);
|
||||
return JsonUtility.FromJson<TData>(json);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
// State we want to take across domain reloads. We can only take some of the
|
||||
// state across. Subscriptions will be lost and have to be manually restored.
|
||||
[Serializable]
|
||||
internal struct SerializedState
|
||||
{
|
||||
public int senderId;
|
||||
public RemoteSender[] senders;
|
||||
|
||||
// We can't take these across domain reloads but we want to take them across
|
||||
// InputSystem.Save/Restore.
|
||||
[NonSerialized] public Subscriber[] subscribers;
|
||||
}
|
||||
|
||||
internal SerializedState SaveState()
|
||||
{
|
||||
return new SerializedState
|
||||
{
|
||||
senders = m_Senders,
|
||||
subscribers = m_Subscribers
|
||||
};
|
||||
}
|
||||
|
||||
internal void RestoreState(SerializedState state, IInputManager manager)
|
||||
{
|
||||
m_LocalManager = manager;
|
||||
m_Senders = state.senders;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
11
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/InputRemoting.cs.meta
vendored
Normal file
11
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/InputRemoting.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 90f809b07b8c64c4e99f2e64cfe0db92
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
45
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/MessageSerializer.cs
vendored
Normal file
45
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/MessageSerializer.cs
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Unity.RenderStreaming.InputSystem
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
static class MessageSerializer
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public static byte[] Serialize(ref InputRemoting.Message message)
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
var writer = new BinaryWriter(stream);
|
||||
|
||||
writer.Write(message.participantId);
|
||||
writer.Write((int)message.type);
|
||||
writer.Write(message.data.Length);
|
||||
writer.Write(message.data);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="bytes"></param>
|
||||
/// <param name="message"></param>
|
||||
public static void Deserialize(byte[] bytes, out InputRemoting.Message message)
|
||||
{
|
||||
var reader = new BinaryReader(new MemoryStream(bytes));
|
||||
|
||||
message = default;
|
||||
message.participantId = reader.ReadInt32();
|
||||
message.type = (InputRemoting.MessageType)reader.ReadInt32();
|
||||
int length = reader.ReadInt32();
|
||||
message.data = reader.ReadBytes(length);
|
||||
}
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7a1c240f9ad55b045884a8e8dc77358b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
211
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/Receiver.cs
vendored
Normal file
211
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/Receiver.cs
vendored
Normal file
@@ -0,0 +1,211 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Unity.WebRTC;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
using UnityEngine.InputSystem.Utilities;
|
||||
|
||||
namespace Unity.RenderStreaming.InputSystem
|
||||
{
|
||||
using InputSystem = UnityEngine.InputSystem.InputSystem;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
partial class Receiver : InputManager, IDisposable
|
||||
{
|
||||
public override event Action<InputRemoting.Message> onMessage;
|
||||
public new event Action<InputDevice, InputDeviceChange> onDeviceChange;
|
||||
public new event Action<string, InputControlLayoutChange> onLayoutChange;
|
||||
|
||||
private RTCDataChannel _channel;
|
||||
private readonly List<InputDevice> _remoteDevices = new List<InputDevice>();
|
||||
|
||||
private readonly Dictionary<string, string> _remoteLayouts = new Dictionary<string, string>();
|
||||
private readonly List<string> _registeredRemoteLayout = new List<string>();
|
||||
private InputPositionCorrector _corrector;
|
||||
private Action<InputEventPtr, InputDevice> _onEvent;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public bool EnableInputPositionCorrection { set; get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="channel"></param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override ReadOnlyArray<InputDevice> 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<InputDevice>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override IEnumerable<string> layouts
|
||||
{
|
||||
get
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public ReadOnlyArray<InputDevice> remoteDevices
|
||||
{
|
||||
get
|
||||
{
|
||||
return new ReadOnlyArray<InputDevice>(_remoteDevices.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
public ReadOnlyArray<string> remoteLayouts
|
||||
{
|
||||
get
|
||||
{
|
||||
return new ReadOnlyArray<string>(_remoteLayouts.Keys.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
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<StateEvent>())
|
||||
{
|
||||
_corrector.Invoke(ptr, device);
|
||||
}
|
||||
else
|
||||
{
|
||||
base.QueueEvent(ptr);
|
||||
}
|
||||
|
||||
// workaround:
|
||||
// UnityEngine.UI.InputField and TMP_InputField depends on Event.PopEvent.
|
||||
// Event.PopEvent is old event API, therefore EventSystem.QueueEvent doesn't queue events.
|
||||
var eventType = ptr.type;
|
||||
if (device is Keyboard &&
|
||||
(eventType == StateEvent.Type ||
|
||||
eventType == DeltaStateEvent.Type ||
|
||||
eventType == TextEvent.Type))
|
||||
{
|
||||
EmulateInputFieldEvent(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="size">Texture Size.</param>
|
||||
/// <param name="region">Region of the texture in world coordinate system.</param>
|
||||
public void CalculateInputRegion(Rect inputRegion, Rect outputRegion)
|
||||
{
|
||||
_corrector.inputRegion = inputRegion;
|
||||
_corrector.outputRegion = outputRegion;
|
||||
}
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
11
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/Receiver.cs.meta
vendored
Normal file
11
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/Receiver.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 834a3bd628e331943b599618b7309d1f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
109
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/Sender.cs
vendored
Normal file
109
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/Sender.cs
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.WebRTC;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
using UnityEngine.InputSystem.Utilities;
|
||||
|
||||
namespace Unity.RenderStreaming.InputSystem
|
||||
{
|
||||
using InputSystem = UnityEngine.InputSystem.InputSystem;
|
||||
|
||||
class Sender : InputManager, IDisposable
|
||||
{
|
||||
public override event Action<InputEventPtr, InputDevice> onEvent;
|
||||
public override event Action<InputDevice, InputDeviceChange> onDeviceChange;
|
||||
public override event Action<string, InputControlLayoutChange> onLayoutChange;
|
||||
|
||||
private InputPositionCorrector _corrector;
|
||||
private Action<InputEventPtr, InputDevice> _onEvent;
|
||||
|
||||
public Sender()
|
||||
{
|
||||
InputSystem.onEvent += OnEvent;
|
||||
InputSystem.onDeviceChange += OnDeviceChange;
|
||||
InputSystem.onLayoutChange += OnLayoutChange;
|
||||
|
||||
_onEvent = (InputEventPtr ptr, InputDevice device) => { onEvent?.Invoke(ptr, device); };
|
||||
_corrector = new InputPositionCorrector(_onEvent);
|
||||
}
|
||||
|
||||
~Sender()
|
||||
{
|
||||
this.Dispose();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
InputSystem.onEvent -= OnEvent;
|
||||
InputSystem.onDeviceChange -= OnDeviceChange;
|
||||
InputSystem.onLayoutChange -= OnLayoutChange;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public bool EnableInputPositionCorrection { set; get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="inputRegion"></param>
|
||||
/// <param name="outputRegion"></param>
|
||||
public void CalculateInputRegion(Rect inputRegion, Rect outputRegion)
|
||||
{
|
||||
_corrector.inputRegion = inputRegion;
|
||||
_corrector.outputRegion = outputRegion;
|
||||
}
|
||||
|
||||
private void OnEvent(InputEventPtr ptr, InputDevice device)
|
||||
{
|
||||
// mapping sender coordinate system to receiver one.
|
||||
if (EnableInputPositionCorrection && device is Pointer && ptr.IsA<StateEvent>())
|
||||
{
|
||||
_corrector.Invoke(ptr, device);
|
||||
}
|
||||
else
|
||||
{
|
||||
onEvent?.Invoke(ptr, device);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDeviceChange(InputDevice device, InputDeviceChange change)
|
||||
{
|
||||
onDeviceChange?.Invoke(device, change);
|
||||
}
|
||||
private void OnLayoutChange(string name, InputControlLayoutChange change)
|
||||
{
|
||||
onLayoutChange?.Invoke(name, change);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
class Observer : IObserver<InputRemoting.Message>
|
||||
{
|
||||
private RTCDataChannel _channel;
|
||||
public Observer(RTCDataChannel channel)
|
||||
{
|
||||
_channel = channel ?? throw new ArgumentNullException("channel is null");
|
||||
}
|
||||
public void OnNext(InputRemoting.Message value)
|
||||
{
|
||||
if (_channel.ReadyState != RTCDataChannelState.Open)
|
||||
return;
|
||||
byte[] bytes = MessageSerializer.Serialize(ref value);
|
||||
_channel.Send(bytes);
|
||||
}
|
||||
|
||||
public void OnCompleted()
|
||||
{
|
||||
}
|
||||
public void OnError(Exception error)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
11
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/Sender.cs.meta
vendored
Normal file
11
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/InputSystem/Sender.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ba4fd50aea9ff3459e460141a546b3c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user