From 40aaca811ec0f875d106100e096434e1b67a6081 Mon Sep 17 00:00:00 2001 From: kevin-zakszewski <99926647+kevin-zakszewski@users.noreply.github.com> Date: Thu, 2 Jul 2026 15:26:09 -0700 Subject: [PATCH 1/7] Fix pose isTracked incorrectly returning 0 --- .../InputSystem/Runtime/Plugins/XR/Controls/PoseControl.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Plugins/XR/Controls/PoseControl.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Plugins/XR/Controls/PoseControl.cs index db4881f631..9d82700a83 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Plugins/XR/Controls/PoseControl.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Plugins/XR/Controls/PoseControl.cs @@ -60,7 +60,7 @@ public PoseState(bool isTracked, TrackingState trackingState, Vector3 position, /// /// 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. /// - [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; /// @@ -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 && + isTracked.m_StateBlock.sizeInBits == 1 && trackingState.optimizedControlDataType == InputStateBlock.kFormatInt && position.optimizedControlDataType == InputStateBlock.kFormatVector3 && rotation.optimizedControlDataType == InputStateBlock.kFormatQuaternion && From 36ec9b9afc2d7b07f18d65942f02a24a530677f2 Mon Sep 17 00:00:00 2001 From: kevin-zakszewski <99926647+kevin-zakszewski@users.noreply.github.com> Date: Thu, 2 Jul 2026 15:27:32 -0700 Subject: [PATCH 2/7] Adding test for pose is tracked fix --- Assets/Tests/InputSystem/Plugins/XRTests.cs | 46 +++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/Assets/Tests/InputSystem/Plugins/XRTests.cs b/Assets/Tests/InputSystem/Plugins/XRTests.cs index 6f0e9cd1fd..b67fd13ffa 100644 --- a/Assets/Tests/InputSystem/Plugins/XRTests.cs +++ b/Assets/Tests/InputSystem/Plugins/XRTests.cs @@ -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")] From 1fdc5db449d9dabb5ce94a3148ea99bebdaafaee Mon Sep 17 00:00:00 2001 From: kevin-zakszewski <99926647+kevin-zakszewski@users.noreply.github.com> Date: Thu, 2 Jul 2026 15:42:56 -0700 Subject: [PATCH 3/7] Changelog --- Packages/com.unity.inputsystem/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Packages/com.unity.inputsystem/CHANGELOG.md b/Packages/com.unity.inputsystem/CHANGELOG.md index 73b3864462..ac9ae472b5 100644 --- a/Packages/com.unity.inputsystem/CHANGELOG.md +++ b/Packages/com.unity.inputsystem/CHANGELOG.md @@ -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`. From 7bdfc9687c2e0a51ed6ebe7329eed8f057bd6a25 Mon Sep 17 00:00:00 2001 From: kevin-zakszewski <99926647+kevin-zakszewski@users.noreply.github.com> Date: Mon, 6 Jul 2026 12:26:27 -0700 Subject: [PATCH 4/7] Add explicit AxisControl preprocessing guards to PoseControl optimization check --- .../InputSystem/Runtime/Plugins/XR/Controls/PoseControl.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Plugins/XR/Controls/PoseControl.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Plugins/XR/Controls/PoseControl.cs index 9d82700a83..2dee049ace 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Plugins/XR/Controls/PoseControl.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Plugins/XR/Controls/PoseControl.cs @@ -254,6 +254,11 @@ protected override FourCC CalculateOptimizedControlDataType() m_StateBlock.bitOffset == 0 && isTracked.m_StateBlock.format == InputStateBlock.kFormatBit && isTracked.m_StateBlock.sizeInBits == 1 && + isTracked.m_StateBlock.bitOffset == 0 && + isTracked.clamp == AxisControl.Clamp.None && + isTracked.invert == false && + isTracked.normalize == false && + isTracked.scale == false && trackingState.optimizedControlDataType == InputStateBlock.kFormatInt && position.optimizedControlDataType == InputStateBlock.kFormatVector3 && rotation.optimizedControlDataType == InputStateBlock.kFormatQuaternion && From a9edd02ac3d093ea2775c35cb60a24b97a07692c Mon Sep 17 00:00:00 2001 From: kevin-zakszewski <99926647+kevin-zakszewski@users.noreply.github.com> Date: Thu, 9 Jul 2026 14:33:36 -0700 Subject: [PATCH 5/7] Add optimization to ButtonControl Also updates the mouse test that I believe would be impacted by the change. --- Assets/Tests/InputSystem/CoreTests_Controls.cs | 2 +- .../InputSystem/Runtime/Controls/ButtonControl.cs | 14 ++++++++++++++ .../Runtime/Plugins/XR/Controls/PoseControl.cs | 8 +------- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Assets/Tests/InputSystem/CoreTests_Controls.cs b/Assets/Tests/InputSystem/CoreTests_Controls.cs index 9776706bff..ee0d8d21df 100644 --- a/Assets/Tests/InputSystem/CoreTests_Controls.cs +++ b/Assets/Tests/InputSystem/CoreTests_Controls.cs @@ -1428,7 +1428,7 @@ public void Controls_OptimizedControls_TrivialControlsAreOptimized() Assert.That(mouse.position.x.optimizedControlDataType, Is.EqualTo(InputStateBlock.FormatFloat)); Assert.That(mouse.position.y.optimizedControlDataType, Is.EqualTo(InputStateBlock.FormatFloat)); Assert.That(mouse.position.optimizedControlDataType, Is.EqualTo(InputStateBlock.FormatVector2)); - Assert.That(mouse.leftButton.optimizedControlDataType, Is.EqualTo(InputStateBlock.FormatInvalid)); + Assert.That(mouse.leftButton.optimizedControlDataType, Is.EqualTo(InputStateBlock.FormatBit)); InputSystem.settings.SetInternalFeatureFlag(InputFeatureNames.kUseOptimizedControls, false); Assert.That(mouse.position.x.optimizedControlDataType, Is.EqualTo(InputStateBlock.FormatInvalid)); diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/ButtonControl.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/ButtonControl.cs index 1b729b3d84..793250bd4d 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/ButtonControl.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/ButtonControl.cs @@ -378,6 +378,20 @@ internal void UpdateWasPressedEditor() #endif // UNITY_EDITOR + protected override FourCC CalculateOptimizedControlDataType() + { + if (clamp == Clamp.None && + invert == false && + normalize == false && + scale == false && + m_StateBlock.format == InputStateBlock.FormatBit && + m_StateBlock.sizeInBits == 1 && + m_StateBlock.bitOffset == 0) + return InputStateBlock.FormatBit; + + return base.CalculateOptimizedControlDataType(); + } + // We make the current global default button press point available as a static so that we don't have to // constantly make the hop from InputSystem.settings -> InputManager.m_Settings -> defaultButtonPressPoint. internal static float s_GlobalDefaultButtonPressPoint; diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Plugins/XR/Controls/PoseControl.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Plugins/XR/Controls/PoseControl.cs index 2dee049ace..0fd8b43dbc 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Plugins/XR/Controls/PoseControl.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Plugins/XR/Controls/PoseControl.cs @@ -252,13 +252,7 @@ protected override FourCC CalculateOptimizedControlDataType() if ( m_StateBlock.sizeInBits == PoseState.kSizeInBytes * 8 && m_StateBlock.bitOffset == 0 && - isTracked.m_StateBlock.format == InputStateBlock.kFormatBit && - isTracked.m_StateBlock.sizeInBits == 1 && - isTracked.m_StateBlock.bitOffset == 0 && - isTracked.clamp == AxisControl.Clamp.None && - isTracked.invert == false && - isTracked.normalize == false && - isTracked.scale == false && + isTracked.optimizedControlDataType == InputStateBlock.kFormatBit && trackingState.optimizedControlDataType == InputStateBlock.kFormatInt && position.optimizedControlDataType == InputStateBlock.kFormatVector3 && rotation.optimizedControlDataType == InputStateBlock.kFormatQuaternion && From 963622549639a80fde6c0b80d1164417b016e36a Mon Sep 17 00:00:00 2001 From: Chris Massie Date: Thu, 9 Jul 2026 17:59:17 -0700 Subject: [PATCH 6/7] Fixed missing `using` for `FourCC` in method declaration --- .../InputSystem/Runtime/Controls/AxisControl.cs | 1 + .../InputSystem/Runtime/Controls/ButtonControl.cs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/AxisControl.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/AxisControl.cs index d584108efc..021fb1ec99 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/AxisControl.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/AxisControl.cs @@ -310,6 +310,7 @@ private float EvaluateMagnitude(float value) return NormalizeProcessor.Normalize(clampedValue, min, max, 0); } + /// protected override FourCC CalculateOptimizedControlDataType() { var noProcessingNeeded = diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/ButtonControl.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/ButtonControl.cs index 793250bd4d..bb5ad0f9bc 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/ButtonControl.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Controls/ButtonControl.cs @@ -1,6 +1,7 @@ using System; using System.Runtime.CompilerServices; using UnityEngine.InputSystem.LowLevel; +using UnityEngine.InputSystem.Utilities; using UnityEngine.Scripting; ////REVIEW: introduce separate base class for ButtonControl and AxisControl instead of deriving ButtonControl from AxisControl? @@ -378,6 +379,7 @@ internal void UpdateWasPressedEditor() #endif // UNITY_EDITOR + /// protected override FourCC CalculateOptimizedControlDataType() { if (clamp == Clamp.None && From 25ef5ff1a1803a4d3df442776a89937a53ceef8e Mon Sep 17 00:00:00 2001 From: Chris Massie Date: Thu, 9 Jul 2026 18:09:37 -0700 Subject: [PATCH 7/7] Tweaked changelog wording --- Packages/com.unity.inputsystem/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/com.unity.inputsystem/CHANGELOG.md b/Packages/com.unity.inputsystem/CHANGELOG.md index ac9ae472b5..e368ade886 100644 --- a/Packages/com.unity.inputsystem/CHANGELOG.md +++ b/Packages/com.unity.inputsystem/CHANGELOG.md @@ -32,7 +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`. +- Fixed `PoseControl.isTracked` always returning false when read through non-optimized code paths (e.g. Input Debugger) due to `sizeInBits = 8` causing the 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`.