Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions Assets/Tests/InputSystem/Plugins/XRTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1222,6 +1222,52 @@ public void Controls_OptimizedControls_PoseControl_IsOptimized()
Assert.That((device["posecontrol"] as PoseControl).optimizedControlDataType, Is.EqualTo(InputStateBlock.FormatPose));
}

[Test]
[Category("Controls")]
[TestCase(true)]
[TestCase(false)]
public void Controls_PoseControl_IsTracked_ReadsCorrectly(bool useOptimizedControls)
{
InputSystem.settings.SetInternalFeatureFlag(InputFeatureNames.kUseOptimizedControls, useOptimizedControls);

runtime.ReportNewInputDevice(PoseDeviceState.CreateDeviceDescription().ToJson());

InputSystem.Update();

var device = InputSystem.devices[0];
var poseControl = device["posecontrol"] as PoseControl;

// Queue state with isTracked = true (byte value 1)
InputSystem.QueueStateEvent(device, new PoseDeviceState
{
isTracked = 1,
trackingState = (uint)(InputTrackingState.Position | InputTrackingState.Rotation),
position = new Vector3(1, 2, 3),
rotation = Quaternion.identity,
});
InputSystem.Update();

// Reading isTracked as a ButtonControl should return true
Assert.That(poseControl.isTracked.isPressed, Is.True, "isTracked.isPressed should be true when tracked");
Assert.That(poseControl.isTracked.ReadValue(), Is.EqualTo(1.0f).Within(0.001f), "isTracked.ReadValue() should be 1.0f when tracked");

// Reading the full PoseState should also have isTracked = true
var poseState = poseControl.ReadValue();
Assert.That(poseState.isTracked, Is.True, "PoseState.isTracked should be true when tracked");

// Queue state with isTracked = false (byte value 0)
InputSystem.QueueStateEvent(device, new PoseDeviceState
{
isTracked = 0,
trackingState = 0,
});
InputSystem.Update();

Assert.That(poseControl.isTracked.isPressed, Is.False, "isTracked.isPressed should be false when not tracked");
Assert.That(poseControl.isTracked.ReadValue(), Is.EqualTo(0.0f).Within(0.001f), "isTracked.ReadValue() should be 0.0f when not tracked");
Assert.That(poseControl.ReadValue().isTracked, Is.False, "PoseState.isTracked should be false when not tracked");
}

// ISXB-405
[Test]
[Category("Devices")]
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 @@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Fixed an incorrect ArraysHelper.HaveDuplicateReferences implementation that didn't use its arguments right [ISXB-1792] (https://github.com/Unity-Technologies/InputSystem/pull/2376)
- Fixed `InputAction.IsPressed`, `WasPressedThisFrame`, and `WasReleasedThisFrame` using a `ButtonControl`'s `pressPoint` when a binding also had an explicit `PressInteraction` with its own `pressPoint`, which could make those APIs disagree with the interaction's press and release behavior. Action-level press APIs now follow the interaction threshold when both are set explicitly.
- Fixed `IndexOutOfRangeException` in `InputDeviceBuilder` when connecting an HID gamepad whose report descriptor declares a hat switch with Report Size 8 (e.g. ESP32-BLE-Gamepad). The HID layer now anchors the hat's directional sub-controls to the hat's own byte instead of letting the layout system auto-allocate a fresh byte for each [UUM-143659](https://jira.unity3d.com/browse/UUM-143659).
- Fixed `PoseControl.isTracked` always returning false when read through non-optimized code paths (e.g. Input Debugger) due to `sizeInBits = 8` causing the bool value to be normalized as `1/255` instead of `1.0`.

### Changed
- Action-level `IsPressed`, `WasPressedThisFrame`, and `WasReleasedThisFrame` for bindings to `Vector2Control` / `StickControl` no longer consult a per-control `pressPoint` on the vector (that field was removed). Use a `Press` interaction to set a custom threshold, or rely on `defaultButtonPressPoint`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public PoseState(bool isTracked, TrackingState trackingState, Vector3 position,
/// <remarks>
/// Fully tracked means that the pose is accurate and not using any simulated or extrapolated positions, and the system tracking this pose is able to confidently track this object.
/// </remarks>
[FieldOffset(0), InputControl(displayName = "Is Tracked", layout = "Button", sizeInBits = 8 /* needed to ensure optimization kicks-in */)]
[FieldOffset(0), InputControl(displayName = "Is Tracked", layout = "Button", sizeInBits = 1)]
public bool isTracked;

/// <summary>
Expand Down Expand Up @@ -252,7 +252,8 @@ protected override FourCC CalculateOptimizedControlDataType()
if (
m_StateBlock.sizeInBits == PoseState.kSizeInBytes * 8 &&
m_StateBlock.bitOffset == 0 &&
isTracked.optimizedControlDataType == InputStateBlock.kFormatByte &&
isTracked.m_StateBlock.format == InputStateBlock.kFormatBit &&

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2

This weakens the safety check for the kFormatPose fast path. Before this change, isTracked.optimizedControlDataType == InputStateBlock.kFormatByte only succeeded when AxisControl had no extra processing and the state was byte-aligned; now we only check the raw state block shape. That means an overridden Pose layout can set isTracked parameters such as invert, normalize, scale, clamp, or even a non-zero bitOffset, and PoseControl will still return kFormatPose. In that case PoseControl.ReadValue() / WriteValueIntoState() will raw-copy PoseState and bypass the child ButtonControl semantics, so poseControl.ReadValue().isTracked can disagree with poseControl.isTracked.ReadValue(). Please reintroduce the old semantic guard explicitly here (at least bitOffset == 0 and no AxisControl preprocessing on isTracked) before enabling the struct fast path.

🤖 Helpful? 👍/👎

isTracked.m_StateBlock.sizeInBits == 1 &&
trackingState.optimizedControlDataType == InputStateBlock.kFormatInt &&
position.optimizedControlDataType == InputStateBlock.kFormatVector3 &&
rotation.optimizedControlDataType == InputStateBlock.kFormatQuaternion &&
Expand Down
Loading