Skip to content

Commit 932d4e4

Browse files
author
Rene Damm
authored
FIX: useStateFrom not working with injected controls (#1067).
1 parent 2a28665 commit 932d4e4

File tree

3 files changed

+97
-22
lines changed

3 files changed

+97
-22
lines changed

Assets/Tests/InputSystem/CoreTests_Layouts.cs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1369,6 +1369,60 @@ public void Layouts_CanAddChildControlToExistingControl()
13691369
Assert.That(device.leftStick["enabled"].parent, Is.SameAs(device.leftStick));
13701370
}
13711371

1372+
[Test]
1373+
[Category("Layouts")]
1374+
public void Layouts_CanAddChildControlToExistingControl_UsingStateFromOtherControl()
1375+
{
1376+
InputSystem.RegisterLayout(@"
1377+
{
1378+
""name"" : ""TestDevice"",
1379+
""controls"" : [
1380+
{ ""name"" : ""noise"", ""layout"" : ""Button"" },
1381+
{ ""name"" : ""scroll"", ""layout"" : ""Vector2"" },
1382+
{ ""name"" : ""scroll/up"", ""layout"" : ""Button"", ""useStateFrom"" : ""scroll/y"", ""parameters"" : ""clamp=1,clampMin=0,clampMax=99999"" },
1383+
{ ""name"" : ""scroll/down"", ""layout"" : ""Button"", ""useStateFrom"" : ""scroll/y"", ""parameters"" : ""clamp=1,clampMin=-99999,clampMax=0,invert"" },
1384+
{ ""name"" : ""scroll/left"", ""layout"" : ""Button"", ""useStateFrom"" : ""scroll/x"", ""parameters"" : ""clamp=1,clampMin=-99999,clampMax=0,invert"" },
1385+
{ ""name"" : ""scroll/right"", ""layout"" : ""Button"", ""useStateFrom"" : ""scroll/x"", ""parameters"" : ""clamp=1,clampMin=0,clampMax=99999"" }
1386+
]
1387+
}
1388+
");
1389+
1390+
var device = InputSystem.AddDevice("TestDevice");
1391+
var scroll = (Vector2Control)device["scroll"];
1392+
1393+
// Left.
1394+
Set(scroll, new Vector2(-123, 0));
1395+
1396+
Assert.That(device["scroll/up"].ReadValueAsObject(), Is.Zero);
1397+
Assert.That(device["scroll/down"].ReadValueAsObject(), Is.Zero);
1398+
Assert.That(device["scroll/left"].ReadValueAsObject(), Is.EqualTo(123).Within(0.00001));
1399+
Assert.That(device["scroll/right"].ReadValueAsObject(), Is.Zero);
1400+
1401+
// Right.
1402+
Set(scroll, new Vector2(234, 0));
1403+
1404+
Assert.That(device["scroll/up"].ReadValueAsObject(), Is.Zero);
1405+
Assert.That(device["scroll/down"].ReadValueAsObject(), Is.Zero);
1406+
Assert.That(device["scroll/left"].ReadValueAsObject(), Is.Zero);
1407+
Assert.That(device["scroll/right"].ReadValueAsObject(), Is.EqualTo(234).Within(0.00001));
1408+
1409+
// Up.
1410+
Set(scroll, new Vector2(0, 123));
1411+
1412+
Assert.That(device["scroll/up"].ReadValueAsObject(), Is.EqualTo(123).Within(0.00001));
1413+
Assert.That(device["scroll/down"].ReadValueAsObject(), Is.Zero);
1414+
Assert.That(device["scroll/left"].ReadValueAsObject(), Is.Zero);
1415+
Assert.That(device["scroll/right"].ReadValueAsObject(), Is.Zero);
1416+
1417+
// Down.
1418+
Set(scroll, new Vector2(0, -432));
1419+
1420+
Assert.That(device["scroll/up"].ReadValueAsObject(), Is.Zero);
1421+
Assert.That(device["scroll/down"].ReadValueAsObject(), Is.EqualTo(432).Within(0.00001));
1422+
Assert.That(device["scroll/left"].ReadValueAsObject(), Is.Zero);
1423+
Assert.That(device["scroll/right"].ReadValueAsObject(), Is.Zero);
1424+
}
1425+
13721426
[Test]
13731427
[Category("Layouts")]
13741428
[Ignore("TODO")]

Packages/com.unity.inputsystem/Documentation~/Touch.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* [`Touchscreen` Device](#touchscreen-device)
44
* [`Touch` class](#enhancedtouchtouch-class)
55
* [Using Touch with Actions](#using-touch-with-actionsactionsmd)
6+
* [Touch Simulation](#touch-simulation)
67

78
Touch support is divided into:
89
* low-level support implemented in the [`Touchscreen`](#touchscreen-device) class.
@@ -76,3 +77,18 @@ The [`EnhancedTouch.Touch`](../api/UnityEngine.InputSystem.EnhancedTouch.Touch.h
7677
See [`EnhancedTouch.Touch` API documentation](../api/UnityEngine.InputSystem.EnhancedTouch.Touch.html) for more details.
7778

7879
>__Note__: The [`Touch`](../api/UnityEngine.InputSystem.EnhancedTouch.Touch.html) and [`Finger`](../api/UnityEngine.InputSystem.EnhancedTouch.Finger.html) APIs don't generate GC garbage. The bulk of the data is stored in unmanaged memory that is indexed by wrapper structs. All arrays are pre-allocated.
80+
81+
## Touch Simulation
82+
83+
Touch input can be simulated from input on other kinds of [Pointer](./Pointers.md) devices such as [Mouse](./Mouse.md) and [Pen](./Pen.md) devices. To enable this, you can either add the [`TouchSimulation`](../api/UnityEngine.InputSystem.EnhancedTouch.TouchSimulation.html) `MonoBehaviour` to a `GameObject` in your scene or simply call [`TouchSimulation.Enable`](../api/UnityEngine.InputSystem.EnhancedTouch.TouchSimulation.html#UnityEngine_InputSystem_EnhancedTouch_TouchSimulation_Enable) somewhere in your startup code.
84+
85+
```CSharp
86+
void OnEnable()
87+
{
88+
TouchSimulation.Enable();
89+
}
90+
```
91+
92+
In the editor, you can also enable touch simulation by toggling "Simulate Touch Input From Mouse or Pen" on in the "Options" dropdown of the [Input Debugger](./Debugging.md).
93+
94+
[`TouchSimulation`](../api/UnityEngine.InputSystem.EnhancedTouch.TouchSimulation.html) will add a [`Touchscreen`](../api/UnityEngine.InputSystem.Touchscreen.html) device and automatically mirror input on any [`Pointer`](../api/UnityEngine.InputSystem.Pointer.html) device to the virtual touchscreen device.

Packages/com.unity.inputsystem/InputSystem/Devices/InputDeviceBuilder.cs

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717
////TODO: ensure that things are aligned properly for ARM; should that be done on the reading side or in the state layouts?
1818
//// (make sure that alignment works the same on *all* platforms; otherwise editor will not be able to process events from players properly)
1919

20-
////FIXME: looks like `useStateFrom` is not working properly in combination with isModifyingExistingControl
21-
2220
namespace UnityEngine.InputSystem.Layouts
2321
{
2422
/// <summary>
@@ -202,28 +200,13 @@ private InputControl InstantiateLayout(InputControlLayout layout, InternedString
202200
// controls, assign them their blocks now.
203201
if (haveChildrenUsingStateFromOtherControl)
204202
{
205-
foreach (var controlLayout in layout.controls)
203+
var controls = layout.m_Controls;
204+
for (var i = 0; i < controls.Length; ++i)
206205
{
207-
if (string.IsNullOrEmpty(controlLayout.useStateFrom))
206+
ref var item = ref controls[i];
207+
if (string.IsNullOrEmpty(item.useStateFrom))
208208
continue;
209-
210-
var child = InputControlPath.TryFindChild(control, controlLayout.name);
211-
Debug.Assert(child != null, "Could not find child control which should be present at this point");
212-
213-
// Find the referenced control.
214-
var referencedControl = InputControlPath.TryFindChild(control, controlLayout.useStateFrom);
215-
if (referencedControl == null)
216-
throw new InvalidOperationException(
217-
$"Cannot find control '{controlLayout.useStateFrom}' referenced in 'useStateFrom' of control '{controlLayout.name}' in layout '{layout.name}'");
218-
219-
// Copy its state settings.
220-
child.m_StateBlock = referencedControl.m_StateBlock;
221-
222-
// At this point, all byteOffsets are relative to parents so we need to
223-
// walk up the referenced control's parent chain and add offsets until
224-
// we are at the same level that we are at.
225-
for (var parentInChain = referencedControl.parent; parentInChain != control; parentInChain = parentInChain.parent)
226-
child.m_StateBlock.byteOffset += parentInChain.m_StateBlock.byteOffset;
209+
ApplyUseStateFrom(control, ref item, layout);
227210
}
228211
}
229212

@@ -574,6 +557,28 @@ private InputControl InsertChildControl(InputControlLayout layout, InternedStrin
574557
return control;
575558
}
576559

560+
private static void ApplyUseStateFrom(InputControl parent, ref InputControlLayout.ControlItem controlItem, InputControlLayout layout)
561+
{
562+
var child = InputControlPath.TryFindChild(parent, controlItem.name);
563+
Debug.Assert(child != null, "Could not find child control which should be present at this point");
564+
565+
// Find the referenced control.
566+
var referencedControl = InputControlPath.TryFindChild(parent, controlItem.useStateFrom);
567+
if (referencedControl == null)
568+
throw new InvalidOperationException(
569+
$"Cannot find control '{controlItem.useStateFrom}' referenced in 'useStateFrom' of control '{controlItem.name}' in layout '{layout.name}'");
570+
571+
// Copy its state settings.
572+
child.m_StateBlock = referencedControl.m_StateBlock;
573+
574+
// At this point, all byteOffsets are relative to parents so we need to
575+
// walk up the referenced control's parent chain and add offsets until
576+
// we are at the same level that we are at.
577+
if (child.parent != referencedControl.parent)
578+
for (var parentInChain = referencedControl.parent; parentInChain != parent; parentInChain = parentInChain.parent)
579+
child.m_StateBlock.byteOffset += parentInChain.m_StateBlock.byteOffset;
580+
}
581+
577582
private static void ShiftChildIndicesInHierarchyOneUp(InputDevice device, int startIndex, InputControl exceptControl)
578583
{
579584
var controls = device.m_ChildrenForEachControl;

0 commit comments

Comments
 (0)