-
Notifications
You must be signed in to change notification settings - Fork 330
NEW: Add generic RacingWheel class. #1430
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,248 @@ | ||
| using UnityEngine.InputSystem.Controls; | ||
| using UnityEngine.InputSystem.Layouts; | ||
| using UnityEngine.InputSystem.LowLevel; | ||
| using UnityEngine.InputSystem.Utilities; | ||
|
|
||
| namespace UnityEngine.InputSystem.LowLevel | ||
| { | ||
| /// <summary> | ||
| /// Input state for a <see cref="RacingWheel"/>. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// <example> | ||
| /// <code> | ||
| /// 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. | ||
| /// }); | ||
| /// </code> | ||
| /// </example> | ||
| /// </remarks> | ||
| 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; | ||
|
|
||
| /// <summary> | ||
| /// Current gear selected in gear shift. | ||
| /// </summary> | ||
| [InputControl(displayName = "Gear", layout = "Integer")] | ||
| public int gear; | ||
|
|
||
| /// <summary> | ||
| /// Position of wheel in [-1,1] range. -1 is all the way left, 1 is all the way right. | ||
| /// </summary> | ||
| [InputControl(displayName = "Wheel", layout = "Axis")] | ||
| public float wheel; | ||
|
|
||
| /// <summary> | ||
| /// Position of throttle/gas pedal in [0,1] range. 0 is fully depressed, 1 is pressed all the way down. | ||
| /// </summary> | ||
| [InputControl(displayName = "Throttle", alias = "gas", layout = "Axis")] | ||
| public float throttle; | ||
|
|
||
| /// <summary> | ||
| /// Position of brake pedal in [0,1] range. 0 is fully depressed, 1 is pressed all the way down. | ||
| /// </summary> | ||
| [InputControl(displayName = "Break", layout = "Axis")] | ||
| public float brake; | ||
|
|
||
| /// <summary> | ||
| /// Position of clutch pedal in [0,1] range. 0 is fully depressed, 1 is pressed all the way down. | ||
| /// </summary> | ||
| [InputControl(displayName = "Clutch", layout = "Axis")] | ||
| public float clutch; | ||
|
|
||
| /// <summary> | ||
| /// Position of handbrake in [0,1] range. 0 is fully released, 1 is engaged at maximum. | ||
| /// </summary> | ||
| [InputControl(displayName = "Handbrake", layout = "Axis")] | ||
| public float handbrake; | ||
|
|
||
| public FourCC format => Format; | ||
|
|
||
| /// <summary> | ||
| /// Set the specific buttons to be pressed or unpressed. | ||
| /// </summary> | ||
| /// <param name="button">A racing wheel button.</param> | ||
| /// <param name="down">Whether to set <paramref name="button"/> to be pressed or not pressed in | ||
| /// <see cref="buttons"/>.</param> | ||
| /// <returns>RacingWheelState with a modified <see cref="buttons"/> mask.</returns> | ||
| 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; | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Buttons on a <see cref="RacingWheel"/>. | ||
| /// </summary> | ||
| public enum RacingWheelButton | ||
| { | ||
| /// <summary> | ||
| /// The up button on a wheel's dpad. | ||
| /// </summary> | ||
| DpadUp = 0, | ||
|
|
||
| /// <summary> | ||
| /// The down button on a wheel's dpad. | ||
| /// </summary> | ||
| DpadDown = 1, | ||
|
|
||
| /// <summary> | ||
| /// The left button on a wheel's dpad. | ||
| /// </summary> | ||
| DpadLeft = 2, | ||
|
|
||
| /// <summary> | ||
| /// The right button on a wheel's dpad. | ||
| /// </summary> | ||
| DpadRight = 3, | ||
|
|
||
| /// <summary> | ||
| /// Button to shift up. | ||
| /// </summary> | ||
| GearUp = 4, | ||
|
|
||
| /// <summary> | ||
| /// Button to shift down. | ||
| /// </summary> | ||
| GearDown = 5, | ||
|
|
||
| /// <summary> | ||
| /// The "menu" button. | ||
| /// </summary> | ||
| Menu = 6, | ||
|
|
||
| /// <summary> | ||
| /// The "view" button. | ||
| /// </summary> | ||
| View = 7, | ||
| } | ||
| } | ||
|
|
||
| namespace UnityEngine.InputSystem | ||
| { | ||
| /// <summary> | ||
| /// Base class for racing wheels. | ||
| /// </summary> | ||
| [InputControlLayout(stateType = typeof(RacingWheelState), displayName = "Racing Wheel", isGenericTypeOfDevice = true)] | ||
| public class RacingWheel : InputDevice | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Biggest question for me is how we want this to relate to So, guess the question is how much we want to put in here in the abstract definition.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Likely shouldn't be a gamepad, but rather dpad from racing wheel should participate in navigation.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wondering about additional controls, though. Seems most sensible to add them here, too. Don't think the wheel should separately be represented as a gamepad but it should probably have ABXY face buttons and shoulder buttons instead of just the narrow set that's currently on the device. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree any additional face buttons should exist with the race wheel device. |
||
| { | ||
| /// <summary> | ||
| /// The D-Pad control on the wheel. | ||
| /// </summary> | ||
| public DpadControl dpad { get; protected set; } | ||
|
|
||
| /// <summary> | ||
| /// Button to shift gears up. | ||
| /// </summary> | ||
| public ButtonControl gearUp { get; protected set; } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any idea how https://www.logitechg.com/en-us/products/driving/driving-force-shifter.941-000119.html is exposed on HID layer? Not sure if gear lever needs more work here or not
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My assumption is this would use the Also not sure how it's exposed at the HID layer. My very limited experience so far with Logitech wheels has been that they masquerade as plain XInput devices and have no interesting properties whatsoever as HIDs and need interfacing through the Logitech SDK to get to the advanced stuff. But no clue about the gear shifters. |
||
|
|
||
| /// <summary> | ||
| /// Button to shift gears down. | ||
| /// </summary> | ||
| public ButtonControl gearDown { get; protected set; } | ||
|
|
||
| /// <summary> | ||
| /// The menu/start button on the wheel. | ||
| /// </summary> | ||
| public ButtonControl menu { get; protected set; } | ||
|
|
||
| /// <summary> | ||
| /// The view/select button on the wheel. | ||
| /// </summary> | ||
| public ButtonControl view { get; protected set; } | ||
|
|
||
| /// <summary> | ||
| /// The control that represents the currently selected gear. | ||
| /// </summary> | ||
| public IntegerControl gear { get; protected set; } | ||
|
|
||
| /// <summary> | ||
| /// 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. | ||
| /// </summary> | ||
| public AxisControl wheel { get; protected set; } | ||
|
|
||
| /// <summary> | ||
| /// 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. | ||
| /// </summary> | ||
| public AxisControl throttle { get; protected set; } | ||
|
|
||
| /// <summary> | ||
| /// The position of the brake pedal or control. In [0,1] range. 0 is fully released and 1 is pressed all the way down. | ||
| /// </summary> | ||
| public AxisControl brake { get; protected set; } | ||
|
|
||
| /// <summary> | ||
| /// The position of the clutch pedal or control. In [0,1] range. 0 is fully released and 1 is pressed all the way down. | ||
| /// </summary> | ||
| public AxisControl clutch { get; protected set; } | ||
|
|
||
| /// <summary> | ||
| /// The position of the handbrake control. In [0,1] range. 0 is fully released and 1 is engaged at maximum. | ||
| /// </summary> | ||
| public AxisControl handbrake { get; protected set; } | ||
|
|
||
| /// <summary> | ||
| /// The currently active racing wheel or <c>null</c> if no racing wheel is present. | ||
| /// </summary> | ||
| public static RacingWheel current { get; private set; } | ||
|
|
||
| /// <summary> | ||
| /// Make this the <see cref="current"/> racing wheel. This happens automatically for a racing wheel | ||
| /// that receives input. | ||
| /// </summary> | ||
| 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<DpadControl>("dpad"); | ||
| gearUp = GetChildControl<ButtonControl>("gearUp"); | ||
| gearDown = GetChildControl<ButtonControl>("gearDown"); | ||
| menu = GetChildControl<ButtonControl>("menu"); | ||
| view = GetChildControl<ButtonControl>("view"); | ||
| gear = GetChildControl<IntegerControl>("gear"); | ||
| wheel = GetChildControl<AxisControl>("wheel"); | ||
| throttle = GetChildControl<AxisControl>("throttle"); | ||
| brake = GetChildControl<AxisControl>("brake"); | ||
| clutch = GetChildControl<AxisControl>("clutch"); | ||
| handbrake = GetChildControl<AxisControl>("handbrake"); | ||
| } | ||
| } | ||
| } | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We likely don't need state struct, rather only
RacingWheeldevice class, so users can write code against that, as device structs will come with platform specific devices. And HID already has it's own thing anyway.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My experience has been that every time we tried to hide the state struct or do away with this, it just ended up being painful because you had no way to send input to the device without using the tedious APIs that write values through individual controls.
It's like
GamepadState.Gamepadhas many different variations and possible states but just being able to spawn a gamepad and directly feed it input is quite useful. IMO better to treat all devices the same way there.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So let's say PS4/PS5 code will need more state, e.g. it will be like DualShock gamepad vs Gamepad, how would that work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as for the current DualShock support. I.e. it'd just come up with its own state format.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok but then it's questionable, e.g. you will not able to queue RacingWheelState into device that is racing wheel but implements it's own state format.