Skip to content
Merged
14 changes: 14 additions & 0 deletions Assets/Tests/InputSystem/CoreTests_Controls.cs
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,20 @@ public void Controls_CanFindControlsByUsage()
}
}

[Test]
[Category("Controls")]
public void Controls_FindingControlsByUsage_IgnoresUsagesOnDevice()
{
var gamepad = InputSystem.AddDevice<Gamepad>();
InputSystem.SetDeviceUsage(gamepad, "Primary2DMotion");

using (var matches = InputSystem.FindControls("<Gamepad>/{Primary2DMotion}"))
{
Assert.That(matches, Has.Count.EqualTo(1));
Assert.That(matches, Has.Exactly(1).SameAs(gamepad.leftStick));
}
}

[Test]
[Category("Controls")]
public void Controls_CanFindChildControlsOfControlsFoundByUsage()
Expand Down
1 change: 1 addition & 0 deletions Packages/com.unity.inputsystem/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ This release includes a number of Quality-of-Life improvements for a range of co
* This bug led to input being missed on a device once another device had been removed.
- `TrackedDevice` layout is no longer incorrectly registered as `Tracked Device`.
- Event traces in the input debugger are no longer lost on domain reloads.
- `IndexOutOfRangeException` being thrown when looking up controls on XR devices.

#### Actions

Expand Down
21 changes: 21 additions & 0 deletions Packages/com.unity.inputsystem/Documentation~/KnownLimitations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Known Limitations

The following is a list of known limitations that the Input System currently has.

## Compatibility with other Unity features

* `PlayerInput` split-screen support does not work with Cinemachine virtual cameras.
* The Input System cannot generate input for IMGUI or UIElements.
* The Input System does not yet support the new 2019.3 mode where domain reloads are disabled when entering play mode.

## Device support

* (Windows) Mouse input from remote desktop connections does not come through properly.
* (Windows) Pen input will not work with Wacom devices if "Windows Ink" support is turned off.
* Joy-Cons are only supported on Switch.
* Sensors in the PS4 controller are currently only supported on PS4.
>NOTE: Support for NDA platforms is distributed as separate packages due to licensing restrictions. The packages, at this point, are made available separately to licensees for download and installation.

## Features Supported by Old Input Manager

* `MonoBehaviour` mouse methods (`OnMouseEnter`, `OnMouseDrag`, etc) will not be called by the Input System.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* [Debugging](Debugging.md)
* [Input testing](Testing.md)
* [Contributing](Contributing.md)
* [Known Limitations](KnownLimitations.md)

