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
14 changes: 14 additions & 0 deletions Assets/Tests/InputSystem/CoreTests_Devices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
using Is = NUnit.Framework.Is;
using Quaternion = UnityEngine.Quaternion;
using TouchPhase = UnityEngine.InputSystem.TouchPhase;
using DeviceOrientation = UnityEngine.InputSystem.DeviceOrientation;
using Vector2 = UnityEngine.Vector2;
using Vector3 = UnityEngine.Vector3;

Expand Down Expand Up @@ -2649,6 +2650,7 @@ public void Devices_DeltaControlsResetBetweenUpdates(string layoutName, string c
[TestCase("Joystick", typeof(Joystick))]
[TestCase("Accelerometer", typeof(Accelerometer))]
[TestCase("Gyroscope", typeof(Gyroscope))]
[TestCase("DeviceOrientationSensor", typeof(DeviceOrientationSensor))]
public void Devices_CanCreateDevice(string layout, System.Type type)
{
var device = InputSystem.AddDevice(layout);
Expand Down Expand Up @@ -3870,6 +3872,18 @@ public void Devices_CanGetLinearAccelerationReading()
Assert.That(LinearAccelerationSensor.current, Is.SameAs(sensor));
}

[Test]
[Category("Devices")]
public void Devices_CanGetDeviceOrientationReading()
{
var sensor = InputSystem.AddDevice<DeviceOrientationSensor>();
InputSystem.QueueStateEvent(sensor, new DeviceOrientationState { orientation = (int)DeviceOrientation.LandscapeLeft });
InputSystem.Update();

Assert.That(sensor.orientation.ReadValue(), Is.EqualTo(DeviceOrientation.LandscapeLeft));
Assert.That(DeviceOrientationSensor.current, Is.SameAs(sensor));
}

[Test]
[Category("Devices")]
[TestCase("Accelerometer", "acceleration")]
Expand Down
37 changes: 37 additions & 0 deletions Assets/Tests/InputSystem/Plugins/UnityRemoteTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using UnityEngine.InputSystem;
using UnityEngine.TestTools.Utils;
using Gyroscope = UnityEngine.InputSystem.Gyroscope;
using DeviceOrientation = UnityEngine.InputSystem.DeviceOrientation;

internal class UnityRemoteTests : CoreTestsFixture
{
Expand Down Expand Up @@ -269,6 +270,42 @@ public void Remote_CanReceiveAccelerometerInputFromUnityRemote()
Assert.That(Accelerometer.current, Is.Null);
}

[Test]
[Category("Remote")]
public void Remote_CanReceiveDeviceOrientationFromUnityRemote()
{
SendUnityRemoteMessage(UnityRemoteSupport.HelloMessage.Create());

// Like the accelerometer, the orientation sensor is assumed present on every device running the
// Unity Remote and does not require explicit enabling.
Assert.That(DeviceOrientationSensor.current, Is.Not.Null);
Assert.That(DeviceOrientationSensor.current.remote, Is.True);
Assert.That(DeviceOrientationSensor.current.enabled, Is.True);

SendUnityRemoteMessage(new UnityRemoteSupport.DeviceOrientationMessage
{
orientation = (int)DeviceOrientation.LandscapeLeft
});
InputSystem.Update();

Assert.That(DeviceOrientationSensor.current.orientation.ReadValue(), Is.EqualTo(DeviceOrientation.LandscapeLeft));

// Disabling it should stop updates.
InputSystem.DisableDevice(DeviceOrientationSensor.current);

SendUnityRemoteMessage(new UnityRemoteSupport.DeviceOrientationMessage
{
orientation = (int)DeviceOrientation.FaceUp
});
InputSystem.Update();

Assert.That(DeviceOrientationSensor.current.orientation.ReadValue(), Is.EqualTo(DeviceOrientation.LandscapeLeft));

SendUnityRemoteMessage(new UnityRemoteSupport.GoodbyeMessage());

Assert.That(DeviceOrientationSensor.current, Is.Null);
}

// We don't currently support joystick input coming from the Unity Remote.
[Test]
[Category("Remote")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ private static unsafe bool ProcessMessageFromUnityRemote(IntPtr messageData)
s_State.touchscreen.m_DeviceFlags |= InputDevice.DeviceFlags.Remote;
s_State.accelerometer = InputSystem.AddDevice<Accelerometer>();
s_State.accelerometer.m_DeviceFlags |= InputDevice.DeviceFlags.Remote;
s_State.orientation = InputSystem.AddDevice<DeviceOrientationSensor>();
s_State.orientation.m_DeviceFlags |= InputDevice.DeviceFlags.Remote;
// Gryo etc. added only when we receive GyroSettingsMessage.

s_State.connected = true;
Expand Down Expand Up @@ -248,6 +250,17 @@ private static unsafe bool ProcessMessageFromUnityRemote(IntPtr messageData)
accelerometerMessage->accelerationZ)
});
break;

