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
140 changes: 140 additions & 0 deletions Assets/Tests/InputSystem/CoreTests_Devices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -3818,6 +3819,145 @@ public void Devices_CanGetAccelerometerReading()
Assert.That(Accelerometer.current, Is.SameAs(accelerometer));
}

[Test]
[Category("Devices")]
public void Devices_CanGetLocationSensorReading()
{
var location = InputSystem.AddDevice<LocationSensor>();
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<LocationSensor>();
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<LocationSensor>();

// 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<LocationSensor>();
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<LocationSensor>();

// 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<LocationSensor>();

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()
Expand Down
5 changes: 5 additions & 0 deletions Packages/com.unity.inputsystem/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`. 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

- 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)
Expand Down

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Original file line number Diff line number Diff line change
Expand Up @@ -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)<br/>Example:<br/>`Gyroscope.current.samplingFrequency = 1.0f / updateInterval;`<br/><br/>__Notes__:<br/>[`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.<br/><br/>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).<br/>Start/Stop:<br/>`InputSystem.EnableDevice(LocationSensor.current);`<br/>`InputSystem.DisableDevice(LocationSensor.current);`<br/>Read the last fix from the controls, for example `LocationSensor.current.latitude.ReadValue()` (also `longitude`, `altitude`, `horizontalAccuracy`, `verticalAccuracy`, `timestamp`).<br/>Query lifecycle and permission with [`LocationSensor.current.status`](xref:UnityEngine.InputSystem.LocationSensor.status) and [`LocationSensor.current.isEnabledByUser`](xref:UnityEngine.InputSystem.LocationSensor.isEnabledByUser).<br/>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).<br/>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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
[`Input.location`](https://docs.unity3d.com/ScriptReference/Input-location.html)|[`LocationSensor`](xref:UnityEngine.InputSystem.LocationSensor).<br/>Start/Stop:<br/>`InputSystem.EnableDevice(LocationSensor.current);`<br/>`InputSystem.DisableDevice(LocationSensor.current);`<br/>Read the last fix from the controls, for example `LocationSensor.current.latitude.ReadValue()` (also `longitude`, `altitude`, `horizontalAccuracy`, `verticalAccuracy`, `timestamp`).<br/>Query lifecycle and permission with [`LocationSensor.current.status`](xref:UnityEngine.InputSystem.LocationSensor.status) and [`LocationSensor.current.isEnabledByUser`](xref:UnityEngine.InputSystem.LocationSensor.isEnabledByUser).<br/>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).<br/>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).<br/>Start/Stop:<br/>`InputSystem.EnableDevice(LocationSensor.current);`<br/>`InputSystem.DisableDevice(LocationSensor.current);`<br/>Read the last fix from the controls, for example `LocationSensor.current.latitude.ReadValue()` (also `longitude`, `altitude`, `horizontalAccuracy`, `verticalAccuracy`, `timestamp`).<br/>Query lifecycle and permission with [`LocationSensor.current.status`](xref:UnityEngine.InputSystem.LocationSensor.status) and [`LocationSensor.current.isEnabledByUser`](xref:UnityEngine.InputSystem.LocationSensor.isEnabledByUser).<br/>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).<br/>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.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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");
Expand All @@ -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 "
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System.Runtime.InteropServices;
using UnityEngine.InputSystem.Utilities;

namespace UnityEngine.InputSystem.LowLevel
{
/// <summary>
/// Command to set the desired accuracy and update-distance threshold of a <see cref="LocationSensor"/>.
/// </summary>
[StructLayout(LayoutKind.Explicit, Size = kSize)]
internal 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
};
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Runtime.InteropServices;
using UnityEngine.InputSystem.Utilities;

namespace UnityEngine.InputSystem.LowLevel
{
/// <summary>
/// Command to query whether the user has granted OS-level permission for a <see cref="LocationSensor"/> to access location data.
/// </summary>
[StructLayout(LayoutKind.Explicit, Size = kSize)]
internal 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)
};
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System.Runtime.InteropServices;
using UnityEngine.InputSystem.Utilities;

namespace UnityEngine.InputSystem.LowLevel
{
/// <summary>
/// Command to query the current status of a <see cref="LocationSensor"/>'s underlying platform location service.
/// </summary>
[StructLayout(LayoutKind.Explicit, Size = kSize)]
internal 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 LocationServiceStatus).
[FieldOffset(InputDeviceCommand.kBaseCommandSize)]
public int status;

public FourCC typeStatic => Type;

public static QueryLocationStatusCommand Create()
{
return new QueryLocationStatusCommand
{
baseCommand = new InputDeviceCommand(Type, kSize)
};
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading