diff --git a/Assets/Tests/InputSystem/CoreTests_Devices.cs b/Assets/Tests/InputSystem/CoreTests_Devices.cs index dbd229c74b..e91eb87784 100644 --- a/Assets/Tests/InputSystem/CoreTests_Devices.cs +++ b/Assets/Tests/InputSystem/CoreTests_Devices.cs @@ -2385,6 +2385,46 @@ public void Devices_JoysticksHaveDeadzonesOnStick() Assert.That(joystick.stick.ReadValue(), Is.EqualTo(Vector2.zero)); } + [Test] + [Category("Devices")] + public void Devices_CanCreateGenericRacingWheel() + { + var wheel = InputSystem.AddDevice(); + + Assert.That(RacingWheel.current, Is.SameAs(wheel)); + + Assert.That(wheel.allControls.OfType().Select(c => c.ReadValue()), Is.All.Zero); + Assert.That(wheel.gear.ReadValue(), Is.Zero); + + AssertButtonPress(wheel, new RacingWheelState().WithButton(RacingWheelButton.DpadUp), wheel.dpad.up); + AssertButtonPress(wheel, new RacingWheelState().WithButton(RacingWheelButton.DpadDown), wheel.dpad.down); + AssertButtonPress(wheel, new RacingWheelState().WithButton(RacingWheelButton.DpadLeft), wheel.dpad.left); + AssertButtonPress(wheel, new RacingWheelState().WithButton(RacingWheelButton.DpadRight), wheel.dpad.right); + AssertButtonPress(wheel, new RacingWheelState().WithButton(RacingWheelButton.GearUp), wheel.gearUp); + AssertButtonPress(wheel, new RacingWheelState().WithButton(RacingWheelButton.GearDown), wheel.gearDown); + AssertButtonPress(wheel, new RacingWheelState().WithButton(RacingWheelButton.Menu), wheel.menu); + AssertButtonPress(wheel, new RacingWheelState().WithButton(RacingWheelButton.View), wheel.view); + + InputSystem.QueueStateEvent(wheel, + new RacingWheelState + { + gear = 123, + throttle = 0.234f, + brake = 0.345f, + clutch = 0.456f, + handbrake = 0.567f, + wheel = 0.678f, + }); + InputSystem.Update(); + + Assert.That(wheel.gear.ReadValue(), Is.EqualTo(123)); + Assert.That(wheel.throttle.ReadValue(), Is.EqualTo(0.234f)); + Assert.That(wheel.brake.ReadValue(), Is.EqualTo(0.345f)); + Assert.That(wheel.clutch.ReadValue(), Is.EqualTo(0.456f)); + Assert.That(wheel.handbrake.ReadValue(), Is.EqualTo(0.567f)); + Assert.That(wheel.wheel.ReadValue(), Is.EqualTo(0.678f)); + } + [Test] [Category("Devices")] public void Devices_PointerDeltasDoNotAccumulateFromPreviousFrame() diff --git a/Packages/com.unity.inputsystem/CHANGELOG.md b/Packages/com.unity.inputsystem/CHANGELOG.md index 79f98f9d7d..ef53ccea95 100755 --- a/Packages/com.unity.inputsystem/CHANGELOG.md +++ b/Packages/com.unity.inputsystem/CHANGELOG.md @@ -33,6 +33,8 @@ however, it has to be formatted properly to pass verification tests. - Added support for PS5 DualSense controllers on Mac and Windows. - Improved the user experience when creating single vs multi-touch touchscreen bindings in the Input Action Asset editor by making both options visible in the input action dropdown menu. Now it's not neccessary to be aware of the touch\*/press path binding syntax ([case 1357664](https://issuetracker.unity3d.com/issues/inputsystem-touchscreens-multi-touch-doesnt-work-when-using-a-custom-inputactionasset)). +- Added a new `RacingWheel` device class that represents a generic racing wheel. + * Support for specific wheels will come later. ## [1.1.1] - 2021-09-03 diff --git a/Packages/com.unity.inputsystem/InputSystem/Devices/RacingWheel.cs b/Packages/com.unity.inputsystem/InputSystem/Devices/RacingWheel.cs new file mode 100644 index 0000000000..0f942a749d --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Devices/RacingWheel.cs @@ -0,0 +1,248 @@ +using UnityEngine.InputSystem.Controls; +using UnityEngine.InputSystem.Layouts; +using UnityEngine.InputSystem.LowLevel; +using UnityEngine.InputSystem.Utilities; + +namespace UnityEngine.InputSystem.LowLevel +{ + /// + /// Input state for a . + /// + /// + /// + /// + /// var wheel = InputSystem.AddDevice<RacingWheel>(); + /// + /// InputSystem.QueueStateEvent(wheel, + /// new RacingWheelState + /// { + /// gear = 2, + /// wheel = 0.5f, // Halfway right. + /// throttle = 0.25f, // Quarter pressure on gas pedal. + /// }); + /// + /// + /// + public struct RacingWheelState : IInputStateTypeInfo + { + public static FourCC Format => new FourCC('W', 'E', 'E', 'L'); + + [InputControl(name = "dpad", layout = "Dpad", usage = "Hatswitch", displayName = "D-Pad", format = "BIT", sizeInBits = 4, bit = 0)] + [InputControl(name = "dpad/up", format = "BIT", bit = (uint)RacingWheelButton.DpadUp, sizeInBits = 1)] + [InputControl(name = "dpad/right", format = "BIT", bit = (uint)RacingWheelButton.DpadRight, sizeInBits = 1)] + [InputControl(name = "dpad/down", format = "BIT", bit = (uint)RacingWheelButton.DpadDown, sizeInBits = 1)] + [InputControl(name = "dpad/left", format = "BIT", bit = (uint)RacingWheelButton.DpadLeft, sizeInBits = 1)] + [InputControl(name = "gearUp", layout = "Button", bit = (uint)RacingWheelButton.GearUp, displayName = "Next Gear")] + [InputControl(name = "gearDown", layout = "Button", bit = (uint)RacingWheelButton.GearDown, displayName = "Previous Gear")] + [InputControl(name = "menu", alias = "start", layout = "Button", bit = (uint)RacingWheelButton.Menu, displayName = "Menu")] + [InputControl(name = "view", alias = "select", layout = "Button", bit = (uint)RacingWheelButton.View, displayName = "View")] + public uint buttons; + + /// + /// Current gear selected in gear shift. + /// + [InputControl(displayName = "Gear", layout = "Integer")] + public int gear; + + /// + /// Position of wheel in [-1,1] range. -1 is all the way left, 1 is all the way right. + /// + [InputControl(displayName = "Wheel", layout = "Axis")] + public float wheel; + + /// + /// Position of throttle/gas pedal in [0,1] range. 0 is fully depressed, 1 is pressed all the way down. + /// + [InputControl(displayName = "Throttle", alias = "gas", layout = "Axis")] + public float throttle; + + /// + /// Position of brake pedal in [0,1] range. 0 is fully depressed, 1 is pressed all the way down. + /// + [InputControl(displayName = "Break", layout = "Axis")] + public float brake; + + /// + /// Position of clutch pedal in [0,1] range. 0 is fully depressed, 1 is pressed all the way down. + /// + [InputControl(displayName = "Clutch", layout = "Axis")] + public float clutch; + + /// + /// Position of handbrake in [0,1] range. 0 is fully released, 1 is engaged at maximum. + /// + [InputControl(displayName = "Handbrake", layout = "Axis")] + public float handbrake; + + public FourCC format => Format; + + /// + /// Set the specific buttons to be pressed or unpressed. + /// + /// A racing wheel button. + /// Whether to set to be pressed or not pressed in + /// . + /// RacingWheelState with a modified mask. + public RacingWheelState WithButton(RacingWheelButton button, bool down = true) + { + Debug.Assert((int)button < 32, $"Expected button < 32, so we fit into the 32 bit wide bitmask"); + var bit = 1U << (int)button; + if (down) + buttons |= bit; + else + buttons &= ~bit; + return this; + } + } + + /// + /// Buttons on a . + /// + public enum RacingWheelButton + { + /// + /// The up button on a wheel's dpad. + /// + DpadUp = 0, + + /// + /// The down button on a wheel's dpad. + /// + DpadDown = 1, + + /// + /// The left button on a wheel's dpad. + /// + DpadLeft = 2, + + /// + /// The right button on a wheel's dpad. + /// + DpadRight = 3, + + /// + /// Button to shift up. + /// + GearUp = 4, + + /// + /// Button to shift down. + /// + GearDown = 5, + + /// + /// The "menu" button. + /// + Menu = 6, + + /// + /// The "view" button. + /// + View = 7, + } +} + +namespace UnityEngine.InputSystem +{ + /// + /// Base class for racing wheels. + /// + [InputControlLayout(stateType = typeof(RacingWheelState), displayName = "Racing Wheel", isGenericTypeOfDevice = true)] + public class RacingWheel : InputDevice + { + /// + /// The D-Pad control on the wheel. + /// + public DpadControl dpad { get; protected set; } + + /// + /// Button to shift gears up. + /// + public ButtonControl gearUp { get; protected set; } + + /// + /// Button to shift gears down. + /// + public ButtonControl gearDown { get; protected set; } + + /// + /// The menu/start button on the wheel. + /// + public ButtonControl menu { get; protected set; } + + /// + /// The view/select button on the wheel. + /// + public ButtonControl view { get; protected set; } + + /// + /// The control that represents the currently selected gear. + /// + public IntegerControl gear { get; protected set; } + + /// + /// The position of the wheel in [-1,1] range. -1 is all the way left, 1 is all the way right, 0 is in neutral position. + /// + public AxisControl wheel { get; protected set; } + + /// + /// The position of the gas/throttle pedal or control. In [0,1] range. 0 is fully released and 1 is pressed all the way down. + /// + public AxisControl throttle { get; protected set; } + + /// + /// The position of the brake pedal or control. In [0,1] range. 0 is fully released and 1 is pressed all the way down. + /// + public AxisControl brake { get; protected set; } + + /// + /// The position of the clutch pedal or control. In [0,1] range. 0 is fully released and 1 is pressed all the way down. + /// + public AxisControl clutch { get; protected set; } + + /// + /// The position of the handbrake control. In [0,1] range. 0 is fully released and 1 is engaged at maximum. + /// + public AxisControl handbrake { get; protected set; } + + /// + /// The currently active racing wheel or null if no racing wheel is present. + /// + public static RacingWheel current { get; private set; } + + /// + /// Make this the racing wheel. This happens automatically for a racing wheel + /// that receives input. + /// + public override void MakeCurrent() + { + base.MakeCurrent(); + current = this; + } + + protected override void OnRemoved() + { + base.OnRemoved(); + + if (this == current) + current = null; + } + + protected override void FinishSetup() + { + base.FinishSetup(); + + dpad = GetChildControl("dpad"); + gearUp = GetChildControl("gearUp"); + gearDown = GetChildControl("gearDown"); + menu = GetChildControl("menu"); + view = GetChildControl("view"); + gear = GetChildControl("gear"); + wheel = GetChildControl("wheel"); + throttle = GetChildControl("throttle"); + brake = GetChildControl("brake"); + clutch = GetChildControl("clutch"); + handbrake = GetChildControl("handbrake"); + } + } +} diff --git a/Packages/com.unity.inputsystem/InputSystem/Devices/RacingWheel.cs.meta b/Packages/com.unity.inputsystem/InputSystem/Devices/RacingWheel.cs.meta new file mode 100644 index 0000000000..d8970886c5 --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Devices/RacingWheel.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 77db223f02364db3a3181517c53a12d4 +timeCreated: 1634644565 \ No newline at end of file diff --git a/Packages/com.unity.inputsystem/InputSystem/InputManager.cs b/Packages/com.unity.inputsystem/InputSystem/InputManager.cs index 75f2f37432..3f26852725 100644 --- a/Packages/com.unity.inputsystem/InputSystem/InputManager.cs +++ b/Packages/com.unity.inputsystem/InputSystem/InputManager.cs @@ -1829,6 +1829,7 @@ internal void InitializeData() RegisterControlLayout("Gamepad", typeof(Gamepad)); // Devices. RegisterControlLayout("Joystick", typeof(Joystick)); + RegisterControlLayout("RacingWheel", typeof(RacingWheel)); RegisterControlLayout("Keyboard", typeof(Keyboard)); RegisterControlLayout("Pointer", typeof(Pointer)); RegisterControlLayout("Mouse", typeof(Mouse));