* Reference
* [Input settings](Settings.md)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -925,7 +925,7 @@ private static TControl MatchByUsageAtDeviceRootRecursive<TControl>(InputDevice
if (usages == null)
return null;

var usageCount = usages.Length;
var usageCount = device.m_UsageToControl.Length;
var startIndex = indexInPath + 1;
var pathCanMatchMultiple = PathComponentCanYieldMultipleMatches(path, indexInPath);
var pathLength = path.Length;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -909,7 +909,7 @@ public event Action<char> onTextInput
{
if (value == null)
throw new ArgumentNullException(nameof(value));
if (!m_TextInputListeners.ContainsReference(value))
if (!m_TextInputListeners.Contains(value))
m_TextInputListeners.Append(value);
}
remove => m_TextInputListeners.Remove(value);
Expand All @@ -931,7 +931,7 @@ public event Action<IMECompositionString> onIMECompositionChange
{
if (value == null)
throw new ArgumentNullException(nameof(value));
if (!m_ImeCompositionListeners.ContainsReference(value))
if (!m_ImeCompositionListeners.Contains(value))
m_ImeCompositionListeners.Append(value);
}
remove => m_ImeCompositionListeners.Remove(value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@

////TODO: add diff-to-previous-event ability to event window

////FIXME: doesn't survive domain reload correctly (could be, it's even leaking unmanaged memory)

////FIXME: the repaint triggered from IInputStateCallbackReceiver somehow comes with a significant delay

////TODO: Add "Remote:" field in list that also has a button for local devices that allows to mirror them and their input
Expand All @@ -39,7 +37,7 @@ namespace UnityEngine.InputSystem.Editor
// Can also be used to alter the state of a device by making up state events.
internal sealed class InputDeviceDebuggerWindow : EditorWindow, ISerializationCallbackReceiver, IDisposable
{
internal const int kDefaultEventTraceSizeInMB = 1;
private const int kDefaultEventTraceSizeInMB = 1;

internal static InlinedArray<Action<InputDevice>> s_OnToolbarGUIActions;

Expand Down Expand Up @@ -90,11 +88,15 @@ internal void OnDestroy()

m_EventTrace?.Dispose();
m_EventTrace = null;

m_ReplayController?.Dispose();
m_ReplayController = null;
}

public void Dispose()
{
m_EventTrace?.Dispose();
m_ReplayController?.Dispose();
}

internal void OnGUI()
Expand Down Expand Up @@ -179,6 +181,9 @@ private void DrawEventList()
GUILayout.Label("Events", GUILayout.MinWidth(100), GUILayout.ExpandWidth(true));
GUILayout.FlexibleSpace();

if (m_ReplayController != null && !m_ReplayController.finished)
EditorGUILayout.LabelField("Playing...", EditorStyles.miniLabel);

// Text field to determine size of event trace.
var currentTraceSizeInBytes = m_EventTrace.allocatedSizeInBytes / (1024 * 1024);
var oldSizeText = currentTraceSizeInBytes + " MB";
Expand All @@ -194,14 +199,18 @@ private void DrawEventList()
}

// Button to disable event tracing.
var eventTraceDisabledNow = GUILayout.Toggle(!m_EventTraceDisabled, Contents.pauseContent, Styles.toolbarButton);
if (eventTraceDisabledNow != m_EventTraceDisabled)
// NOTE: We force-disable event tracing while a replay is in progress.
using (new EditorGUI.DisabledScope(m_ReplayController != null && !m_ReplayController.finished))
{
m_EventTraceDisabled = eventTraceDisabledNow;
if (eventTraceDisabledNow)
m_EventTrace.Disable();
else
m_EventTrace.Enable();
var eventTraceDisabledNow = GUILayout.Toggle(!m_EventTraceDisabled, Contents.pauseContent, Styles.toolbarButton);
if (eventTraceDisabledNow != m_EventTraceDisabled)
{
m_EventTraceDisabled = eventTraceDisabledNow;
if (eventTraceDisabledNow)
m_EventTrace.Disable();
else
m_EventTrace.Enable();
}
}

// Button to toggle recording of frame markers.
Expand All @@ -223,11 +232,28 @@ private void DrawEventList()
var fileName = EditorUtility.OpenFilePanel("Choose event trace to load", string.Empty, "inputtrace");
if (!string.IsNullOrEmpty(fileName))
{
// If replay is in progress, stop it.
if (m_ReplayController != null)
{
m_ReplayController.Dispose();
m_ReplayController = null;
}

// Make sure event trace isn't recording while we're playing.
m_EventTrace.Disable();
m_EventTraceDisabled = true;

m_EventTrace.ReadFrom(fileName);
m_EventTree.Reload();
m_EventTrace.Replay().PlayAllFramesOneByOne();

m_ReplayController = m_EventTrace.Replay()
.PlayAllFramesOneByOne()
.OnFinished(() =>
{
m_ReplayController.Dispose();
m_ReplayController = null;
Repaint();
});
}
}

