Skip to content
Draft
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
139 changes: 139 additions & 0 deletions Assets/Tests/InputSystem/CoreTests_Devices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<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
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.status`](xref:UnityEngine.InputSystem.LocationSensor) and [`LocationSensor.isEnabledByUser`](xref:UnityEngine.InputSystem.LocationSensor).<br/>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.
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)]
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
};
}
}
}

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)]
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)
};
}
}
}

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)]
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)
};
}
}
}

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

Loading