Giter Site home page Giter Site logo

Comments (24)

jimon avatar jimon commented on June 2, 2024

Question, so let's say users use this API earlier in development of their game, satisfied with it, and then later in the development they need to support control rebinding, how would that look like?

from inputsystem.

jimon avatar jimon commented on June 2, 2024

Have you had thoughts about making enum Inputs a partial enum? (doesn't exist in C# but still)

Thinking if we could achieve stability of constants of that enum (e.g. adding new key should change value of Key_U) we could achieve better things down the line (native->managed api transition stability)

from inputsystem.

jimon avatar jimon commented on June 2, 2024

Have you tried going with method overloads? E.g.

    public static bool IsButtonPressed(Inputs input);
    public static bool IsButtonDown(Inputs input);
    public static bool IsButtonUp(Inputs input);

    public static bool IsButtonPressed(GamepadButton button, GamepadSlot gamepadSlot = GamepadSlot.Any);
    public static bool IsButtonDown(GamepadButton button, GamepadSlot gamepadSlot = GamepadSlot.Any);
    public static bool IsButtonUp(GamepadButton input, GamepadSlot gamepadSlot = GamepadSlot.Any);

    ... etc ...

Seems like if we do GamepadButton-esque enums for every sub-type we could provide overloads for each and rely on type safety for API UX

from inputsystem.

jimon avatar jimon commented on June 2, 2024

Why there is no public static Vector2 GetAxis(Inputs stick); and no public static Vector2 GetAxis(Inputs horizontal, Inputs vertical);? Feels like providing multiple enum values for same control could work given that copies will point to different type

That way in the enum we would have Up, Down, Left, Right, Horizonal, Vertical, 2D. Imho will provide better API UX if we can leverage autocomplete to do the right thing.

from inputsystem.

andrew-oc avatar andrew-oc commented on June 2, 2024

Question, so let's say users use this API earlier in development of their game, satisfied with it, and then later in the development they need to support control rebinding, how would that look like?

This part of the API doesn't support control rebinding. The action part, coming next, does though. But the path would be to replace the Input.IsControlxxx method calls with the equivalent Input.[action].

Have you had thoughts about making enum Inputs a partial enum? (doesn't exist in C# but still)

Thinking if we could achieve stability of constants of that enum (e.g. adding new key should change value of Key_U) we could achieve better things down the line (native->managed api transition stability)

Can you elaborate? What would that look like if the concept of partial enum doesn't exist in C#? What would be the motivation to add another enum there? It should already cover all inputs on the standard devices that this API supports.

Have you tried going with method overloads? E.g.

    public static bool IsButtonPressed(Inputs input);
    public static bool IsButtonDown(Inputs input);
    public static bool IsButtonUp(Inputs input);

    public static bool IsButtonPressed(GamepadButton button, GamepadSlot gamepadSlot = GamepadSlot.Any);
    public static bool IsButtonDown(GamepadButton button, GamepadSlot gamepadSlot = GamepadSlot.Any);
    public static bool IsButtonUp(GamepadButton input, GamepadSlot gamepadSlot = GamepadSlot.Any);

    ... etc ...

Seems like if we do GamepadButton-esque enums for every sub-type we could provide overloads for each and rely on type safety for API UX

I did look at that, but I felt that it implied that you couldn't use IsControlPressed/Up/Down for gamepad buttons, which you can, and in a completely type safe way.

Why there is no public static Vector2 GetAxis(Inputs stick); and no public static Vector2 GetAxis(Inputs horizontal, Inputs vertical);? Feels like providing multiple enum values for same control could work given that copies will point to different type

That way in the enum we would have Up, Down, Left, Right, Horizonal, Vertical, 2D. Imho will provide better API UX if we can leverage autocomplete to do the right thing.

Because those wouldn't be entirely type safe. It would be possible to pass the wrong enum in both cases, and I feel like we should avoid runtime errors where possible.

from inputsystem.

jimon avatar jimon commented on June 2, 2024

Existence of both Inputs.Gamepad_DpadUp and GamepadButton.DpadUp at a same time is a bit of a deal breaker for me tbh. Can we work around so there is always only one definition for a control?

from inputsystem.

ekcoh avatar ekcoh commented on June 2, 2024

Regarding Pressed, Released, Down, Up. I think its key to keep consistency in these. E.g. Pressed is an event/transition so is Released right? Down/Up are absolute state evaluations right? - It feels IsPressed is confusing since nothing is constantly transitioning into pressed? IsDown/IsUp makes sense though. Noticed this in, e.g.

  public class FireProjectiles : MonoBehaviour
  {
    [SerializeField] private float m_FireInterval;
    [SerializeField] private GameObject m_Projectile;
    private float m_LastFireTime;

    public void Update()
    {
      if (Input.IsGamepadButtonPressed(GamepadButton.South) && Time.time - m_LastFireTime > m_FireInterval)
      {
        Instantiate(m_Projectile);
        m_LastFireTime = Time.time;
      }
    }
  }

Or is this implying everytime the button is pressed as in down, up sequence and one such event happened during a frame one projectile is spawned. If two such events happened during a frame one projectile is spawned?

from inputsystem.

lyndon-unity avatar lyndon-unity commented on June 2, 2024

What does this property represent? It was the only one that wasn't intuitive to me.
public static Vector2 mousePresent { get; }

from inputsystem.

andrew-oc avatar andrew-oc commented on June 2, 2024

@ekcoh The intent was that Pressed means this control is currently held down. Maybe IsHeld is better? Down and up are the actual state transitions. Those methods are intended to return true in the frame that the control is pressed or released, and they're named for familiarity with the legacy API.

@lyndon-unity It's meant to represent whether a mouse is connected or not, but should have had a bool return type.

from inputsystem.

lyndon-unity avatar lyndon-unity commented on June 2, 2024

@lyndon-unity It's meant to represent whether a mouse is connected or not, but should have had a bool return type.

It would be good to be consistent with the pad function naming which uses the phrase 'connected'
public static bool IsGamepadConnected(GamepadSlot slot);

I momentarily wondered then if it should be moved to a function and take a parameter but I see is a convenience for the common case with a single mouse (or first mouse). Do we need both?

Do we need a IsJoystickConnected(int joystickIndex);

I'm also wondering why we have an enum for gamepad but just int for joystick.
I see its because we have the 'all/any' cases. Do we need that for Joysticks too though?

Or am I confused with what joystickIndex is? Is this parameter a device index or for multiple sticks on a single device
public static Vector2 GetJoystickAxis(int joystickIndex);

from inputsystem.

andrew-oc avatar andrew-oc commented on June 2, 2024

It would be good to be consistent with the pad function naming which uses the phrase 'connected' public static bool IsGamepadConnected(GamepadSlot slot);

Initially it was called mouseConnected but it ended up as mousePresent for two reasons. One, familiarity with the legacy API which also calls it mousePresent, and two, a 'mouse' can be any device that allows a cursor to be moved, like a trackpad in a laptop or gamepad, so it feels wrong calling it "connected". What do you think?

I momentarily wondered then if it should be moved to a function and take a parameter but I see is a convenience for the common case with a single mouse (or first mouse). Do we need both?

Yeah, it's a toss up between keeping the API surface as small as possible (bearing in mind it will grow a bit over the next few proposals) and providing convenience methods for every device. It is still possible to check if a mouse is present even without this convenience method by checking the mice collection for a non-null device in any slot but my thoughts on this is that it's not a common enough use case to have it's own API method.

Do we need a IsJoystickConnected(int joystickIndex);

I'm also wondering why we have an enum for gamepad but just int for joystick. I see its because we have the 'all/any' cases. Do we need that for Joysticks too though?

Same as previous argument.

Or am I confused with what joystickIndex is? Is this parameter a device index or for multiple sticks on a single device
public static Vector2 GetJoystickAxis(int joystickIndex);

Nope, you're correct. It's a slot index for a device. Maybe we could rename GamepadSlot to DeviceSlot and use that for all APIs that take a slot index. Would that make things better?

from inputsystem.

lyndon-unity avatar lyndon-unity commented on June 2, 2024

Initially it was called mouseConnected but it ended up as mousePresent for two reasons. One, familiarity with the legacy API which also calls it mousePresent, and two, a 'mouse' can be any device that allows a cursor to be moved, like a trackpad in a laptop or gamepad, so it feels wrong calling it "connected". What do you think?

Thank you I wasn't aware of those aspects. Your reasoning seems fair to me. Perhaps we simply need to add a comment on this property to make it a little clearer. E.g.

public static Vector2 mousePresent { get; } // True if a mouse, trackpad or similar is present/connected.

(I was then wondering if IsGamepadConnected should be renamed IsGamepadPresent for consistency, but I still prefer the phrase connected so I'm I've mixed feelings.)

Maybe we could rename GamepadSlot to DeviceSlot and use that for all APIs that take a slot index. Would that make things better?

I like that proposal and feel it would make it more consistent and allow for the All/Any case for Joysticks.

from inputsystem.

ekcoh avatar ekcoh commented on June 2, 2024

Regarding previous comment/feedback

@ekcoh The intent was that Pressed means this control is currently held down. Maybe IsHeld is better? Down and up are the actual state transitions. Those methods are intended to return true in the frame that the control is pressed or released, and they're named for familiarity with the legacy API.

This was also discussed in other review thread, IsHeld is better I think but also reflects assumption about push button which might be fine. IsHeld is definately a contender, other options include I guess IsActuated/IsActive/IsTriggered/IsOn. Maybe it would be helpful to try to define whether we want to model the physical action in the names or the logical. On a physical model (class) it makes more sense to use e.g. Held, Down, Up etc if it models a physical entity, for a logical entity is feels like it makes more sense with e.g. On, Off, High, Low, Active etc. Naming is hard, but I think it might be good if we avoid mixing physical and logical modeling/representation.

from inputsystem.

ekcoh avatar ekcoh commented on June 2, 2024

Just for clarification I assume this API is also subject for down-sampling to frame granularity?E.g. use-case example: Perform some gameplay action when both the left keyboard Control key and left mouse button are pressed.` would basically be true if left keyboard control key and left mouse button was pressed at some point during the same frame, not necessarily at the same time? (This is just for making sure interpretation is correct)

Maybe its wise to scope out higher-frequency events since it would drive complexity and those interested can use other APIs

from inputsystem.

ekcoh avatar ekcoh commented on June 2, 2024

I noticed we have IsControlPressed(Inputs input); should there be a IsControlReleased(Inputs input); for the inverse edge? Or is this reflecting if actuated?

from inputsystem.

ekcoh avatar ekcoh commented on June 2, 2024

Regarding previous discussion of "Connected" vs "Present" based off previous APIs I have worked with I would suggest to stick to defining something like:

Connected - Is a specific device connected to the system. This may not imply that its available since it might be connected and be possible to enumerate, but it might be disabled in software, for example its driver being disabled but enumerable via underlying protocols. This is applies to both peripherals and device interfacing via e.g. on-board USB or other hardware interfaces. An integrated device, e.g. touch screen is typically always connected but might no be present if disabled in software.

Present - A higher level concept indicating that the device is available and active. A device wouldn't be present if connected and disabled in driver/os or software level. A device being present indicates it can be used.

Such detail is likely not applicable to this high level API anyway but it might be good to use similar concepts between API layers. If we already use connected maybe we need to stick to it.

from inputsystem.

ekcoh avatar ekcoh commented on June 2, 2024

Based on previous comments it sounds like the intention with the enum is to be applicable to this API surface only? If not to me it looks like an oppertunity to map usages that could be applicable and potentially aliased for any control, including all HID controls long-term and potentially also be fitted into future lower layers. This might imply that its not an enum but rather integer constants under the hood of a type if type safety is intended which may be used to support partial enums as mentioned by Dmytro and/or HID usage aliasing and/or Spatial aliasing and/or user-extension within custom ranges.

Or what benefits do you see with enum compared to numeric constants (under a layer of type safety)? - I assume the key point here is provide compile-time type safety?

Is the slot concept intended to be applied for all device interface models?

from inputsystem.

ekcoh avatar ekcoh commented on June 2, 2024

It seems like the mouse accessors are different from the other accessors but there is still a concept of a collection of mice? I noticed the reply to Lyndon about pointer devices, but since some platforms, e.g. console, typically never have a pointer device what is the motivation for having it different from other device models?

from inputsystem.

ekcoh avatar ekcoh commented on June 2, 2024

What benefit do you see from having GamepadSlot an enum? It seems like an unsigned would do just fine for the "instance" use-case?

from inputsystem.

ekcoh avatar ekcoh commented on June 2, 2024

Review meeting:

Discussed alternatives to enum Inputs:

  • if structs could be an alternative
  • type safety in relation enum Inputs.

public bool Input.IsControlPressed(GamepadButton button);
vs
public struct bool IsControlPressed(Button button);

One angle would be implementation aspect with e.g. HID page / id.
Another angle from user is using auto-complete. Less fluid with dot vs underscore.
Regarding above the biggest downside might be overloads. Might be undesirable to have too abstract identifiers.
Clarified that public static bool IsControlPressed(Inputs) is only intended for the first device.

Discussed Inputs enum and whether Inputs need to be explicitly assigned or not. There are pros and cons with both approaches.

Way forward: Lets proceed with enum version for usability evaluation and reevaluate struct approach if highlighted in feedback.

from inputsystem.

ekcoh avatar ekcoh commented on June 2, 2024

Review meeting:

Discussed why we have mousePresent, inherited from existing API. Should we consider calling this "pointer" to not let user assume this is a mouse. If user is developing for mobile and thinking mobile should we call this "pointer" which would be touch. Discussed pen and touch and whether to differentiate or not. This might also make it confusing with scroll delta. What is use case for mousePosition. From a less-work-for-developer point of view a pointer is likely more useful to provide an abstraction.

Use-case for it, motivate why do we need that compares like isKeyboardPresent.

Way forward: Drop mouse present. Pointer could be an alternative.

Discussed whether e.g.
public static Vector2 GetScreenPosition(PositionSource source)

This could provide consistency with e.g. GetAxis, IsControlDown etc.

Discussed if e.g. XR use-cases might be relevant for this API or more advanced use-cases. Will we be able to build on-top of this.

There are some inconsistency in the API design, this is intentional, but consistency might be beneficial for extendability. E.g. handle system keyboard similar to a "system gamepad".
Discussed device specific and device unspecific.

Clarified that IReadonlyList and friends are mapping 1:1 with existing InputSystem collections of current devices.

Suggested to join joystick and gamepad slots. Or generalize into DeviceSlots. One option would be to have ints instead to avoid casting. Clarified that slot concept is intended to be assigned and then stick and leaves a reassignable hole when disconnected.

MInor: IsGamepadButtonUp first argument should be "button".

Way forward: Consider enum or int but there is benefit for Any and All when using enum, max value could be a constant. APIs could be generalized for instance/slot specific access also for other device types if needed.

Some concerns regarding how to handle e.g. Android specific key code. Other example is e.g. pointing devices.
Extendability might be problematic with fixed enums.

from inputsystem.

jimon avatar jimon commented on June 2, 2024

After some poking at this, I would like to propose a slightly tweaked version while keeping the spirit of the original proposal:

  • Issue with Inputs + GamepadButton enums is solved by only keeping latter in public API (KeyboardButton, MouseButton, GamepadButton enums) while global enum of all controls is now internal.
  • Any control could be stored in InputControlReference, which is then could be used for any sort of serialization, wrapping, etc.
  • Device slots reworked, and now can store any amount of devices, e.g. one slot could store keyboard + mouse, while another could be just one gamepad.
  • Can query latest used device / control.
  • GetAxis that returns [0, 1] range and [-1, 1] range are different methods, which provides extra type safety.
  • Rebinding support via replacing which API control is connected to which real control, see SetRebinding.
  • The usage examples are mostly left as-is, with the only difference that now IsPressed and others could be used for any device type.

Overall this API provides potentially somewhat more future-proof API, as now users can implement their game by using only keyboard + mouse, and then add rebinding in the end of game development and by doing this allow for usage of any other device type (even future ones).

namespace UnityEngine.InputSystem.HighLevelAPI
{
    // -------------------------------------------------------------------- Type safe public enums
    // Basic idea here is to provide enums such so return type of control is figured out in compile time.
    // For example when using GamepadTwoWayAxis.LeftStickHorizontal,
    // user will know that return type is float in [-1, 1] range, and not in [0, 1] range.

    public enum KeyboardButton
    {
        Space = InputControl.KeyboardButtonSpace,
        Digit0 = InputControl.KeyboardButtonDigit0,
        Digit1 = InputControl.KeyboardButtonDigit1,
        Digit2 = InputControl.KeyboardButtonDigit2,
        Digit3 = InputControl.KeyboardButtonDigit3
    }

    public enum MouseButton
    {
        Left = InputControl.MouseButtonLeft,
        Right = InputControl.MouseButtonRight,
        Middle = InputControl.MouseButtonMiddle,
        Forward = InputControl.MouseButtonForward,
        Back = InputControl.MouseButtonBack,
        ScrollLeft = InputControl.MouseButtonScrollLeft,
        ScrollUp = InputControl.MouseButtonScrollUp,
        ScrollRight = InputControl.MouseButtonScrollRight,
        ScrollDown = InputControl.MouseButtonScrollDown,
    }

    public enum MouseTwoWayAxis
    {
        ScrollHorizontalTimeNormalized = InputControl.MouseTwoWayAxisScrollHorizontalTimeNormalized,
        ScrollVerticalTimeNormalized = InputControl.MouseTwoWayAxisScrollVerticalTimeNormalized,
    }

    // buttons
    public enum GamepadButton
    {
        LeftTrigger = InputControl.GamepadButtonLeftTrigger,
        RightTrigger = InputControl.GamepadButtonRightTrigger,
        DpadLeft = InputControl.GamepadButtonDpadLeft,
        DpadUp = InputControl.GamepadButtonDpadUp,
        DpadRight = InputControl.GamepadButtonDpadRight,
        DpadDown = InputControl.GamepadButtonDpadDown,
        LeftStickLeft = InputControl.GamepadButtonLeftStickLeft,
        LeftStickUp = InputControl.GamepadButtonLeftStickUp,
        LeftStickRight = InputControl.GamepadButtonLeftStickRight,
        LeftStickDown = InputControl.GamepadButtonLeftStickDown,
        RightStickLeft = InputControl.GamepadButtonRightStickLeft,
        RightStickUp = InputControl.GamepadButtonRightStickUp,
        RightStickRight = InputControl.GamepadButtonRightStickRight,
        RightStickDown = InputControl.GamepadButtonRightStickDown,
        West = InputControl.GamepadButtonWest,
        North = InputControl.GamepadButtonNorth,
        East = InputControl.GamepadButtonEast,
        South = InputControl.GamepadButtonSouth,
        LeftStickPress = InputControl.GamepadButtonLeftStickPress,
        RightStickPress = InputControl.GamepadButtonRightStickPress,
        LeftShoulder = InputControl.GamepadButtonLeftShoulder,
        RightShoulder = InputControl.GamepadButtonRightShoulder,
        Start = InputControl.GamepadButtonStart,
        Select = InputControl.GamepadButtonSelect
    }

    // 1D axis with values in [-1, 1] range
    public enum GamepadTwoWayAxis
    {
        DpadHorizontal = InputControl.GamepadTwoWayAxisDpadHorizontal,
        DpadVertical = InputControl.GamepadTwoWayAxisDpadVertical,
        LeftStickHorizontal = InputControl.GamepadTwoWayAxisLeftStickHorizontal,
        LeftStickVertical = InputControl.GamepadTwoWayAxisLeftStickVertical,
        RightStickHorizontal = InputControl.GamepadTwoWayAxisRightStickHorizontal,
        RightStickVertical = InputControl.GamepadTwoWayAxisRightStickVertical
    }

    // 2D normalized vector
    public enum GamepadStick
    {
        Dpad = InputControl.GamepadStickDpad,
        Left = InputControl.GamepadStickLeft,
        Right = InputControl.GamepadStickRight
    }

    // -------------------------------------------------------------------- Storing controls in generic data structures

    // Not sure if we need this one,
    // but could be beneficial for cases where users need to
    // show icon or text for a latest used control
    // or for rebinding to check if engaged control is of the same type
    public enum InputControlType
    {
        Button, // every button could be also read as one way axis
        OneWayAxis, // do we need separate one?
        TwoWayAxis,
        Stick,
        CursorPosition,
        ScrollDelta
    }
    
    // It is useful to allow the users to store controls in some generic data structure like a list,
    // for that we need to unify all enums back to generic InputControl, but keep the type safety.
    // This container struct tries to achieve exactly that.
    public struct InputControlReference
    {
        internal InputControl control;
        
        // TODO do we want to add some type checking here?
        // is it even possible?

        public bool IsValid() => control == InputControl.Invalid;

        public static implicit operator InputControlReference(KeyboardButton btn) => new InputControlReference() {control = (InputControl)btn};
        public static implicit operator InputControlReference(MouseButton btn);
        public static implicit operator InputControlReference(MouseTwoWayAxis btn);
        public static implicit operator InputControlReference(GamepadButton btn);
        public static implicit operator InputControlReference(GamepadTwoWayAxis btn);
        public static implicit operator InputControlReference(GamepadStick btn);

        public InputControlType GetControlType() => Input.InputControlToType(control);
    }

    // -------------------------------------------------------------------- Device slots

    // Device slots are similar concept to player slots in split screen games.
    // But a specific device slot can contain multiple devices, like a keyboard and a mouse.
    // Device slots could be used for player assignment management.
    // By default all new devices go to Unassigned slot.
    public enum DeviceSlot
    {
        Any = -1,
        Unassigned = 0,
        Slot1,
        Slot2,
        Slot3,
        Slot4,
        Slot5,
        Slot6,
        Slot7,
        Slot8,
        Slot9,
        Slot10,
        Slot11,
        Slot12,
        Slot13,
        Slot14,
        Slot15,
        Slot16,
        // any positive int number could be used?
    }

    public static class Input
    {
        // By default all devices go to unassigned slot,
        // this methods should be used to manage slot assignment.
        // DeviceSlot.Any is not a valid argument.
        public static void AssignDeviceToSlot(InputDevice device, DeviceSlot slot);
        public static void RemoveDeviceFromSlot(InputDevice device, DeviceSlot slot);

        // If provided with DeviceSlot.Any returns all devices.
        public static InputDevice[] GetDevices(DeviceSlot slot);

        // Returns latest used device in this frame, or null otherwise.
        // Useful for player join-in, or showing icon of latest used device.
        // If provided with DeviceSlot.Any returns latest used device in general.
        public static InputDevice GetLatestUsedDevice(DeviceSlot slot = DeviceSlot.Any);

        // Returns latest used control in this frame, or invalid reference otherwise. 
        // Useful for rebinding implementation.
        public static InputControlReference GetLatestUsedControl(InputDevice device);

        public static bool IsConnected(DeviceSlot slot) => GetDevices(slot).Length != 0;

        // --------------------------------------------------------------------

        // Sets trigger set point for analogue buttons,
        // like gamepad triggers, joystick triggers, gamepad stick buttons up/down/left/right.
        // Default is 0.5f 
        public static void SetTriggerPressPoint(float pressPoint, DeviceSlot slot = DeviceSlot.Any);
        public static void SetStickDeadzone(float deadzone, DeviceSlot slot = DeviceSlot.Any);

        // Internal helper to convert from global enum value to control type
        internal static InputControlType InputControlToType(InputControl control);

        // --------------------------------------------------------------------
        // Less type-safe API, only to be used when required to store controls of different type
        // together in some data structure like list or array.
        // Notice we can't override GetAxis here and have to revert to name methods fully,
        // due to only difference being the return type.
        public static class ByReference
        {
            public static bool IsButtonPressed(InputControlReference control, DeviceSlot slot);
            public static bool WasButtonDown(InputControlReference control, DeviceSlot slot);
            public static bool WasButtonUp(InputControlReference control, DeviceSlot slot);

            // Any button is also a one way axis.
            // Returns value in [0, 1] range
            // TODO do we have any control which is one way axis but not a button?
            public static float GetOneWayAxis(InputControlReference control, DeviceSlot slot);

            // Returns value in [-1, 1] range
            public static float GetTwoWayAxis(InputControlReference control, DeviceSlot slot);

            public static Vector2 GetStick(InputControlReference control, DeviceSlot slot);
        }

        // -------------------------------------------------------------------- Keyboard support
        public static bool IsPressed(KeyboardButton button, DeviceSlot slot = DeviceSlot.Any);
        public static bool WasDown(KeyboardButton button, DeviceSlot slot = DeviceSlot.Any);
        public static bool WasUp(KeyboardButton button, DeviceSlot slot = DeviceSlot.Any);

        // Returns value in [0, 1] range
        public static float GetAxis(KeyboardButton button, DeviceSlot slot = DeviceSlot.Any);

        // Helper for WASD like controls.
        public static Vector2 GetAxis(KeyboardButton left, KeyboardButton up, KeyboardButton right, KeyboardButton down, DeviceSlot slot = DeviceSlot.Any);

        // -------------------------------------------------------------------- Mouse support
        public static bool IsPressed(MouseButton button, DeviceSlot slot = DeviceSlot.Any);
        public static bool WasDown(MouseButton button, DeviceSlot slot = DeviceSlot.Any);
        public static bool WasUp(MouseButton button, DeviceSlot slot = DeviceSlot.Any);

        // Returns value in [0, 1] range
        public static float GetAxis(MouseButton button, DeviceSlot slot = DeviceSlot.Any);

        // Returns value in [-1, 1] range
        public static float GetAxis(MouseTwoWayAxis button, DeviceSlot slot = DeviceSlot.Any);

        // Returns current mouse cursor position
        public static Vector2 GetMousePosition(DeviceSlot slot = DeviceSlot.Any);

        // Returns current frame accumulated mouse scroll value
        public static Vector2 GetMouseScroll(DeviceSlot slot = DeviceSlot.Any);

        // -------------------------------------------------------------------- Gamepad support
        public static bool IsPressed(GamepadButton button, DeviceSlot slot = DeviceSlot.Any);
        public static bool WasDown(GamepadButton button, DeviceSlot slot = DeviceSlot.Any);
        public static bool WasUp(GamepadButton button, DeviceSlot slot = DeviceSlot.Any);

        // Returns value in [0, 1] range
        public static float GetAxis(GamepadButton button, DeviceSlot slot = DeviceSlot.Any);

        // Returns value in [-1, 1] range
        public static float GetAxis(GamepadTwoWayAxis axis, DeviceSlot slot = DeviceSlot.Any);

        public static Vector2 GetAxis(GamepadStick stick, DeviceSlot slot = DeviceSlot.Any);

        // --------------------------------------------------------------------
        // Replaces which controls drive a provided control.
        // By default every control drives itself,
        // e.g. pressing Space key on keyboard will report as space key.
        // But it's possible to override which keys will be reported as space key,
        // e.g. pressing Enter key could be driving Space key.
        // But pressing Space key then would do nothing.  
        public static void SetRebinding(
            InputControlReference driveControl,
            IEnumerable<InputControlReference> withAnyOfFollowingControls,
            DeviceSlot inSlot);
    }

    // --------------------------------------------------------------------
    // It is in principle beneficial to have a list of all controls,
    // as this is where stability of enum API values could be enforced.
    // Also we could separate controls by type based on this enum,
    // e.g. have bool IsButton(InputControl control) and similar.
    // It's also useful for rebinding activities.
    // Plus we can figure out if we need to split a control into multiple of different types,
    // e.g. mouse scroll is vector2 delta control, and also 2 single axis controls, plus 4 buttons.
    // But for the sake of type safety, let's not expose it directly to the user,
    // and provide necessary overrides instead.
    internal enum InputControl
    {
        Invalid = 0x0,
        
        KeyboardButtonSpace = 0x0100000,
        KeyboardButtonDigit0,
        KeyboardButtonDigit1,
        KeyboardButtonDigit2,
        KeyboardButtonDigit3,
        // ... 100 more

        MouseButtonLeft = 0x0200000,
        MouseButtonRight,
        MouseButtonMiddle,
        MouseButtonForward,
        MouseButtonBack,
        MouseButtonScrollLeft,
        MouseButtonScrollUp,
        MouseButtonScrollRight,
        MouseButtonScrollDown,

        // mouse scroll divided by delta time, and normalized to [-1, 1] range
        // useful for using scroll like gamepad stick
        MouseTwoWayAxisScrollHorizontalTimeNormalized = 0x0210000,
        MouseTwoWayAxisScrollVerticalTimeNormalized,

        // Cursor position is an absolute value control, unlike vector2 control which is normalized
        MouseCursorPosition = 0x0220000,

        // Scroll delta is a relative value control, unlike vector2 control which is normalized
        MouseScrollDelta = 0x0230000,

        GamepadButtonLeftTrigger = 0x0300000,
        GamepadButtonRightTrigger,
        GamepadButtonDpadLeft,
        GamepadButtonDpadUp,
        GamepadButtonDpadRight,
        GamepadButtonDpadDown,
        GamepadButtonLeftStickLeft,
        GamepadButtonLeftStickUp,
        GamepadButtonLeftStickRight,
        GamepadButtonLeftStickDown,
        GamepadButtonRightStickLeft,
        GamepadButtonRightStickUp,
        GamepadButtonRightStickRight,
        GamepadButtonRightStickDown,
        GamepadButtonWest,
        GamepadButtonNorth,
        GamepadButtonEast,
        GamepadButtonSouth,
        GamepadButtonLeftStickPress,
        GamepadButtonRightStickPress,
        GamepadButtonLeftShoulder,
        GamepadButtonRightShoulder,
        GamepadButtonStart,
        GamepadButtonSelect,

        GamepadTwoWayAxisDpadHorizontal = 0x0310000,
        GamepadTwoWayAxisDpadVertical,
        GamepadTwoWayAxisLeftStickHorizontal,
        GamepadTwoWayAxisLeftStickVertical,
        GamepadTwoWayAxisRightStickHorizontal,
        GamepadTwoWayAxisRightStickVertical,

        // stick is normalized vector2
        GamepadStickDpad = 0x0320000,
        GamepadStickLeft,
        GamepadStickRight
    }
}

from inputsystem.

ekcoh avatar ekcoh commented on June 2, 2024

Team discussion notes on last iteration of proposal (comment above):

Key concepts:

  • User sees device specific enums, e.g. KeyboardButton, MouseButton etc
  • IsPressed accepts specific enum via overlaps supported by the C# type system.
  • Overarching input enum (InputControl) is internal. Reason fir it to exist is to store notion of controls using a single type.
  • InputControlReference wraps InputControl but has implicit conversion to each type. Different APIU to use it via ByReference.
  • Device slots in comparison to original proposal stores "list" of devices assigned to a slot representing a user. Perspective on multi-player, assign to slots to differentiate players but support multiple devices. Shares some similarity with control schemes.
  • Adding support for rebinding with intention to support moving forward into rebinding support without need to redo code.

Discussion points

  • Rebinding concept introduced here overlaps with what is supported by Actions. Desirable to allow a trivial upgrade path for users but not add extra tooling to do what actions already solve.
  • Touched on GetLatestUsedDevice, GetLatestUsedControl. Pointed out that this is more or less equivalent to existing event API proposal. We should pick one flavor and go with it.
  • Unassigned slots are intended to act as a "parkinglot" for devices available to assign to new users with this design. This is similar but slightly expanded from the initial proposal tied to gamepads.
  • Both VS and Resharper have no intellisense issues with proposed overloads.
  • Proposal adds vertical and horizontal scroll concepts to support 2D axis.
  • Cursor position added to mouse.

Way forward

  • Investigate reconnection scenarios and user pairing on console platforms before deciding on how to best design slot mechanism. It is desirable to keep design close to underling mechanics instead of adding design diverging from underlying concepts.
  • Investigate scroll and absolute vs relative values if it makes sense to support conversion to units over time to support use-cases where scroll wheel(s) are used as a stick.
  • Find a way to be able to store enums in a container (of different types), e.g. "sum type", tuple or variant.
  • Revisit rebinding story to provide consitency and if we should redirect to an action-based approach as soon as rebinding is needed or support remapping controls as in the last proposal.
  • Evaluate what the reals gains with separate enums vs a large enum really is and decide on way forward.

from inputsystem.

jamesmcgill avatar jamesmcgill commented on June 2, 2024

This work has been discontinued.

from inputsystem.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.