Expand Down Expand Up @@ -301,21 +327,22 @@ private void RefreshControlTreeValues()
// We will lose our device on domain reload and then look it back up the first
// time we hit a repaint after a reload. By that time, the input system should have
// fully come back to life as well.
[NonSerialized] private InputDevice m_Device;
[NonSerialized] private string m_DeviceIdString;
[NonSerialized] private string m_DeviceUsagesString;
[NonSerialized] private string m_DeviceFlagsString;
[NonSerialized] private InputControlTreeView m_ControlTree;
[NonSerialized] private InputEventTreeView m_EventTree;
[NonSerialized] private bool m_NeedControlValueRefresh;
private InputDevice m_Device;
private string m_DeviceIdString;
private string m_DeviceUsagesString;
private string m_DeviceFlagsString;
private InputControlTreeView m_ControlTree;
private InputEventTreeView m_EventTree;
private bool m_NeedControlValueRefresh;
private InputEventTrace.ReplayController m_ReplayController;
private InputEventTrace m_EventTrace;

[SerializeField] private int m_DeviceId = InputDevice.InvalidDeviceId;
[SerializeField] private TreeViewState m_ControlTreeState;
[SerializeField] private TreeViewState m_EventTreeState;
[SerializeField] private MultiColumnHeaderState m_ControlTreeHeaderState;
[SerializeField] private MultiColumnHeaderState m_EventTreeHeaderState;
[SerializeField] private Vector2 m_ControlTreeScrollPosition;
[SerializeField] private InputEventTrace m_EventTrace;
[SerializeField] private bool m_EventTraceDisabled;

private static List<InputDeviceDebuggerWindow> s_OpenDebuggerWindows;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine.InputSystem.LowLevel;
using UnityEngine.InputSystem.Utilities;
using UnityEditor.IMGUI.Controls;
using UnityEngine.Profiling;

////TODO: switch to ReadValueFromState (the current value reading code dates back to very early versions of the input system)
//// (note that doing so will have an impact on mouse coordinates which then will go through EditorWindowSpaceProcessor)

////TODO: make control values editable (create state events from UI and pump them into the system)

////TODO: show processors attached to controls
Expand Down Expand Up @@ -319,71 +314,8 @@ private unsafe string ReadRawValueAsString(InputControl control, byte[] state)
{
fixed(byte* statePtr = state)
{
var ptr = statePtr + control.m_StateBlock.byteOffset - m_RootControl.m_StateBlock.byteOffset;
var format = control.m_StateBlock.format;

object value = null;
if (format == InputStateBlock.FormatBit)
{
if (control.valueSizeInBytes == 1)
{
value = MemoryHelpers.ReadSingleBit(ptr, control.m_StateBlock.bitOffset) ? "1" : "0";
}
else
{
value = MemoryHelpers.ReadIntFromMultipleBits(ptr, control.m_StateBlock.bitOffset, control.m_StateBlock.sizeInBits);
}
}
else if (format == InputStateBlock.FormatSBit)
{
if (control.valueSizeInBytes == 1)
{
value = MemoryHelpers.ReadSingleBit(ptr, control.m_StateBlock.bitOffset) ? "1" : "-1";
}
else
{
var halfMaxValue = ((1 << (int)control.m_StateBlock.sizeInBits) - 1) / 2;
var fullValue = (MemoryHelpers.ReadIntFromMultipleBits(ptr, control.m_StateBlock.bitOffset, control.m_StateBlock.sizeInBits));
value = fullValue - halfMaxValue;
}
}
else if (format == InputStateBlock.FormatByte || format == InputStateBlock.FormatSByte)
{
value = *ptr;
}
else if (format == InputStateBlock.FormatShort)
{
value = *(short*)ptr;
}
else if (format == InputStateBlock.FormatUShort)
{
value = *(ushort*)ptr;
}
else if (format == InputStateBlock.FormatInt)
{
value = *(int*)ptr;
}
else if (format == InputStateBlock.FormatUInt)
{
value = *(uint*)ptr;
}
else if (format == InputStateBlock.FormatFloat)
{
value = *(float*)ptr;
}
else if (format == InputStateBlock.FormatDouble)
{
value = *(double*)ptr;
}

// Stringify enum values, for. ex., TouchPhase
if (value != null && control.valueType.IsEnum)
{
var intValue = Convert.ToInt32(value);
value = Enum.ToObject(control.valueType, intValue);
}

return value?.ToString();
var ptr = statePtr - m_RootControl.m_StateBlock.byteOffset;
return control.ReadValueFromStateAsObject(ptr).ToString();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

////TODO: add diagnostics to immediately highlight problems with events (e.g. events getting ignored because of incorrect type codes)

////TODO: implement support for sorting data by different property collumns (we currently always sort events by ID)
////TODO: implement support for sorting data by different property columns (we currently always sort events by ID)

namespace UnityEngine.InputSystem.Editor
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ public void InitializeWithEvent(InputEventPtr eventPtr, InputControl control)
m_StateBuffers = new byte[1][];
m_StateBuffers[0] = GetEventStateBuffer(eventPtr, control);
m_SelectedStateBuffer = 0;

titleContent = new GUIContent(control.displayName);
}

public void InitializeWithEvents(InputEventPtr[] eventPtrs, InputControl control)
Expand All @@ -49,6 +51,8 @@ public void InitializeWithEvents(InputEventPtr[] eventPtrs, InputControl control
m_StateBuffers[i] = GetEventStateBuffer(eventPtrs[i], control);
m_CompareStateBuffers = true;
m_ShowDifferentOnly = true;

titleContent = new GUIContent(control.displayName);
}

private unsafe byte[] GetEventStateBuffer(InputEventPtr eventPtr, InputControl control)
Expand Down Expand Up @@ -124,6 +128,8 @@ public unsafe void InitializeWithControl(InputControl control)

m_BufferChoices = bufferChoices.ToArray();
m_BufferChoiceValues = bufferChoiceValues.ToArray();

titleContent = new GUIContent(control.displayName);
}

