diff --git a/panda/src/device/evdevInputDevice.cxx b/panda/src/device/evdevInputDevice.cxx index 67fa1193c7..c94c71df98 100644 --- a/panda/src/device/evdevInputDevice.cxx +++ b/panda/src/device/evdevInputDevice.cxx @@ -90,7 +90,9 @@ EvdevInputDevice(int index) : _dpad_x_axis(-1), _dpad_y_axis(-1), _dpad_left_button(-1), - _dpad_up_button(-1) { + _dpad_up_button(-1), + _ltrigger_code(-1), + _rtrigger_code(-1) { char path[64]; sprintf(path, "/dev/input/event%d", index); @@ -239,6 +241,7 @@ init_device() { bool all_values_zero = true; bool emulate_dpad = true; + bool have_analog_triggers = false; bool has_keys = false; bool has_axes = false; @@ -375,7 +378,12 @@ init_device() { } if (button.handle == GamepadButton::dpad_left()) { emulate_dpad = false; + } else if (button.handle == GamepadButton::ltrigger()) { + _ltrigger_code = i; + } else if (button.handle == GamepadButton::rtrigger()) { + _rtrigger_code = i; } + _buttons.push_back(button); if (i >= _button_indices.size()) { _button_indices.resize(i + 1, -1); @@ -415,6 +423,7 @@ init_device() { axis = InputDevice::C_right_x; } else if (_device_class == DC_gamepad) { axis = InputDevice::C_left_trigger; + have_analog_triggers = true; } else { axis = InputDevice::C_throttle; } @@ -434,6 +443,7 @@ init_device() { axis = InputDevice::C_right_y; } else if (_device_class == DC_gamepad) { axis = InputDevice::C_right_trigger; + have_analog_triggers = true; } else { axis = InputDevice::C_yaw; } @@ -454,6 +464,7 @@ init_device() { case ABS_GAS: if (_device_class == DC_gamepad) { axis = InputDevice::C_right_trigger; + have_analog_triggers = true; } else { axis = InputDevice::C_accelerator; } @@ -461,6 +472,7 @@ init_device() { case ABS_BRAKE: if (_device_class == DC_gamepad) { axis = InputDevice::C_left_trigger; + have_analog_triggers = true; } else { axis = InputDevice::C_brake; } @@ -541,6 +553,16 @@ init_device() { } } + if (_ltrigger_code >= 0 && _rtrigger_code >= 0 && !have_analog_triggers) { + // Emulate analog triggers. + _ltrigger_control = (int)_controls.size(); + add_control(C_left_trigger, 0, 1, false); + add_control(C_right_trigger, 0, 1, false); + } else { + _ltrigger_code = -1; + _rtrigger_code = -1; + } + char path[64]; char buffer[256]; sprintf(path, "/sys/class/input/event%d/device/device/../product", _index); @@ -666,6 +688,11 @@ process_events() { if (index >= 0) { button_changed(index, events[i].value != 0); } + if (code == _ltrigger_code) { + control_changed(_ltrigger_control, events[i].value); + } else if (code == _rtrigger_code) { + control_changed(_ltrigger_control + 1, events[i].value); + } break; default: diff --git a/panda/src/device/evdevInputDevice.h b/panda/src/device/evdevInputDevice.h index 9ebaef03f2..0a6baa058a 100644 --- a/panda/src/device/evdevInputDevice.h +++ b/panda/src/device/evdevInputDevice.h @@ -53,6 +53,11 @@ private: int _dpad_left_button; int _dpad_up_button; + // This is used for axis emulation. + int _ltrigger_control; + int _ltrigger_code; + int _rtrigger_code; + public: static ButtonHandle map_button(int code, DeviceClass device_class = DC_unknown); diff --git a/panda/src/device/linuxJoystickDevice.cxx b/panda/src/device/linuxJoystickDevice.cxx index 9aca81ad3d..7c62ce2ae5 100644 --- a/panda/src/device/linuxJoystickDevice.cxx +++ b/panda/src/device/linuxJoystickDevice.cxx @@ -12,6 +12,7 @@ */ #include "linuxJoystickDevice.h" +#include "evdevInputDevice.h" #ifdef PHAVE_LINUX_INPUT_H @@ -32,7 +33,9 @@ LinuxJoystickDevice(int index) : _dpad_x_axis(-1), _dpad_y_axis(-1), _dpad_left_button(-1), - _dpad_up_button(-1) + _dpad_up_button(-1), + _ltrigger_button(-1), + _rtrigger_button(-1) { LightMutexHolder holder(_lock); if (!open_device()) { @@ -107,6 +110,8 @@ open_device() { ioctl(_fd, JSIOCGNAME(sizeof(name)), name); _name = name; + bool have_analog_triggers = false; + // Get the number of axes. uint8_t num_axes = 0, num_buttons = 0; ioctl(_fd, JSIOCGAXES, &num_axes); @@ -120,104 +125,18 @@ open_device() { ioctl(_fd, JSIOCGBTNMAP, btnmap); for (uint8_t i = 0; i < num_buttons; ++i) { - ButtonHandle handle = ButtonHandle::none(); - switch (btnmap[i]) { - case BTN_A: - handle = GamepadButton::action_a(); - _device_class = DC_gamepad; - break; - - case BTN_B: - handle = GamepadButton::action_b(); - break; - - case BTN_C: - handle = GamepadButton::action_c(); - break; - - case BTN_X: - handle = GamepadButton::action_x(); - break; - - case BTN_Y: - handle = GamepadButton::action_y(); - break; - - case BTN_Z: - handle = GamepadButton::action_z(); - break; - - case BTN_TL: - handle = GamepadButton::lshoulder(); - break; - - case BTN_TR: - handle = GamepadButton::rshoulder(); - break; - - case BTN_TL2: - handle = GamepadButton::ltrigger(); - break; - - case BTN_TR2: - handle = GamepadButton::rtrigger(); - break; - - case BTN_1: - handle = GamepadButton::action_1(); - break; - - case BTN_2: - handle = GamepadButton::action_2(); - break; - - case BTN_SELECT: - case KEY_PREVIOUS: - handle = GamepadButton::back(); - break; - - case BTN_START: - case KEY_NEXT: - handle = GamepadButton::start(); - break; - - case BTN_MODE: - handle = GamepadButton::guide(); - break; - - case BTN_THUMBL: - handle = GamepadButton::lstick(); - break; - - case BTN_THUMBR: - handle = GamepadButton::rstick(); - break; - - case BTN_TRIGGER_HAPPY1: - handle = GamepadButton::dpad_left(); - _dpad_left_button = i; - break; - - case BTN_TRIGGER_HAPPY2: - handle = GamepadButton::dpad_right(); - break; - - case BTN_TRIGGER_HAPPY3: - handle = GamepadButton::dpad_up(); - _dpad_up_button = i; - break; - - case BTN_TRIGGER_HAPPY4: - handle = GamepadButton::dpad_down(); - break; - - default: + ButtonHandle handle = EvdevInputDevice::map_button(btnmap[i]); + if (handle == ButtonHandle::none()) { if (device_cat.is_debug()) { device_cat.debug() << "Unmapped /dev/input/js" << _index << " button " << (int)i << ": 0x" << hex << btnmap[i] << "\n"; } - handle = ButtonHandle::none(); - break; + } else if (handle == GamepadButton::action_a()) { + _device_class = DC_gamepad; + } else if (handle == GamepadButton::ltrigger()) { + _ltrigger_button = i; + } else if (handle == GamepadButton::rtrigger()) { + _rtrigger_button = i; } _buttons[i].handle = handle; } @@ -333,6 +252,7 @@ open_device() { // We'd like to use 0.0 to indicate the resting position. _controls[i]._scale = 1.0 / 65534.0; _controls[i]._bias = 0.5; + have_analog_triggers = true; } else if (axis == C_left_y || axis == C_right_y || axis == C_y) { _controls[i]._scale = 1.0 / -32767.0; _controls[i]._bias = 0.0; @@ -343,6 +263,16 @@ open_device() { } } + if (_ltrigger_button >= 0 && _rtrigger_button >= 0 && !have_analog_triggers) { + // Emulate analog triggers. + _ltrigger_control = (int)_controls.size(); + add_control(C_left_trigger, 0, 1, false); + add_control(C_right_trigger, 0, 1, false); + } else { + _ltrigger_button = -1; + _rtrigger_button = -1; + } + // Get additional information from sysfs. sprintf(path, "/sys/class/input/js%d/device/id/vendor", _index); FILE *f = fopen(path, "r"); @@ -454,6 +384,11 @@ process_events() { int index = events[i].number; if (events[i].type & JS_EVENT_BUTTON) { + if (index == _ltrigger_button) { + control_changed(_ltrigger_control, events[i].value); + } else if (index == _rtrigger_button) { + control_changed(_ltrigger_control + 1, events[i].value); + } button_changed(index, (events[i].value != 0)); } else if (events[i].type & JS_EVENT_AXIS) { diff --git a/panda/src/device/linuxJoystickDevice.h b/panda/src/device/linuxJoystickDevice.h index 7bd8203039..ab97dd5293 100644 --- a/panda/src/device/linuxJoystickDevice.h +++ b/panda/src/device/linuxJoystickDevice.h @@ -45,6 +45,11 @@ private: int _dpad_left_button; int _dpad_up_button; + // This is used for axis emulation. + int _ltrigger_control; + int _ltrigger_button; + int _rtrigger_button; + public: static TypeHandle get_class_type() { return _type_handle;