diff --git a/panda/src/device/evdevInputDevice.cxx b/panda/src/device/evdevInputDevice.cxx index 610fb8722a..057d9b14ff 100644 --- a/panda/src/device/evdevInputDevice.cxx +++ b/panda/src/device/evdevInputDevice.cxx @@ -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(); } diff --git a/panda/src/device/evdevInputDevice.h b/panda/src/device/evdevInputDevice.h index 53c495ad08..994915e40b 100644 --- a/panda/src/device/evdevInputDevice.h +++ b/panda/src/device/evdevInputDevice.h @@ -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() { diff --git a/panda/src/device/linuxJoystickDevice.cxx b/panda/src/device/linuxJoystickDevice.cxx index 1871a1e948..c964ea8499 100644 --- a/panda/src/device/linuxJoystickDevice.cxx +++ b/panda/src/device/linuxJoystickDevice.cxx @@ -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)); diff --git a/panda/src/device/linuxJoystickDevice.h b/panda/src/device/linuxJoystickDevice.h index af0a74e3e6..61d05cd3e8 100644 --- a/panda/src/device/linuxJoystickDevice.h +++ b/panda/src/device/linuxJoystickDevice.h @@ -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; diff --git a/panda/src/putil/gamepadButton.cxx b/panda/src/putil/gamepadButton.cxx index 2924f0bf90..4e3c8be22c 100644 --- a/panda/src/putil/gamepadButton.cxx +++ b/panda/src/putil/gamepadButton.cxx @@ -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"); diff --git a/panda/src/putil/gamepadButton.h b/panda/src/putil/gamepadButton.h index 774ee8ef2f..ff89c7e294 100644 --- a/panda/src/putil/gamepadButton.h +++ b/panda/src/putil/gamepadButton.h @@ -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();