private static unsafe void* TryGetDeviceState(InputDevice device, BufferSelector selector)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ public event Action<InputEventPtr> onEvent
{
add
{
if (!m_EventListeners.ContainsReference(value))
if (!m_EventListeners.Contains(value))
m_EventListeners.Append(value);
}
remove => m_EventListeners.Remove(value);
Expand Down
12 changes: 6 additions & 6 deletions Packages/com.unity.inputsystem/InputSystem/InputManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ public event EventListener onEvent
{
add
{
if (!m_EventListeners.ContainsReference(value))
if (!m_EventListeners.Contains(value))
m_EventListeners.AppendWithCapacity(value);
}
remove
Expand All @@ -254,7 +254,7 @@ public event UpdateListener onBeforeUpdate
add
{
InstallBeforeUpdateHookIfNecessary();
if (!m_BeforeUpdateListeners.ContainsReference(value))
if (!m_BeforeUpdateListeners.Contains(value))
m_BeforeUpdateListeners.AppendWithCapacity(value);
}
remove
Expand All @@ -269,7 +269,7 @@ public event UpdateListener onAfterUpdate
{
add
{
if (!m_AfterUpdateListeners.ContainsReference(value))
if (!m_AfterUpdateListeners.Contains(value))
m_AfterUpdateListeners.AppendWithCapacity(value);
}
remove
Expand All @@ -284,7 +284,7 @@ public event Action onSettingsChange
{
add
{
if (!m_SettingsChangedListeners.ContainsReference(value))
if (!m_SettingsChangedListeners.Contains(value))
m_SettingsChangedListeners.AppendWithCapacity(value);
}
remove
Expand Down Expand Up @@ -1183,8 +1183,8 @@ public void RemoveDevice(InputDevice device, bool keepOnListOfAvailableDevices =
var deviceId = device.deviceId;
if (deviceIndex < m_StateChangeMonitors.LengthSafe())
{
// m_StateChangeMonitors mirrors layout of m_Devices.
var count = m_DevicesCount;
// m_StateChangeMonitors mirrors layout of m_Devices *but* may be shorter.
var count = m_StateChangeMonitors.Length;
ArrayHelpers.EraseAtWithCapacity(m_StateChangeMonitors, ref count, deviceIndex);
}
ArrayHelpers.EraseAtWithCapacity(m_Devices, ref m_DevicesCount, deviceIndex);
Expand Down
Loading