device: support for Steam Controller on Linux

Adds lgrip and rgrip button handles, which are present on Steam Controller but also on the Oculus Touch
This commit is contained in:
rdb 2018-12-31 16:10:56 +01:00
parent 4699dfcd5b
commit f3ba1d317c
6 changed files with 70 additions and 10 deletions

View File

@ -57,6 +57,9 @@ enum QuirkBits {
// ABS_THROTTLE maps to rudder
QB_rudder_from_throttle = 16,
// Special handling for Steam Controller, which has many peculiarities.
QB_steam_controller = 32,
};
static const struct DeviceMapping {
@ -71,6 +74,10 @@ static const struct DeviceMapping {
{0x044f, 0xb108, InputDevice::DeviceClass::flight_stick, QB_centered_throttle | QB_reversed_throttle | QB_rudder_from_throttle},
// Xbox 360 Wireless Controller
{0x045e, 0x0719, InputDevice::DeviceClass::gamepad, QB_connect_if_nonzero},
// Steam Controller (wired)
{0x28de, 0x1102, InputDevice::DeviceClass::unknown, QB_steam_controller},
// Steam Controller (wireless)
{0x28de, 0x1142, InputDevice::DeviceClass::unknown, QB_steam_controller},
// Jess Tech Colour Rumble Pad
{0x0f30, 0x0111, InputDevice::DeviceClass::gamepad, 0},
// Trust GXT 24
@ -299,6 +306,13 @@ init_device() {
++mapping;
}
// The Steam Controller reports as multiple devices, one of which a gamepad.
if (quirks & QB_steam_controller) {
if (test_bit(BTN_GAMEPAD, keys)) {
_device_class = DeviceClass::gamepad;
}
}
// Try to detect which type of device we have here
if (_device_class == DeviceClass::unknown) {
int device_scores[(size_t)DeviceClass::spatial_mouse] = {0};
@ -378,7 +392,7 @@ init_device() {
for (int i = 0; i <= KEY_MAX; ++i) {
if (test_bit(i, keys)) {
ButtonState button;
button.handle = map_button(i, _device_class);
button.handle = map_button(i, _device_class, quirks);
int button_index = (int)_buttons.size();
if (button.handle == ButtonHandle::none()) {
@ -527,6 +541,18 @@ init_device() {
}
}
break;
case ABS_HAT2X:
if (quirks & QB_steam_controller) {
axis = InputDevice::Axis::right_trigger;
have_analog_triggers = true;
}
break;
case ABS_HAT2Y:
if (quirks & QB_steam_controller) {
axis = InputDevice::Axis::left_trigger;
have_analog_triggers = true;
}
break;
}
// Check the initial value and ranges.
@ -740,7 +766,7 @@ process_events() {
* Static function to map an evdev code to a ButtonHandle.
*/
ButtonHandle EvdevInputDevice::
map_button(int code, DeviceClass device_class) {
map_button(int code, DeviceClass device_class, int quirks) {
if (code >= 0 && code < 0x80) {
// See linux/input.h for the source of this mapping.
static const ButtonHandle keyboard_map[] = {
@ -897,7 +923,11 @@ map_button(int code, DeviceClass device_class) {
}
} else if ((code & 0xfff0) == BTN_JOYSTICK) {
if (device_class == DeviceClass::gamepad) {
if (quirks & QB_steam_controller) {
// BTN_THUMB and BTN_THUMB2 detect touching the touchpads.
return ButtonHandle::none();
} else if (device_class == DeviceClass::gamepad) {
// Based on "Jess Tech Colour Rumble Pad"
static const ButtonHandle mapping[] = {
GamepadButton::face_x(),
@ -991,6 +1021,13 @@ map_button(int code, DeviceClass device_class) {
case BTN_TRIGGER_HAPPY4:
return GamepadButton::dpad_down();
// The next two are for the Steam Controller's grip buttons.
case BTN_GEAR_DOWN:
return GamepadButton::lgrip();
case BTN_GEAR_UP:
return GamepadButton::rgrip();
default:
return ButtonHandle::none();
}

View File

@ -64,7 +64,9 @@ private:
int _rtrigger_code;
public:
static ButtonHandle map_button(int code, DeviceClass device_class = DeviceClass::unknown);
static ButtonHandle map_button(int code,
DeviceClass device_class = DeviceClass::unknown,
int quirks = 0);
public:
static TypeHandle get_class_type() {

View File

@ -113,6 +113,7 @@ open_device() {
ioctl(_fd, JSIOCGNAME(sizeof(name)), name);
_name = name;
bool emulate_dpad = true;
bool have_analog_triggers = false;
// Get the number of axes.
@ -138,6 +139,8 @@ open_device() {
_device_class = DeviceClass::gamepad;
} else if (handle == GamepadButton::trigger()) {
_device_class = DeviceClass::flight_stick;
} else if (handle == GamepadButton::dpad_left()) {
emulate_dpad = false;
} else if (handle == GamepadButton::ltrigger()) {
_ltrigger_button = i;
} else if (handle == GamepadButton::rtrigger()) {
@ -220,7 +223,7 @@ open_device() {
break;
case ABS_HAT0X:
if (_dpad_left_button == -1) {
if (emulate_dpad) {
// Emulate D-Pad or hat switch.
_dpad_x_axis = i;
_dpad_left_button = (int)_buttons.size();
@ -236,7 +239,7 @@ open_device() {
break;
case ABS_HAT0Y:
if (_dpad_up_button == -1) {
if (emulate_dpad) {
// Emulate D-Pad.
_dpad_y_axis = i;
_dpad_up_button = (int)_buttons.size();
@ -251,6 +254,18 @@ open_device() {
}
break;
case ABS_HAT2X:
if (_device_class == DeviceClass::gamepad) {
axis = InputDevice::Axis::right_trigger;
}
break;
case ABS_HAT2Y:
if (_device_class == DeviceClass::gamepad) {
axis = InputDevice::Axis::left_trigger;
}
break;
default:
if (device_cat.is_debug()) {
device_cat.debug() << "Unmapped /dev/input/js" << _index
@ -278,7 +293,7 @@ open_device() {
if (_ltrigger_button >= 0 && _rtrigger_button >= 0 && !have_analog_triggers) {
// Emulate analog triggers.
_ltrigger_control = (int)_axes.size();
_ltrigger_axis = (int)_axes.size();
add_axis(Axis::left_trigger, 0, 1, false);
add_axis(Axis::right_trigger, 0, 1, false);
} else {
@ -398,9 +413,9 @@ process_events() {
if (events[i].type & JS_EVENT_BUTTON) {
if (index == _ltrigger_button) {
axis_changed(_ltrigger_control, events[i].value);
axis_changed(_ltrigger_axis, events[i].value);
} else if (index == _rtrigger_button) {
axis_changed(_ltrigger_control + 1, events[i].value);
axis_changed(_ltrigger_axis + 1, events[i].value);
}
button_changed(index, (events[i].value != 0));

View File

@ -50,7 +50,7 @@ private:
int _dpad_up_button;
// This is used for axis emulation.
int _ltrigger_control;
int _ltrigger_axis;
int _ltrigger_button;
int _rtrigger_button;

View File

@ -24,6 +24,8 @@ DEFINE_GAMEPAD_BUTTON_HANDLE(lshoulder)
DEFINE_GAMEPAD_BUTTON_HANDLE(rshoulder)
DEFINE_GAMEPAD_BUTTON_HANDLE(ltrigger)
DEFINE_GAMEPAD_BUTTON_HANDLE(rtrigger)
DEFINE_GAMEPAD_BUTTON_HANDLE(lgrip)
DEFINE_GAMEPAD_BUTTON_HANDLE(rgrip)
DEFINE_GAMEPAD_BUTTON_HANDLE(dpad_left)
DEFINE_GAMEPAD_BUTTON_HANDLE(dpad_right)
@ -87,6 +89,8 @@ init_gamepad_buttons() {
ButtonRegistry::ptr()->register_button(_rshoulder, "rshoulder");
ButtonRegistry::ptr()->register_button(_ltrigger, "ltrigger");
ButtonRegistry::ptr()->register_button(_rtrigger, "rtrigger");
ButtonRegistry::ptr()->register_button(_lgrip, "lgrip");
ButtonRegistry::ptr()->register_button(_rgrip, "rgrip");
ButtonRegistry::ptr()->register_button(_dpad_left, "dpad_left");
ButtonRegistry::ptr()->register_button(_dpad_right, "dpad_right");

View File

@ -30,6 +30,8 @@ PUBLISHED:
static ButtonHandle rshoulder();
static ButtonHandle ltrigger();
static ButtonHandle rtrigger();
static ButtonHandle lgrip();
static ButtonHandle rgrip();
static ButtonHandle dpad_left();
static ButtonHandle dpad_right();