linuxgame-enginegamepadevdev

evdev: Find the "rest" value of a gamepad axis


How to find what is the at-rest value of any axis of a game controller? For example, on my Dualshock 4, here is the relevant data from evtest:

Event code 0 (ABS_X)
  Value    126
  Min        0
  Max      255
  Flat      15
Event code 1 (ABS_Y)
  Value    127
  Min        0
  Max      255
  Flat      15
Event code 2 (ABS_Z)
  Value    255
  Min        0
  Max      255
  Flat      15
Event code 3 (ABS_RX)
  Value    127
  Min        0
  Max      255
  Flat      15
Event code 4 (ABS_RY)
  Value    123
  Min        0
  Max      255
  Flat      15
Event code 5 (ABS_RZ)
  Value      0
  Min        0
  Max      255
  Flat      15

In the above example, I was pulling the right trigger all the way while running evtest; thus, the value for ABS_Z came to 255 instead of 0. So, since we can't use value for this purpose, is their any way to find out what the at-rest value is?


EDIT: I am using the libevdev API to access the gamepad. The information printed above can be accessed from the input_absinfo struct.


Solution

  • This can't be done generically using only the information available from evdev.

    Most gamepads report axis inputs (thumbsticks and triggers) using the first 6 axes:

    ABS_X
    ABS_Y
    ABS_Z
    ABS_RX
    ABS_RY
    ABS_RZ
    

    The left thumbstick always uses ABS_X and ABS_Y. The right thumbstick sometimes uses ABS_Z and ABS_RZ, but may also use ABS_RX and ABS_RY which is the case with DS4. For thumbstick axes, the neutral value is halfway between Min and Max.

    The triggers typically use whatever is left over. For instance, if the right thumbstick is ABS_Z/ABS_RZ then the triggers are usually ABS_RX/ABS_RY. Some gamepads use ABS_BRAKE/ABS_GAS instead. For trigger axes, the neutral value is Min.

    Some devices correctly report a negative Min for thumbstick axes. For instance, here's what evtest gets for an Xbox One controller connected over USB:

    Event code 0 (ABS_X)
      Value      0
      Min   -32768
      Max    32767
      Fuzz      16
      Flat     128
    Event code 1 (ABS_Y)
      Value      0
      Min   -32768
      Max    32767
      Fuzz      16
      Flat     128
    Event code 2 (ABS_Z)
      Value      0
      Min        0
      Max     1023
    Event code 3 (ABS_RX)
      Value      0
      Min   -32768
      Max    32767
      Fuzz      16
      Flat     128
    Event code 4 (ABS_RY)
      Value      0
      Min   -32768
      Max    32767
      Fuzz      16
      Flat     128
    Event code 5 (ABS_RZ)
      Value      0
      Min        0
      Max     1023
    

    In this case, the driver (xpad) recognizes the device and knows the logical range of each axis without relying on information reported by the device. The issue with DS4 is it's a HID-compliant gamepad. The HID protocol allows a device to define its logical range, and DS4 reports 0 as the minimum for each axis. The DS4 driver (hid-sony) reports these axis bounds as-is.

    Here's what it looks like in the portion of DS4's HID report descriptor that defines the thumbstick axes:

    0x09, 0x30,        //   Usage (X)
    0x09, 0x31,        //   Usage (Y)
    0x09, 0x32,        //   Usage (Z)
    0x09, 0x35,        //   Usage (Rz)
    0x15, 0x00,        //   Logical Minimum (0)
    0x26, 0xFF, 0x00,  //   Logical Maximum (255)
    0x75, 0x08,        //   Report Size (8)
    0x95, 0x04,        //   Report Count (4)
    0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    

    The lines with "Usage" in them define which axes are used for each axis input. X, Y, Z, and Rz get translated into ABS_X, ABS_Y, ABS_Z, ABS_RZ in evdev. The axis ranges are defined by "Logical Minimum" and "Logical Maximum" which apply to all four axes. We can also see from "Report Size" that each axis is an 8-bit value.

    Here's the part the defines the triggers, note that the logical range is defined exactly the same as for the thumbstick axes:

    0x09, 0x33,        //   Usage (Rx)
    0x09, 0x34,        //   Usage (Ry)
    0x15, 0x00,        //   Logical Minimum (0)
    0x26, 0xFF, 0x00,  //   Logical Maximum (255)
    0x75, 0x08,        //   Report Size (8)
    0x95, 0x02,        //   Report Count (2)
    0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    

    Because of these kinds of ambiguities, you can't solely rely on heuristics to distinguish trigger and thumbstick axes. To get this right in the general case, you'll need a registry of known gamepads that tells you which inputs are mapped to which axes. SDL2 is great for this, it has a large registry of gamepads including many console gamepads like DS4.

    https://github.com/spurious/SDL-mirror/blob/master/src/joystick/controller_type.h#L72