case (byte)MessageType.DeviceOrientation:
if (s_State.orientation == null)
break;
var orientationMessage = (DeviceOrientationMessage*)messageData;
// The remote sends the DeviceOrientation enum value directly (same values as ours).
InputSystem.QueueStateEvent(s_State.orientation, new DeviceOrientationState
{
orientation = orientationMessage->orientation
});
break;
}

return false;
Expand All @@ -257,6 +270,8 @@ private static void Disconnect()
{
InputSystem.RemoveDevice(s_State.touchscreen);
InputSystem.RemoveDevice(s_State.accelerometer);
if (s_State.orientation != null)
InputSystem.RemoveDevice(s_State.orientation);
if (s_State.gyroscope != null)
InputSystem.RemoveDevice(s_State.gyroscope);
if (s_State.attitude != null)
Expand Down Expand Up @@ -287,6 +302,8 @@ private static void OnDeviceChange(InputDevice device, InputDeviceChange change)
s_State.touchscreen = null;
else if (device == s_State.linearAcceleration)
s_State.linearAcceleration = null;
else if (device == s_State.orientation)
s_State.orientation = null;
break;

case InputDeviceChange.Enabled:
Expand Down Expand Up @@ -534,6 +551,17 @@ internal struct AccelerometerInputMessage : IUnityRemoteMessage
public byte staticType => (byte)MessageType.AccelerometerInput;
}

// See HandleOrientationMessage() in Editor/Src/RemoteInput/GenericRemote.cpp: a single int32 holding
// the DeviceOrientation enum value.
[StructLayout(LayoutKind.Explicit)]
internal struct DeviceOrientationMessage : IUnityRemoteMessage
{
[FieldOffset(0)] public MessageHeader header;
[FieldOffset(5)] public int orientation;

public byte staticType => (byte)MessageType.DeviceOrientation;
}

private struct State
{
public bool connected;
Expand All @@ -548,6 +576,7 @@ private struct State
// Devices that we create for receiving input from the remote.
public Touchscreen touchscreen;
public Accelerometer accelerometer;
public DeviceOrientationSensor orientation;
public Gyroscope gyroscope;
public AttitudeSensor attitude;
public GravitySensor gravity;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.LowLevel;

namespace UnityEngine.InputSystem.Controls
{
/// <summary>
/// A control reading a <see cref="DeviceOrientation"/> value.
/// </summary>
/// <remarks>
/// This is used by <see cref="DeviceOrientationSensor"/> to report the physical orientation of the device
/// (see <see cref="DeviceOrientationSensor.orientation"/>). It provides feature parity with the legacy
/// <c>UnityEngine.Input.deviceOrientation</c> property.
/// </remarks>
/// <seealso cref="DeviceOrientationSensor"/>
[InputControlLayout(hideInUI = true)]
public class OrientationControl : InputControl<DeviceOrientation>
{
/// <summary>
/// Default-initialize the control.
/// </summary>
/// <remarks>
/// Format of the control is <see cref="InputStateBlock.FormatInt"/>
/// by default.
/// </remarks>
public OrientationControl()
{
m_StateBlock.format = InputStateBlock.FormatInt;
}

/// <inheritdoc />
public override unsafe DeviceOrientation ReadUnprocessedValueFromState(void* statePtr)
{
var intValue = stateBlock.ReadInt(statePtr);
return (DeviceOrientation)intValue;
}

/// <inheritdoc />
public override unsafe void WriteValueIntoState(DeviceOrientation value, void* statePtr)
{
var valuePtr = (byte*)statePtr + (int)m_StateBlock.byteOffset;
*(int*)valuePtr = (int)value;
}
}
}

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

117 changes: 117 additions & 0 deletions Packages/com.unity.inputsystem/InputSystem/Runtime/Devices/Sensor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ internal struct LinearAccelerationState : IInputStateTypeInfo

public FourCC format => kFormat;
}

internal struct DeviceOrientationState : IInputStateTypeInfo
{
public static FourCC kFormat => new FourCC('O', 'R', 'N', 'T');

// Note: unlike the other sensors this value is *not* compensated for screen orientation. It reports
// the physical orientation of the device and thus must be independent of how the content is rendered.
[InputControl(name = "orientation", displayName = "Orientation", layout = "Orientation")]
public int orientation;

public FourCC format => kFormat;
}
}

namespace UnityEngine.InputSystem
Expand Down Expand Up @@ -694,4 +706,109 @@ protected override void FinishSetup()
base.FinishSetup();
}
}

