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.
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