Browse Source

input: add analog trigger emulation on Linux

rdb 8 years ago
parent
commit
9fbdefe120

+ 28 - 1
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:

+ 5 - 0
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);
 

+ 30 - 95
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) {

+ 5 - 0
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;