/// <summary>
/// Enum describing the physical orientation of a device as reported by <see cref="DeviceOrientationSensor"/>.
/// </summary>
/// <remarks>
/// The values mirror the legacy <c>UnityEngine.DeviceOrientation</c> enum so that content migrating from
/// <c>UnityEngine.Input.deviceOrientation</c> to the Input System observes identical semantics. Note that this
/// is a package-local enum, kept independent of the legacy input module.
/// </remarks>
/// <seealso cref="DeviceOrientationSensor"/>
public enum DeviceOrientation
{
/// <summary>The orientation of the device cannot be determined.</summary>
Unknown = 0,

/// <summary>The device is in portrait mode, with the device held upright and the home button at the bottom.</summary>
Portrait = 1,

/// <summary>The device is in portrait mode but upside down, with the device held upright and the home button at the top.</summary>
PortraitUpsideDown = 2,

/// <summary>The device is in landscape mode, with the device held upright and the home button on the right side.</summary>
LandscapeLeft = 3,

/// <summary>The device is in landscape mode, with the device held upright and the home button on the left side.</summary>
LandscapeRight = 4,

/// <summary>The device is held parallel to the ground with the screen facing upwards.</summary>
FaceUp = 5,

/// <summary>The device is held parallel to the ground with the screen facing downwards.</summary>
FaceDown = 6,
}

/// <summary>
/// Input device representing the physical orientation of the device playing the content.
/// </summary>
/// <remarks>
/// The orientation sensor reports the physical orientation of the device (for example, whether it is held in
/// portrait or landscape, or lying face up or face down) as a discrete <see cref="DeviceOrientation"/> value.
/// It provides feature parity with the legacy <c>UnityEngine.Input.deviceOrientation</c> property.
///
/// Unlike the other motion sensors, the reported value is not compensated for screen orientation; it always
/// describes the physical orientation of the hardware.
///
/// <example>
/// <code>
/// class MyBehavior : MonoBehaviour
/// {
/// protected void OnEnable()
/// {
/// InputSystem.EnableDevice(DeviceOrientationSensor.current);
/// }
///
/// protected void OnDisable()
/// {
/// InputSystem.DisableDevice(DeviceOrientationSensor.current);
/// }
///
/// protected void Update()
/// {
/// var orientation = DeviceOrientationSensor.current.orientation.ReadValue();
/// //...
/// }
/// }
/// </code>
/// </example>
/// </remarks>
[InputControlLayout(stateType = typeof(DeviceOrientationState), displayName = "Orientation")]
public class DeviceOrientationSensor : Sensor
{
/// <summary>
/// The physical orientation of the device.
/// </summary>
/// <value>Control reporting the current <see cref="DeviceOrientation"/>.</value>
public OrientationControl orientation { get; protected set; }

/// <summary>
/// The orientation sensor that was last added or had activity last.
/// </summary>
/// <value>Current orientation sensor or <c>null</c>.</value>
public static DeviceOrientationSensor current { get; private set; }

/// <inheritdoc />
public override void MakeCurrent()
{
base.MakeCurrent();
current = this;
}

/// <inheritdoc />
protected override void OnRemoved()
{
base.OnRemoved();
if (current == this)
current = null;
}

/// <inheritdoc />
protected override void FinishSetup()
{
orientation = GetChildControl<OrientationControl>("orientation");
base.FinishSetup();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2053,6 +2053,7 @@ internal void InitializeData()
RegisterControlLayout("Touch", typeof(TouchControl));
RegisterControlLayout("TouchPhase", typeof(TouchPhaseControl));
RegisterControlLayout("TouchPress", typeof(TouchPressControl));
RegisterControlLayout("Orientation", typeof(OrientationControl));

RegisterControlLayout("Gamepad", typeof(Gamepad)); // Devices.
RegisterControlLayout("Joystick", typeof(Joystick));
Expand All @@ -2073,6 +2074,7 @@ internal void InitializeData()
RegisterControlLayout("HumiditySensor", typeof(HumiditySensor));
RegisterControlLayout("AmbientTemperatureSensor", typeof(AmbientTemperatureSensor));
RegisterControlLayout("StepCounter", typeof(StepCounter));
RegisterControlLayout("DeviceOrientationSensor", typeof(DeviceOrientationSensor));
RegisterControlLayout("TrackedDevice", typeof(TrackedDevice));

// Precompiled layouts.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ public static void Initialize()
.WithDeviceClass("AndroidSensor")
.WithCapability("sensorType", AndroidSensorType.HingeAngle));

// Device orientation is not an Android hardware sensor; it is reported as its own device
// class and maps directly to the base DeviceOrientationSensor layout.
InputSystem.RegisterLayoutMatcher("DeviceOrientationSensor",
new InputDeviceMatcher()
.WithInterface(kAndroidInterface)
.WithDeviceClass("Orientation"));

InputSystem.onFindLayoutForDevice += OnFindLayoutForDevice;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ public static void Initialize()
new InputDeviceMatcher()
.WithInterface("iOS")
.WithDeviceClass("LinearAcceleration"));
InputSystem.RegisterLayoutMatcher("DeviceOrientationSensor",
new InputDeviceMatcher()
.WithInterface("iOS")
.WithDeviceClass("Orientation"));
#if UNITY_EDITOR || UNITY_IOS
InputSystem.RegisterLayout<iOSStepCounter>();
// Don't add devices for InputTestRuntime
Expand Down