From 3625a0a455a4a28c40ce839b9834498d97acb5b8 Mon Sep 17 00:00:00 2001 From: Morgan Hoarau Date: Thu, 6 Aug 2026 15:55:40 +0100 Subject: [PATCH 01/15] feat: add LocationSensor --- .../Commands/ConfigureLocationCommand.cs | 37 ++++ .../Commands/ConfigureLocationCommand.cs.meta | 2 + .../QueryLocationEnabledByUserCommand.cs | 32 ++++ .../QueryLocationEnabledByUserCommand.cs.meta | 2 + .../Commands/QueryLocationStatusCommand.cs | 33 ++++ .../QueryLocationStatusCommand.cs.meta | 2 + .../InputSystem/Runtime/Devices/Sensor.cs | 179 ++++++++++++++++++ .../InputSystem/Runtime/InputManager.cs | 1 + .../InputSystem/Runtime/InputSettings.cs | 46 +++++ 9 files changed, 334 insertions(+) create mode 100644 Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/ConfigureLocationCommand.cs create mode 100644 Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/ConfigureLocationCommand.cs.meta create mode 100644 Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationEnabledByUserCommand.cs create mode 100644 Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationEnabledByUserCommand.cs.meta create mode 100644 Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationStatusCommand.cs create mode 100644 Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationStatusCommand.cs.meta diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/ConfigureLocationCommand.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/ConfigureLocationCommand.cs new file mode 100644 index 0000000000..fd3bb0d20c --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/ConfigureLocationCommand.cs @@ -0,0 +1,37 @@ +using System.Runtime.InteropServices; +using UnityEngine.InputSystem.Utilities; + +namespace UnityEngine.InputSystem.LowLevel +{ + /// + /// Command to set the desired accuracy and update-distance threshold of a . + /// + [StructLayout(LayoutKind.Explicit, Size = kSize)] + public struct ConfigureLocationCommand : IInputDeviceCommandInfo + { + public static FourCC Type => new FourCC('L', 'C', 'F', 'G'); + + internal const int kSize = InputDeviceCommand.kBaseCommandSize + sizeof(float) * 2; + + [FieldOffset(0)] + public InputDeviceCommand baseCommand; + + [FieldOffset(InputDeviceCommand.kBaseCommandSize)] + public float desiredAccuracyInMeters; + + [FieldOffset(InputDeviceCommand.kBaseCommandSize + sizeof(float))] + public float updateDistanceInMeters; + + public FourCC typeStatic => Type; + + public static ConfigureLocationCommand Create(float desiredAccuracyInMeters, float updateDistanceInMeters) + { + return new ConfigureLocationCommand + { + baseCommand = new InputDeviceCommand(Type, kSize), + desiredAccuracyInMeters = desiredAccuracyInMeters, + updateDistanceInMeters = updateDistanceInMeters + }; + } + } +} diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/ConfigureLocationCommand.cs.meta b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/ConfigureLocationCommand.cs.meta new file mode 100644 index 0000000000..82326bf220 --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/ConfigureLocationCommand.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c34cf3d871008934dbec8c2f78fd2b44 \ No newline at end of file diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationEnabledByUserCommand.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationEnabledByUserCommand.cs new file mode 100644 index 0000000000..1d6a7227e5 --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationEnabledByUserCommand.cs @@ -0,0 +1,32 @@ +using System.Runtime.InteropServices; +using UnityEngine.InputSystem.Utilities; + +namespace UnityEngine.InputSystem.LowLevel +{ + /// + /// Command to query whether the user has granted OS-level permission for a to access location data. + /// + [StructLayout(LayoutKind.Explicit, Size = kSize)] + public struct QueryLocationEnabledByUserCommand : IInputDeviceCommandInfo + { + public static FourCC Type => new FourCC('L', 'U', 'S', 'R'); + + internal const int kSize = InputDeviceCommand.kBaseCommandSize + sizeof(bool); + + [FieldOffset(0)] + public InputDeviceCommand baseCommand; + + [FieldOffset(InputDeviceCommand.kBaseCommandSize)] + public bool enabledByUser; + + public FourCC typeStatic => Type; + + public static QueryLocationEnabledByUserCommand Create() + { + return new QueryLocationEnabledByUserCommand + { + baseCommand = new InputDeviceCommand(Type, kSize) + }; + } + } +} diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationEnabledByUserCommand.cs.meta b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationEnabledByUserCommand.cs.meta new file mode 100644 index 0000000000..591688ebce --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationEnabledByUserCommand.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c424603c48a383a4db10641fb4c153a0 \ No newline at end of file diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationStatusCommand.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationStatusCommand.cs new file mode 100644 index 0000000000..573eeb61b7 --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationStatusCommand.cs @@ -0,0 +1,33 @@ +using System.Runtime.InteropServices; +using UnityEngine.InputSystem.Utilities; + +namespace UnityEngine.InputSystem.LowLevel +{ + /// + /// Command to query the current status of a 's underlying platform location service. + /// + [StructLayout(LayoutKind.Explicit, Size = kSize)] + public struct QueryLocationStatusCommand : IInputDeviceCommandInfo + { + public static FourCC Type => new FourCC('L', 'S', 'T', 'A'); + + internal const int kSize = InputDeviceCommand.kBaseCommandSize + sizeof(int); + + [FieldOffset(0)] + public InputDeviceCommand baseCommand; + + // 0 Stopped, 1 Initializing, 2 Running, 3 Failed (matches UnityEngine.LocationServiceStatus). + [FieldOffset(InputDeviceCommand.kBaseCommandSize)] + public int status; + + public FourCC typeStatic => Type; + + public static QueryLocationStatusCommand Create() + { + return new QueryLocationStatusCommand + { + baseCommand = new InputDeviceCommand(Type, kSize) + }; + } + } +} diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationStatusCommand.cs.meta b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationStatusCommand.cs.meta new file mode 100644 index 0000000000..aea4c69174 --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationStatusCommand.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 6df2a82c47c50a448b780dac53477379 \ No newline at end of file diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs index c4cd9c952d..ceeddcae9d 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs @@ -60,6 +60,30 @@ internal struct LinearAccelerationState : IInputStateTypeInfo public FourCC format => kFormat; } + + /// + /// Low-level input state for . + /// + internal struct LocationState : IInputStateTypeInfo + { + public static FourCC kFormat => new FourCC('L', 'O', 'C', ' '); + + // Order matches native LocationInfo (timestamp first). Do not reorder. + [InputControl(displayName = "Timestamp", layout = "Double")] + public double timestamp; + [InputControl(displayName = "Latitude", layout = "Axis", noisy = true)] + public float latitude; + [InputControl(displayName = "Longitude", layout = "Axis", noisy = true)] + public float longitude; + [InputControl(displayName = "Altitude", layout = "Axis", noisy = true)] + public float altitude; + [InputControl(displayName = "Horizontal Accuracy", layout = "Axis", noisy = true)] + public float horizontalAccuracy; + [InputControl(displayName = "Vertical Accuracy", layout = "Axis", noisy = true)] + public float verticalAccuracy; + + public FourCC format => kFormat; + } } namespace UnityEngine.InputSystem @@ -694,4 +718,159 @@ protected override void FinishSetup() base.FinishSetup(); } } + + /// + /// Input device representing a GPS location sensor. + /// + /// + /// A location sensor reports the device's geographic position (, + /// , ). + /// After enabling it with , the location service may take several + /// seconds to acquire valid data, so readings are only valid once reaches + /// . Accessing location requires the user to have + /// granted permission (). + /// + [InputControlLayout(stateType = typeof(LocationState), displayName = "Location")] + public class LocationSensor : Sensor + { + /// + /// Latitude in degrees. + /// + public AxisControl latitude { get; protected set; } + + /// + /// Longitude in degrees. + /// + public AxisControl longitude { get; protected set; } + + /// + /// Altitude in meters. + /// + public AxisControl altitude { get; protected set; } + + /// + /// Horizontal accuracy of the reading in meters. + /// + public AxisControl horizontalAccuracy { get; protected set; } + + /// + /// Vertical accuracy of the reading in meters. + /// + public AxisControl verticalAccuracy { get; protected set; } + + /// + /// Time the reading was taken, in seconds since the epoch used by the platform location service. + /// + public DoubleControl timestamp { get; protected set; } + + /// + /// The location sensor that was last added or had activity last. + /// + /// Current location sensor or null. + public static LocationSensor current { get; private set; } + + /// + public override void MakeCurrent() + { + base.MakeCurrent(); + current = this; + } + + /// + protected override void OnRemoved() + { + base.OnRemoved(); + if (current == this) + current = null; + } + + /// + protected override void FinishSetup() + { + latitude = GetChildControl("latitude"); + longitude = GetChildControl("longitude"); + altitude = GetChildControl("altitude"); + horizontalAccuracy = GetChildControl("horizontalAccuracy"); + verticalAccuracy = GetChildControl("verticalAccuracy"); + timestamp = GetChildControl("timestamp"); + base.FinishSetup(); + } + + /// + /// Current status of the location service. + /// + /// + /// After the sensor is enabled the service starts asynchronously, passing through + /// before it reaches + /// . Readings are only valid while running. + /// + public LocationServiceStatus status + { + get + { + var command = QueryLocationStatusCommand.Create(); + if (ExecuteCommand(ref command) >= 0) + return (LocationServiceStatus)command.status; + return LocationServiceStatus.Stopped; // no native impl (editor/desktop) -> degrades + } + } + + /// + /// Whether the user has granted the app permission to access the device location. + /// + /// + /// A user can grant permission while the service is not running. If permission is denied, + /// the service does not reach . + /// + public bool isEnabledByUser + { + get + { + var command = QueryLocationEnabledByUserCommand.Create(); + if (ExecuteCommand(ref command) >= 0) + return command.enabledByUser; + return false; + } + } + + /// + /// Sets the desired accuracy and update-distance threshold for location readings. + /// + /// Desired horizontal accuracy, in meters. + /// Minimum distance the device must move before a new reading is reported, in meters. + /// + /// By default, the sensor is configured with the values from + /// and ; call + /// to return to those defaults. + /// + /// If the sensor is already enabled, readings may briefly pause while they are applied. + /// Otherwise, they apply the next time it is enabled. + /// + public void Configure(float desiredAccuracyInMeters, float updateDistanceInMeters) + { + var command = ConfigureLocationCommand.Create(desiredAccuracyInMeters, updateDistanceInMeters); + ExecuteCommand(ref command); + } + + /// + /// Reverts the accuracy and update-distance threshold to the defaults. + /// + /// + /// Subject to the same application timing as . + /// + public void ResetConfiguration() + { + var settings = InputSystem.settings; + Configure(settings.locationAccuracy, settings.locationDistanceThreshold); + } + + /// + protected override void OnAdded() + { + base.OnAdded(); + + // Seed InputSettings defaults into native once on add. + ResetConfiguration(); + } + } } diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/InputManager.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/InputManager.cs index 994538ecc2..ac1045e027 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/InputManager.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/InputManager.cs @@ -2073,6 +2073,7 @@ internal void InitializeData() RegisterControlLayout("HumiditySensor", typeof(HumiditySensor)); RegisterControlLayout("AmbientTemperatureSensor", typeof(AmbientTemperatureSensor)); RegisterControlLayout("StepCounter", typeof(StepCounter)); + RegisterControlLayout("LocationSensor", typeof(LocationSensor)); RegisterControlLayout("TrackedDevice", typeof(TrackedDevice)); // Precompiled layouts. diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/InputSettings.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/InputSettings.cs index 74220921c4..21e6e9dd7a 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/InputSettings.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/InputSettings.cs @@ -466,6 +466,48 @@ public float multiTapDelayTime } } + /// + /// The desired accuracy of location updates reported by , in meters. + /// + /// Desired horizontal accuracy in meters. Default is 10 meters. + /// + /// Note that the accuracy achieved is hardware and platform-dependent. A finer accuracy can increase power use. + /// + /// + public float locationAccuracy + { + get => m_LocationAccuracy; + set + { + // ReSharper disable once CompareOfFloatsByEqualityOperator + if (m_LocationAccuracy == value) + return; + m_LocationAccuracy = Mathf.Max(0f, value); + OnChange(); + } + } + + /// + /// The minimum distance, in meters, the device must move before reports an update. + /// + /// Minimum update distance in meters. Default is 10 meters. + /// + /// A larger threshold reports updates less often as the device moves, which can lower power use. + /// + /// + public float locationDistanceThreshold + { + get => m_LocationDistanceThreshold; + set + { + // ReSharper disable once CompareOfFloatsByEqualityOperator + if (m_LocationDistanceThreshold == value) + return; + m_LocationDistanceThreshold = Mathf.Max(0f, value); + OnChange(); + } + } + /// /// When Application.runInBackground is true, this property determines what happens when application focus changes /// (see Application.isFocused) changes and how we handle @@ -793,6 +835,8 @@ public void SetInternalFeatureFlag(string featureName, bool enabled) [SerializeField] private float m_DefaultHoldTime = 0.4f; [SerializeField] private float m_TapRadius = 5; [SerializeField] private float m_MultiTapDelayTime = 0.75f; + [SerializeField] private float m_LocationAccuracy = 10f; + [SerializeField] private float m_LocationDistanceThreshold = 10f; [SerializeField] private bool m_DisableRedundantEventsMerging = false; [SerializeField] private bool m_ShortcutKeysConsumeInputs = false; // This is the shortcut support from v1.4. Temporarily moved here as an opt-in feature, while it's issues are investigated. [SerializeField] private bool m_ShortcutKeysUseActionPriority = false; @@ -1087,6 +1131,8 @@ internal static bool AreEqual(InputSettings a, InputSettings b) CompareFloats(a.defaultHoldTime, b.defaultHoldTime) && CompareFloats(a.tapRadius, b.tapRadius) && CompareFloats(a.multiTapDelayTime, b.multiTapDelayTime) && + CompareFloats(a.locationAccuracy, b.locationAccuracy) && + CompareFloats(a.locationDistanceThreshold, b.locationDistanceThreshold) && a.backgroundBehavior == b.backgroundBehavior && a.editorInputBehaviorInPlayMode == b.editorInputBehaviorInPlayMode && a.inputActionPropertyDrawerMode == b.inputActionPropertyDrawerMode && From c0fc4883eda448641436f44a39444fd6033b6770 Mon Sep 17 00:00:00 2001 From: Morgan Hoarau Date: Thu, 6 Aug 2026 15:56:44 +0100 Subject: [PATCH 02/15] feat: Add inputSystem location settings to editor --- .../Editor/Settings/InputSettingsProvider.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Packages/com.unity.inputsystem/InputSystem/Editor/Settings/InputSettingsProvider.cs b/Packages/com.unity.inputsystem/InputSystem/Editor/Settings/InputSettingsProvider.cs index 575d73c9f5..84ef946513 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Editor/Settings/InputSettingsProvider.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Editor/Settings/InputSettingsProvider.cs @@ -128,6 +128,8 @@ public override void OnGUI(string searchContext) EditorGUILayout.Space(); EditorGUILayout.PropertyField(m_CompensateForScreenOrientation, m_CompensateForScreenOrientationContent); + EditorGUILayout.PropertyField(m_LocationAccuracy, m_LocationAccuracyContent); + EditorGUILayout.PropertyField(m_LocationDistanceThreshold, m_LocationDistanceThresholdContent); // NOTE: We do NOT make showing this one conditional on whether runInBackground is actually set in the // player settings as regardless of whether it's on or not, Unity will force it on in standalone @@ -302,6 +304,8 @@ private void InitializeWithCurrentSettings() m_UpdateMode = m_SettingsObject.FindProperty("m_UpdateMode"); m_ScrollDeltaBehavior = m_SettingsObject.FindProperty("m_ScrollDeltaBehavior"); m_CompensateForScreenOrientation = m_SettingsObject.FindProperty("m_CompensateForScreenOrientation"); + m_LocationAccuracy = m_SettingsObject.FindProperty("m_LocationAccuracy"); + m_LocationDistanceThreshold = m_SettingsObject.FindProperty("m_LocationDistanceThreshold"); m_BackgroundBehavior = m_SettingsObject.FindProperty("m_BackgroundBehavior"); m_EditorInputBehaviorInPlayMode = m_SettingsObject.FindProperty("m_EditorInputBehaviorInPlayMode"); m_DefaultDeadzoneMin = m_SettingsObject.FindProperty("m_DefaultDeadzoneMin"); @@ -321,6 +325,8 @@ private void InitializeWithCurrentSettings() m_ScrollDeltaBehaviorContent = new GUIContent("Scroll Delta Behavior", "Controls whether the value returned by the Scroll Wheel Delta is normalized (to be uniform across all platforms), or returns the non-normalized platform-specific range which can vary between platforms."); #endif m_CompensateForScreenOrientationContent = new GUIContent("Compensate Orientation", "Whether sensor input on mobile devices should be transformed to be relative to the current device orientation."); + m_LocationAccuracyContent = new GUIContent("Location Accuracy", "Default desired accuracy of LocationSensor updates, in meters. The accuracy achieved is hardware and platform-dependent, and a finer accuracy can increase power use."); + m_LocationDistanceThresholdContent = new GUIContent("Location Distance Threshold", "Default minimum distance, in meters, the device must move before LocationSensor reports an update. A larger threshold reports updates less often, which can lower power use."); m_BackgroundBehaviorContent = new GUIContent("Background Behavior", "If runInBackground is true (and in standalone *development* players and the editor), " + "determines what happens to InputDevices and events when the application moves in and out of running in the foreground.\n\n" + "'Reset And Disable Non-Background Devices' soft-resets and disables devices that cannot run in the background while the application does not have focus. Devices " @@ -446,6 +452,8 @@ private static string[] FindInputSettingsInProject() [NonSerialized] private SerializedProperty m_UpdateMode; [NonSerialized] private SerializedProperty m_ScrollDeltaBehavior; [NonSerialized] private SerializedProperty m_CompensateForScreenOrientation; + [NonSerialized] private SerializedProperty m_LocationAccuracy; + [NonSerialized] private SerializedProperty m_LocationDistanceThreshold; [NonSerialized] private SerializedProperty m_BackgroundBehavior; [NonSerialized] private SerializedProperty m_EditorInputBehaviorInPlayMode; [NonSerialized] private SerializedProperty m_DefaultDeadzoneMin; @@ -473,6 +481,8 @@ private static string[] FindInputSettingsInProject() private GUIContent m_ScrollDeltaBehaviorContent; #endif private GUIContent m_CompensateForScreenOrientationContent; + private GUIContent m_LocationAccuracyContent; + private GUIContent m_LocationDistanceThresholdContent; private GUIContent m_BackgroundBehaviorContent; private GUIContent m_EditorInputBehaviorInPlayModeContent; private GUIContent m_DefaultDeadzoneMinContent; From 777eadd028aa2f5ae55c7d58f3eafcb23b5befc4 Mon Sep 17 00:00:00 2001 From: Morgan Hoarau Date: Thu, 6 Aug 2026 15:57:06 +0100 Subject: [PATCH 03/15] test: add LocationSensor tests --- Assets/Tests/InputSystem/CoreTests_Devices.cs | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/Assets/Tests/InputSystem/CoreTests_Devices.cs b/Assets/Tests/InputSystem/CoreTests_Devices.cs index ed90efe605..33a31980dc 100644 --- a/Assets/Tests/InputSystem/CoreTests_Devices.cs +++ b/Assets/Tests/InputSystem/CoreTests_Devices.cs @@ -3818,6 +3818,145 @@ public void Devices_CanGetAccelerometerReading() Assert.That(Accelerometer.current, Is.SameAs(accelerometer)); } + [Test] + [Category("Devices")] + public void Devices_CanGetLocationSensorReading() + { + var location = InputSystem.AddDevice(); + InputSystem.EnableDevice(location); // Sensors start disabled. + InputSystem.QueueStateEvent(location, new LocationState + { + latitude = 59.3293f, + longitude = 18.0686f, + altitude = 28.0f, + horizontalAccuracy = 5.0f, + verticalAccuracy = 8.0f, + timestamp = 1_700_000_000.0 + }); + InputSystem.Update(); + + Assert.That(location.latitude.ReadValue(), Is.EqualTo(59.3293f).Within(1e-4)); + Assert.That(location.longitude.ReadValue(), Is.EqualTo(18.0686f).Within(1e-4)); + Assert.That(location.altitude.ReadValue(), Is.EqualTo(28.0f).Within(1e-4)); + Assert.That(location.horizontalAccuracy.ReadValue(), Is.EqualTo(5.0f).Within(1e-4)); + Assert.That(location.verticalAccuracy.ReadValue(), Is.EqualTo(8.0f).Within(1e-4)); + Assert.That(location.timestamp.ReadValue(), Is.EqualTo(1_700_000_000.0).Within(1e-6)); + Assert.That(LocationSensor.current, Is.SameAs(location)); + } + + [Test] + [Category("Devices")] + public unsafe void Devices_CanQueryLocationSensorStatus() + { + var location = InputSystem.AddDevice(); + runtime.SetDeviceCommandCallback(location.deviceId, + (id, commandPtr) => + { + if (commandPtr->type == QueryLocationStatusCommand.Type) + { + ((QueryLocationStatusCommand*)commandPtr)->status = (int)LocationServiceStatus.Running; + return InputDeviceCommand.GenericSuccess; + } + + return InputDeviceCommand.GenericFailure; + }); + + Assert.That(location.status, Is.EqualTo(LocationServiceStatus.Running)); + } + + [Test] + [Category("Devices")] + public unsafe void Devices_CanConfigureLocationSensor() + { + var location = InputSystem.AddDevice(); + + // The callback below is registered after AddDevice, so OnAdded's seed ConfigureLocationCommand + // (the 10f/10f InputSettings defaults) fires before any callback exists and is dropped. + // The 5f/2f value-gate below distinguishes our explicit Configure() call from those defaults. + var received = false; + runtime.SetDeviceCommandCallback(location.deviceId, + (id, commandPtr) => + { + if (commandPtr->type == ConfigureLocationCommand.Type) + { + var command = (ConfigureLocationCommand*)commandPtr; + if (Mathf.Approximately(command->desiredAccuracyInMeters, 5f) && + Mathf.Approximately(command->updateDistanceInMeters, 2f)) + received = true; + return InputDeviceCommand.GenericSuccess; + } + + return InputDeviceCommand.GenericFailure; + }); + + location.Configure(5f, 2f); + + Assert.That(received, Is.True); + } + + [Test] + [Category("Devices")] + public unsafe void Devices_CanQueryLocationSensorIsEnabledByUser() + { + var location = InputSystem.AddDevice(); + runtime.SetDeviceCommandCallback(location.deviceId, + (id, commandPtr) => + { + if (commandPtr->type == QueryLocationEnabledByUserCommand.Type) + { + ((QueryLocationEnabledByUserCommand*)commandPtr)->enabledByUser = true; + return InputDeviceCommand.GenericSuccess; + } + + return InputDeviceCommand.GenericFailure; + }); + + Assert.That(location.isEnabledByUser, Is.True); + } + + [Test] + [Category("Devices")] + public void Devices_LocationSensorDegradesWhenNoNativeHandler() + { + var location = InputSystem.AddDevice(); + + // No command callback is installed, so both queries fall through to the + // "no native impl (editor/desktop)" degradation paths. + Assert.That(location.status, Is.EqualTo(LocationServiceStatus.Stopped)); + Assert.That(location.isEnabledByUser, Is.False); + } + + [Test] + [Category("Devices")] + public unsafe void Devices_CanResetLocationConfig() + { + InputSystem.settings.locationAccuracy = 33f; + InputSystem.settings.locationDistanceThreshold = 7f; + + var location = InputSystem.AddDevice(); + + var lastAccuracy = 0f; + var lastDistanceThreshold = 0f; + runtime.SetDeviceCommandCallback(location.deviceId, + (id, commandPtr) => + { + if (commandPtr->type == ConfigureLocationCommand.Type) + { + var command = (ConfigureLocationCommand*)commandPtr; + lastAccuracy = command->desiredAccuracyInMeters; + lastDistanceThreshold = command->updateDistanceInMeters; + return InputDeviceCommand.GenericSuccess; + } + + return InputDeviceCommand.GenericFailure; + }); + + location.ResetConfiguration(); + + Assert.That(lastAccuracy, Is.EqualTo(33f).Within(1e-4)); + Assert.That(lastDistanceThreshold, Is.EqualTo(7f).Within(1e-4)); + } + [Test] [Category("Devices")] public void Devices_CanGetGyroReading() From 5d4a2842f13313b7617e203a187c7c42511d7efb Mon Sep 17 00:00:00 2001 From: Morgan Hoarau Date: Thu, 6 Aug 2026 15:57:45 +0100 Subject: [PATCH 04/15] docs: map Input.location to LocationSensor in old-to-new API table --- .../Documentation~/corresponding-old-new-api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/com.unity.inputsystem/Documentation~/corresponding-old-new-api.md b/Packages/com.unity.inputsystem/Documentation~/corresponding-old-new-api.md index dcad91390f..e1a71536df 100644 --- a/Packages/com.unity.inputsystem/Documentation~/corresponding-old-new-api.md +++ b/Packages/com.unity.inputsystem/Documentation~/corresponding-old-new-api.md @@ -115,5 +115,5 @@ Note: [`UnityEngine.TouchScreenKeyboard`](https://docs.unity3d.com/ScriptReferen [`Input.gyro.rotationRateUnbiased`](https://docs.unity3d.com/ScriptReference/Gyroscope-rotationRateUnbiased.html)|No corresponding API yet. [`Input.gyro.updateInterval`](https://docs.unity3d.com/ScriptReference/Gyroscope-updateInterval.html)|[`Sensor.samplingFrequency`](xref:UnityEngine.InputSystem.Sensor)
Example:
`Gyroscope.current.samplingFrequency = 1.0f / updateInterval;`

__Notes__:
[`samplingFrequency`](xref:UnityEngine.InputSystem.Sensor) is in Hz, not in seconds as [`updateInterval`](https://docs.unity3d.com/ScriptReference/Gyroscope-updateInterval.html), so you need to divide 1 by the value.

The new Input System replaces `UnityEngine.Gyroscope` with multiple separate sensor devices. Substitute [`Gyroscope`](xref:UnityEngine.InputSystem.Gyroscope) with other sensors in the sample as needed. See the notes for `Input.gyro` above for details. [`Input.gyro.userAcceleration`](https://docs.unity3d.com/ScriptReference/Gyroscope-userAcceleration.html)|[`LinearAccelerationSensor.current.acceleration.ReadValue()`](xref:UnityEngine.InputSystem.LinearAccelerationSensor) -[`Input.location`](https://docs.unity3d.com/ScriptReference/Input-location.html)|No corresponding API yet. +[`Input.location`](https://docs.unity3d.com/ScriptReference/Input-location.html)|[`LocationSensor`](xref:UnityEngine.InputSystem.LocationSensor).
Start/Stop:
`InputSystem.EnableDevice(LocationSensor.current);`
`InputSystem.DisableDevice(LocationSensor.current);`
Read the last fix from the controls, for example `LocationSensor.current.latitude.ReadValue()` (also `longitude`, `altitude`, `horizontalAccuracy`, `verticalAccuracy`, `timestamp`).
Query lifecycle and permission with [`LocationSensor.status`](xref:UnityEngine.InputSystem.LocationSensor) and [`LocationSensor.isEnabledByUser`](xref:UnityEngine.InputSystem.LocationSensor).
Set the requested accuracy and update-distance with `LocationSensor.current.Configure(accuracyInMeters, updateDistanceInMeters)`, or `ResetConfiguration()` to revert to the project defaults [`InputSettings.locationAccuracy`](xref:UnityEngine.InputSystem.InputSettings) and [`InputSettings.locationDistanceThreshold`](xref:UnityEngine.InputSystem.InputSettings). [`Input.GetAccelerationEvent`](https://docs.unity3d.com/ScriptReference/Input.GetAccelerationEvent.html)|See notes for `Input.accelerationEvents` above. From 66c56822612442e642e16662a46081f89553154b Mon Sep 17 00:00:00 2001 From: Morgan Hoarau Date: Thu, 6 Aug 2026 16:01:08 +0100 Subject: [PATCH 05/15] docs: improve location sensor xml doc --- .../InputSystem/Runtime/Devices/Sensor.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs index ceeddcae9d..f74bb52f7d 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs @@ -820,7 +820,7 @@ public LocationServiceStatus status ///
/// /// A user can grant permission while the service is not running. If permission is denied, - /// the service does not reach . + /// the service won't reach . /// public bool isEnabledByUser { @@ -840,11 +840,10 @@ public bool isEnabledByUser /// Minimum distance the device must move before a new reading is reported, in meters. /// /// By default, the sensor is configured with the values from - /// and ; call - /// to return to those defaults. + /// and . return to those defaults. /// /// If the sensor is already enabled, readings may briefly pause while they are applied. - /// Otherwise, they apply the next time it is enabled. + /// If the sensor is disabled, values apply when device is enabled. /// public void Configure(float desiredAccuracyInMeters, float updateDistanceInMeters) { From f8f840b49a5f3dff5859a66b9e79a2a76e28639a Mon Sep 17 00:00:00 2001 From: Morgan Hoarau Date: Tue, 11 Aug 2026 14:53:44 +0100 Subject: [PATCH 06/15] Fixes comments grammar --- .../InputSystem/Runtime/Devices/Sensor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs index f74bb52f7d..a7dfcd9180 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs @@ -840,10 +840,10 @@ public bool isEnabledByUser /// Minimum distance the device must move before a new reading is reported, in meters. /// /// By default, the sensor is configured with the values from - /// and . return to those defaults. + /// and . returns to those defaults. /// /// If the sensor is already enabled, readings may briefly pause while they are applied. - /// If the sensor is disabled, values apply when device is enabled. + /// If the sensor is disabled, values apply when the device is enabled. /// public void Configure(float desiredAccuracyInMeters, float updateDistanceInMeters) { From e34417dfa48c536830fc03ec21b12eddb034d339 Mon Sep 17 00:00:00 2001 From: Morgan Hoarau <122548697+MorganHoarau@users.noreply.github.com> Date: Tue, 11 Aug 2026 16:19:59 +0100 Subject: [PATCH 07/15] Update Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs --- .../com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs index f74bb52f7d..c89c9321b2 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs @@ -68,7 +68,7 @@ internal struct LocationState : IInputStateTypeInfo { public static FourCC kFormat => new FourCC('L', 'O', 'C', ' '); - // Order matches native LocationInfo (timestamp first). Do not reorder. + // Order matches native LocationInfo. Do not reorder. [InputControl(displayName = "Timestamp", layout = "Double")] public double timestamp; [InputControl(displayName = "Latitude", layout = "Axis", noisy = true)] From 4c9aef3165b1bb7292c63780851a0474a5c6c41a Mon Sep 17 00:00:00 2001 From: Morgan Hoarau Date: Tue, 11 Aug 2026 16:20:41 +0100 Subject: [PATCH 08/15] Update CHANGELOG.md --- Packages/com.unity.inputsystem/CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Packages/com.unity.inputsystem/CHANGELOG.md b/Packages/com.unity.inputsystem/CHANGELOG.md index 5e13c71fe8..9f75274df4 100644 --- a/Packages/com.unity.inputsystem/CHANGELOG.md +++ b/Packages/com.unity.inputsystem/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] - yyyy-mm-dd +### Added + +- Added `LocationSensor`, exposing GPS position, `status`, and permission state as the parity equivalent of `UnityEngine.Input.location`. +- Added `InputSettings.locationAccuracy` and `InputSettings.locationDistanceThreshold` project defaults for location updates. + ### Fixed - Fixed an `OverflowException` when creating a control scheme (or other named item) whose all-numeric name exceeds `Int32.MaxValue`, which previously discarded the entered name and fell back to the default [UUM-145766](https://issuetracker.unity3d.com/product/unity/issues/guid/UUM-145766) From 60caf6d2b3880a4b4a6bd5f0ff6bc1d69a874456 Mon Sep 17 00:00:00 2001 From: Morgan Hoarau Date: Wed, 12 Aug 2026 11:10:44 +0100 Subject: [PATCH 09/15] Update corresponding-old-new-api.md --- .../Documentation~/corresponding-old-new-api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/com.unity.inputsystem/Documentation~/corresponding-old-new-api.md b/Packages/com.unity.inputsystem/Documentation~/corresponding-old-new-api.md index e1a71536df..5cdf2e0ddd 100644 --- a/Packages/com.unity.inputsystem/Documentation~/corresponding-old-new-api.md +++ b/Packages/com.unity.inputsystem/Documentation~/corresponding-old-new-api.md @@ -115,5 +115,5 @@ Note: [`UnityEngine.TouchScreenKeyboard`](https://docs.unity3d.com/ScriptReferen [`Input.gyro.rotationRateUnbiased`](https://docs.unity3d.com/ScriptReference/Gyroscope-rotationRateUnbiased.html)|No corresponding API yet. [`Input.gyro.updateInterval`](https://docs.unity3d.com/ScriptReference/Gyroscope-updateInterval.html)|[`Sensor.samplingFrequency`](xref:UnityEngine.InputSystem.Sensor)
Example:
`Gyroscope.current.samplingFrequency = 1.0f / updateInterval;`

__Notes__:
[`samplingFrequency`](xref:UnityEngine.InputSystem.Sensor) is in Hz, not in seconds as [`updateInterval`](https://docs.unity3d.com/ScriptReference/Gyroscope-updateInterval.html), so you need to divide 1 by the value.

The new Input System replaces `UnityEngine.Gyroscope` with multiple separate sensor devices. Substitute [`Gyroscope`](xref:UnityEngine.InputSystem.Gyroscope) with other sensors in the sample as needed. See the notes for `Input.gyro` above for details. [`Input.gyro.userAcceleration`](https://docs.unity3d.com/ScriptReference/Gyroscope-userAcceleration.html)|[`LinearAccelerationSensor.current.acceleration.ReadValue()`](xref:UnityEngine.InputSystem.LinearAccelerationSensor) -[`Input.location`](https://docs.unity3d.com/ScriptReference/Input-location.html)|[`LocationSensor`](xref:UnityEngine.InputSystem.LocationSensor).
Start/Stop:
`InputSystem.EnableDevice(LocationSensor.current);`
`InputSystem.DisableDevice(LocationSensor.current);`
Read the last fix from the controls, for example `LocationSensor.current.latitude.ReadValue()` (also `longitude`, `altitude`, `horizontalAccuracy`, `verticalAccuracy`, `timestamp`).
Query lifecycle and permission with [`LocationSensor.status`](xref:UnityEngine.InputSystem.LocationSensor) and [`LocationSensor.isEnabledByUser`](xref:UnityEngine.InputSystem.LocationSensor).
Set the requested accuracy and update-distance with `LocationSensor.current.Configure(accuracyInMeters, updateDistanceInMeters)`, or `ResetConfiguration()` to revert to the project defaults [`InputSettings.locationAccuracy`](xref:UnityEngine.InputSystem.InputSettings) and [`InputSettings.locationDistanceThreshold`](xref:UnityEngine.InputSystem.InputSettings). +[`Input.location`](https://docs.unity3d.com/ScriptReference/Input-location.html)|[`LocationSensor`](xref:UnityEngine.InputSystem.LocationSensor).
Start/Stop:
`InputSystem.EnableDevice(LocationSensor.current);`
`InputSystem.DisableDevice(LocationSensor.current);`
Read the last fix from the controls, for example `LocationSensor.current.latitude.ReadValue()` (also `longitude`, `altitude`, `horizontalAccuracy`, `verticalAccuracy`, `timestamp`).
Query lifecycle and permission with [`LocationSensor.current.status`](xref:UnityEngine.InputSystem.LocationSensor.status) and [`LocationSensor.current.isEnabledByUser`](xref:UnityEngine.InputSystem.LocationSensor.isEnabledByUser).
Set the requested accuracy and update-distance with `LocationSensor.current.Configure(accuracyInMeters, updateDistanceInMeters)`, or `LocationSensor.current.ResetConfiguration()` to revert to the project defaults [`InputSettings.locationAccuracy`](xref:UnityEngine.InputSystem.InputSettings.locationAccuracy) and [`InputSettings.locationDistanceThreshold`](xref:UnityEngine.InputSystem.InputSettings.locationDistanceThreshold). [`Input.GetAccelerationEvent`](https://docs.unity3d.com/ScriptReference/Input.GetAccelerationEvent.html)|See notes for `Input.accelerationEvents` above. From 166cb554a44fb93cbae8bd924c5ae860e3bfdd6b Mon Sep 17 00:00:00 2001 From: Morgan Hoarau Date: Wed, 12 Aug 2026 14:35:46 +0100 Subject: [PATCH 10/15] Decouple ISX from legacy LocationStatus enum --- Assets/Tests/InputSystem/CoreTests_Devices.cs | 1 + Packages/com.unity.inputsystem/CHANGELOG.md | 2 +- .../Commands/QueryLocationStatusCommand.cs | 2 +- .../InputSystem/Runtime/Devices/Sensor.cs | 26 +++++++++++++++++++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Assets/Tests/InputSystem/CoreTests_Devices.cs b/Assets/Tests/InputSystem/CoreTests_Devices.cs index 33a31980dc..1b6a8dc9f8 100644 --- a/Assets/Tests/InputSystem/CoreTests_Devices.cs +++ b/Assets/Tests/InputSystem/CoreTests_Devices.cs @@ -21,6 +21,7 @@ using UnityEngine.TestTools.Utils; using UnityEngineInternal.Input; using Gyroscope = UnityEngine.InputSystem.Gyroscope; +using LocationServiceStatus = UnityEngine.InputSystem.LocationServiceStatus; using UnityEngine.TestTools.Constraints; using Is = NUnit.Framework.Is; using Quaternion = UnityEngine.Quaternion; diff --git a/Packages/com.unity.inputsystem/CHANGELOG.md b/Packages/com.unity.inputsystem/CHANGELOG.md index 9f75274df4..f2c2b4b76d 100644 --- a/Packages/com.unity.inputsystem/CHANGELOG.md +++ b/Packages/com.unity.inputsystem/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added -- Added `LocationSensor`, exposing GPS position, `status`, and permission state as the parity equivalent of `UnityEngine.Input.location`. +- Added `LocationSensor`, exposing GPS position, `status`, and permission state as the parity equivalent of `UnityEngine.Input.location`. Reports status via a new Input System `LocationServiceStatus` enum, so the package does not depend on the legacy input module. - Added `InputSettings.locationAccuracy` and `InputSettings.locationDistanceThreshold` project defaults for location updates. ### Fixed diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationStatusCommand.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationStatusCommand.cs index 573eeb61b7..4929d90c94 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationStatusCommand.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationStatusCommand.cs @@ -16,7 +16,7 @@ public struct QueryLocationStatusCommand : IInputDeviceCommandInfo [FieldOffset(0)] public InputDeviceCommand baseCommand; - // 0 Stopped, 1 Initializing, 2 Running, 3 Failed (matches UnityEngine.LocationServiceStatus). + // 0 Stopped, 1 Initializing, 2 Running, 3 Failed (matches LocationServiceStatus). [FieldOffset(InputDeviceCommand.kBaseCommandSize)] public int status; diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs index 07c69ddf70..a101f97952 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs @@ -719,6 +719,32 @@ protected override void FinishSetup() } } + /// + /// Status of the location service backing a . + /// + public enum LocationServiceStatus + { + /// + /// The location service is not running. + /// + Stopped = 0, + + /// + /// The location service is initializing and does not yet have a valid reading. + /// + Initializing = 1, + + /// + /// The location service is running and the sensor readings are valid. + /// + Running = 2, + + /// + /// The location service failed to start, for example because the user denied permission. + /// + Failed = 3 + } + /// /// Input device representing a GPS location sensor. /// From fe5105e844c05506cecc269bcb5a1ff3e6c2c925 Mon Sep 17 00:00:00 2001 From: Morgan Hoarau Date: Wed, 12 Aug 2026 14:36:01 +0100 Subject: [PATCH 11/15] Documents Location backend service limitation --- .../InputSystem/Runtime/Devices/Sensor.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs index a101f97952..05936c6a7e 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs @@ -755,6 +755,10 @@ public enum LocationServiceStatus /// seconds to acquire valid data, so readings are only valid once reaches /// . Accessing location requires the user to have /// granted permission (). + /// + /// Do not drive location from both this device and the legacy UnityEngine.Input.location API in the + /// same project. Both share the same underlying platform location service, so disabling this device also + /// stops updates for the legacy API (and vice versa). Use a single location API per project. /// [InputControlLayout(stateType = typeof(LocationState), displayName = "Location")] public class LocationSensor : Sensor From 2a473d8fcd0ffad242a7d081fbab22e4c4b51e17 Mon Sep 17 00:00:00 2001 From: Morgan Hoarau Date: Thu, 13 Aug 2026 11:51:46 +0100 Subject: [PATCH 12/15] Make Location commands internal --- .../Runtime/Devices/Commands/ConfigureLocationCommand.cs | 2 +- .../Devices/Commands/QueryLocationEnabledByUserCommand.cs | 2 +- .../Runtime/Devices/Commands/QueryLocationStatusCommand.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/ConfigureLocationCommand.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/ConfigureLocationCommand.cs index fd3bb0d20c..6b7e75aa9a 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/ConfigureLocationCommand.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/ConfigureLocationCommand.cs @@ -7,7 +7,7 @@ namespace UnityEngine.InputSystem.LowLevel /// Command to set the desired accuracy and update-distance threshold of a . /// [StructLayout(LayoutKind.Explicit, Size = kSize)] - public struct ConfigureLocationCommand : IInputDeviceCommandInfo + internal struct ConfigureLocationCommand : IInputDeviceCommandInfo { public static FourCC Type => new FourCC('L', 'C', 'F', 'G'); diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationEnabledByUserCommand.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationEnabledByUserCommand.cs index 1d6a7227e5..7f75a61e6c 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationEnabledByUserCommand.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationEnabledByUserCommand.cs @@ -7,7 +7,7 @@ namespace UnityEngine.InputSystem.LowLevel /// Command to query whether the user has granted OS-level permission for a to access location data. /// [StructLayout(LayoutKind.Explicit, Size = kSize)] - public struct QueryLocationEnabledByUserCommand : IInputDeviceCommandInfo + internal struct QueryLocationEnabledByUserCommand : IInputDeviceCommandInfo { public static FourCC Type => new FourCC('L', 'U', 'S', 'R'); diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationStatusCommand.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationStatusCommand.cs index 4929d90c94..8aa2481cb0 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationStatusCommand.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Commands/QueryLocationStatusCommand.cs @@ -7,7 +7,7 @@ namespace UnityEngine.InputSystem.LowLevel /// Command to query the current status of a 's underlying platform location service. /// [StructLayout(LayoutKind.Explicit, Size = kSize)] - public struct QueryLocationStatusCommand : IInputDeviceCommandInfo + internal struct QueryLocationStatusCommand : IInputDeviceCommandInfo { public static FourCC Type => new FourCC('L', 'S', 'T', 'A'); From 59c65e147ea9c7268a0bc9db0962f98e2cf10d0e Mon Sep 17 00:00:00 2001 From: Morgan Hoarau Date: Fri, 14 Aug 2026 19:48:28 +0100 Subject: [PATCH 13/15] docs: document IL ref limitation for permission injection also mention of feature capability check --- .../Documentation~/corresponding-old-new-api.md | 2 +- .../InputSystem/Runtime/Devices/Sensor.cs | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Packages/com.unity.inputsystem/Documentation~/corresponding-old-new-api.md b/Packages/com.unity.inputsystem/Documentation~/corresponding-old-new-api.md index 5cdf2e0ddd..34abd6a22d 100644 --- a/Packages/com.unity.inputsystem/Documentation~/corresponding-old-new-api.md +++ b/Packages/com.unity.inputsystem/Documentation~/corresponding-old-new-api.md @@ -115,5 +115,5 @@ Note: [`UnityEngine.TouchScreenKeyboard`](https://docs.unity3d.com/ScriptReferen [`Input.gyro.rotationRateUnbiased`](https://docs.unity3d.com/ScriptReference/Gyroscope-rotationRateUnbiased.html)|No corresponding API yet. [`Input.gyro.updateInterval`](https://docs.unity3d.com/ScriptReference/Gyroscope-updateInterval.html)|[`Sensor.samplingFrequency`](xref:UnityEngine.InputSystem.Sensor)
Example:
`Gyroscope.current.samplingFrequency = 1.0f / updateInterval;`

__Notes__:
[`samplingFrequency`](xref:UnityEngine.InputSystem.Sensor) is in Hz, not in seconds as [`updateInterval`](https://docs.unity3d.com/ScriptReference/Gyroscope-updateInterval.html), so you need to divide 1 by the value.

The new Input System replaces `UnityEngine.Gyroscope` with multiple separate sensor devices. Substitute [`Gyroscope`](xref:UnityEngine.InputSystem.Gyroscope) with other sensors in the sample as needed. See the notes for `Input.gyro` above for details. [`Input.gyro.userAcceleration`](https://docs.unity3d.com/ScriptReference/Gyroscope-userAcceleration.html)|[`LinearAccelerationSensor.current.acceleration.ReadValue()`](xref:UnityEngine.InputSystem.LinearAccelerationSensor) -[`Input.location`](https://docs.unity3d.com/ScriptReference/Input-location.html)|[`LocationSensor`](xref:UnityEngine.InputSystem.LocationSensor).
Start/Stop:
`InputSystem.EnableDevice(LocationSensor.current);`
`InputSystem.DisableDevice(LocationSensor.current);`
Read the last fix from the controls, for example `LocationSensor.current.latitude.ReadValue()` (also `longitude`, `altitude`, `horizontalAccuracy`, `verticalAccuracy`, `timestamp`).
Query lifecycle and permission with [`LocationSensor.current.status`](xref:UnityEngine.InputSystem.LocationSensor.status) and [`LocationSensor.current.isEnabledByUser`](xref:UnityEngine.InputSystem.LocationSensor.isEnabledByUser).
Set the requested accuracy and update-distance with `LocationSensor.current.Configure(accuracyInMeters, updateDistanceInMeters)`, or `LocationSensor.current.ResetConfiguration()` to revert to the project defaults [`InputSettings.locationAccuracy`](xref:UnityEngine.InputSystem.InputSettings.locationAccuracy) and [`InputSettings.locationDistanceThreshold`](xref:UnityEngine.InputSystem.InputSettings.locationDistanceThreshold). +[`Input.location`](https://docs.unity3d.com/ScriptReference/Input-location.html)|[`LocationSensor`](xref:UnityEngine.InputSystem.LocationSensor).
Start/Stop:
`InputSystem.EnableDevice(LocationSensor.current);`
`InputSystem.DisableDevice(LocationSensor.current);`
Read the last fix from the controls, for example `LocationSensor.current.latitude.ReadValue()` (also `longitude`, `altitude`, `horizontalAccuracy`, `verticalAccuracy`, `timestamp`).
Query lifecycle and permission with [`LocationSensor.current.status`](xref:UnityEngine.InputSystem.LocationSensor.status) and [`LocationSensor.current.isEnabledByUser`](xref:UnityEngine.InputSystem.LocationSensor.isEnabledByUser).
Set the requested accuracy and update-distance with `LocationSensor.current.Configure(accuracyInMeters, updateDistanceInMeters)`, or `LocationSensor.current.ResetConfiguration()` to revert to the project defaults [`InputSettings.locationAccuracy`](xref:UnityEngine.InputSystem.InputSettings.locationAccuracy) and [`InputSettings.locationDistanceThreshold`](xref:UnityEngine.InputSystem.InputSettings.locationDistanceThreshold).
Note: on Android and iOS the location permission and usage description are auto-added to the build only when your code references `LocationSensor` directly; if you use it solely through an `.inputactions` binding, reference the type in code (for example `LocationSensor.current`) or add the permission and usage description manually. [`Input.GetAccelerationEvent`](https://docs.unity3d.com/ScriptReference/Input.GetAccelerationEvent.html)|See notes for `Input.accelerationEvents` above. diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs index 05936c6a7e..45c7e0cc77 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs @@ -755,10 +755,19 @@ public enum LocationServiceStatus /// seconds to acquire valid data, so readings are only valid once reaches /// . Accessing location requires the user to have /// granted permission (). + /// The sensor's presence ( being non-null) does not guarantee the location service is + /// available or running; query and to determine that. /// /// Do not drive location from both this device and the legacy UnityEngine.Input.location API in the /// same project. Both share the same underlying platform location service, so disabling this device also /// stops updates for the legacy API (and vice versa). Use a single location API per project. + /// + /// On Android and iOS the required location permission (Android) and usage description (iOS) are added to the + /// build automatically only when your compiled code references directly. If you + /// access the sensor solely through an .inputactions asset binding and never reference the type in code, + /// this detection does not trigger and the build ships without them, so the service fails to start at runtime. + /// Reference in code (for example by accessing once), + /// or add the platform permission and usage description manually. /// [InputControlLayout(stateType = typeof(LocationState), displayName = "Location")] public class LocationSensor : Sensor From b8b9c2ac8a3384de526c483b7d8e4edf7155c7ce Mon Sep 17 00:00:00 2001 From: Morgan Hoarau <122548697+MorganHoarau@users.noreply.github.com> Date: Mon, 17 Aug 2026 14:07:15 +0100 Subject: [PATCH 14/15] Update Packages/com.unity.inputsystem/Documentation~/corresponding-old-new-api.md Co-authored-by: Sue Arkin <85237015+suearkinunity@users.noreply.github.com> --- .../Documentation~/corresponding-old-new-api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/com.unity.inputsystem/Documentation~/corresponding-old-new-api.md b/Packages/com.unity.inputsystem/Documentation~/corresponding-old-new-api.md index 34abd6a22d..57f7263217 100644 --- a/Packages/com.unity.inputsystem/Documentation~/corresponding-old-new-api.md +++ b/Packages/com.unity.inputsystem/Documentation~/corresponding-old-new-api.md @@ -115,5 +115,5 @@ Note: [`UnityEngine.TouchScreenKeyboard`](https://docs.unity3d.com/ScriptReferen [`Input.gyro.rotationRateUnbiased`](https://docs.unity3d.com/ScriptReference/Gyroscope-rotationRateUnbiased.html)|No corresponding API yet. [`Input.gyro.updateInterval`](https://docs.unity3d.com/ScriptReference/Gyroscope-updateInterval.html)|[`Sensor.samplingFrequency`](xref:UnityEngine.InputSystem.Sensor)
Example:
`Gyroscope.current.samplingFrequency = 1.0f / updateInterval;`

__Notes__:
[`samplingFrequency`](xref:UnityEngine.InputSystem.Sensor) is in Hz, not in seconds as [`updateInterval`](https://docs.unity3d.com/ScriptReference/Gyroscope-updateInterval.html), so you need to divide 1 by the value.

The new Input System replaces `UnityEngine.Gyroscope` with multiple separate sensor devices. Substitute [`Gyroscope`](xref:UnityEngine.InputSystem.Gyroscope) with other sensors in the sample as needed. See the notes for `Input.gyro` above for details. [`Input.gyro.userAcceleration`](https://docs.unity3d.com/ScriptReference/Gyroscope-userAcceleration.html)|[`LinearAccelerationSensor.current.acceleration.ReadValue()`](xref:UnityEngine.InputSystem.LinearAccelerationSensor) -[`Input.location`](https://docs.unity3d.com/ScriptReference/Input-location.html)|[`LocationSensor`](xref:UnityEngine.InputSystem.LocationSensor).
Start/Stop:
`InputSystem.EnableDevice(LocationSensor.current);`
`InputSystem.DisableDevice(LocationSensor.current);`
Read the last fix from the controls, for example `LocationSensor.current.latitude.ReadValue()` (also `longitude`, `altitude`, `horizontalAccuracy`, `verticalAccuracy`, `timestamp`).
Query lifecycle and permission with [`LocationSensor.current.status`](xref:UnityEngine.InputSystem.LocationSensor.status) and [`LocationSensor.current.isEnabledByUser`](xref:UnityEngine.InputSystem.LocationSensor.isEnabledByUser).
Set the requested accuracy and update-distance with `LocationSensor.current.Configure(accuracyInMeters, updateDistanceInMeters)`, or `LocationSensor.current.ResetConfiguration()` to revert to the project defaults [`InputSettings.locationAccuracy`](xref:UnityEngine.InputSystem.InputSettings.locationAccuracy) and [`InputSettings.locationDistanceThreshold`](xref:UnityEngine.InputSystem.InputSettings.locationDistanceThreshold).
Note: on Android and iOS the location permission and usage description are auto-added to the build only when your code references `LocationSensor` directly; if you use it solely through an `.inputactions` binding, reference the type in code (for example `LocationSensor.current`) or add the permission and usage description manually. +[`Input.location`](https://docs.unity3d.com/ScriptReference/Input-location.html)|[`LocationSensor`](xref:UnityEngine.InputSystem.LocationSensor).
Start/Stop:
`InputSystem.EnableDevice(LocationSensor.current);`
`InputSystem.DisableDevice(LocationSensor.current);`
Read the last fix from the controls, for example `LocationSensor.current.latitude.ReadValue()` (also `longitude`, `altitude`, `horizontalAccuracy`, `verticalAccuracy`, `timestamp`).
Query lifecycle and permission with [`LocationSensor.current.status`](xref:UnityEngine.InputSystem.LocationSensor.status) and [`LocationSensor.current.isEnabledByUser`](xref:UnityEngine.InputSystem.LocationSensor.isEnabledByUser).
Set the requested accuracy and update-distance with `LocationSensor.current.Configure(accuracyInMeters, updateDistanceInMeters)`, or `LocationSensor.current.ResetConfiguration()` to revert to the project defaults [`InputSettings.locationAccuracy`](xref:UnityEngine.InputSystem.InputSettings.locationAccuracy) and [`InputSettings.locationDistanceThreshold`](xref:UnityEngine.InputSystem.InputSettings.locationDistanceThreshold).
Note: on Android and iOS the location permission and usage description are auto-added to the build only when your code references `LocationSensor` directly. If you use `LocationSensor` only through an `.inputactions` binding, you can either reference the type in code (for example `LocationSensor.current`) or add the permission and usage description manually. [`Input.GetAccelerationEvent`](https://docs.unity3d.com/ScriptReference/Input.GetAccelerationEvent.html)|See notes for `Input.accelerationEvents` above. From 8288d7504abc7ace58a6002c9ef6bffa64adcaa3 Mon Sep 17 00:00:00 2001 From: Morgan Hoarau Date: Mon, 17 Aug 2026 15:43:32 +0100 Subject: [PATCH 15/15] update Loc sensor properties' remarks to mention thread requirement --- .../InputSystem/Runtime/Devices/Sensor.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs index 45c7e0cc77..74e89d1c1e 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs @@ -842,6 +842,7 @@ protected override void FinishSetup() /// After the sensor is enabled the service starts asynchronously, passing through /// before it reaches /// . Readings are only valid while running. + /// Must be accessed from the main thread only. /// public LocationServiceStatus status { @@ -860,6 +861,7 @@ public LocationServiceStatus status /// /// A user can grant permission while the service is not running. If permission is denied, /// the service won't reach . + /// Must be accessed from the main thread only. /// public bool isEnabledByUser { @@ -883,6 +885,7 @@ public bool isEnabledByUser /// /// If the sensor is already enabled, readings may briefly pause while they are applied. /// If the sensor is disabled, values apply when the device is enabled. + /// Must be called from the main thread only. /// public void Configure(float desiredAccuracyInMeters, float updateDistanceInMeters) { @@ -895,6 +898,7 @@ public void Configure(float desiredAccuracyInMeters, float updateDistanceInMeter /// /// /// Subject to the same application timing as . + /// Must be called from the main thread only. /// public void ResetConfiguration() {