浏览代码

input: joystick buttons, use yaw/pitch/roll for axes, more devices

Also adds format_* functions to get string from enum value.
rdb 8 年之前
父节点
当前提交
4f739e88cf

+ 82 - 23
panda/src/device/evdevInputDevice.cxx

@@ -37,6 +37,9 @@ enum QuirkBits {
 
   // Only consider the device "connected" if all axes are non-zero.
   QB_connect_if_nonzero = 8,
+
+  // ABS_THROTTLE maps to rudder
+  QB_rudder_from_throttle = 16,
 };
 
 static const struct DeviceMapping {
@@ -48,9 +51,25 @@ static const struct DeviceMapping {
   // NVIDIA Shield Controller
   {0x0955, 0x7214, InputDevice::DC_gamepad, QB_rstick_from_z},
   // T.Flight Hotas X
-  {0x044f, 0xb108, InputDevice::DC_flight_stick, QB_centered_throttle | QB_reversed_throttle},
+  {0x044f, 0xb108, InputDevice::DC_flight_stick, QB_centered_throttle | QB_reversed_throttle | QB_rudder_from_throttle},
   // Xbox 360 Wireless Controller
   {0x045e, 0x0719, InputDevice::DC_gamepad, QB_connect_if_nonzero},
+  // Jess Tech Colour Rumble Pad
+  {0x0f30, 0x0111, InputDevice::DC_gamepad, 0},
+  // 3Dconnexion Space Traveller 3D Mouse
+  {0x046d, 0xc623, InputDevice::DC_3d_mouse, 0},
+  // 3Dconnexion Space Pilot 3D Mouse
+  {0x046d, 0xc625, InputDevice::DC_3d_mouse, 0},
+  // 3Dconnexion Space Navigator 3D Mouse
+  {0x046d, 0xc626, InputDevice::DC_3d_mouse, 0},
+  // 3Dconnexion Space Explorer 3D Mouse
+  {0x046d, 0xc627, InputDevice::DC_3d_mouse, 0},
+  // 3Dconnexion Space Navigator for Notebooks
+  {0x046d, 0xc628, InputDevice::DC_3d_mouse, 0},
+  // 3Dconnexion SpacePilot Pro 3D Mouse
+  {0x046d, 0xc629, InputDevice::DC_3d_mouse, 0},
+  // 3Dconnexion Space Mouse Pro
+  {0x046d, 0xc62b, InputDevice::DC_3d_mouse, 0},
   {0},
 };
 
@@ -329,10 +348,6 @@ init_device() {
     //cerr << "Found highscore class " << _device_class << " with this score: " << highest_score << "\n";
   }
 
-  if (_device_class != DC_gamepad) {
-    emulate_dpad = false;
-  }
-
   if (has_keys) {
     // Also check whether the buttons are currently pressed.
     uint8_t states[(KEY_CNT + 7) >> 3];
@@ -342,7 +357,7 @@ init_device() {
     for (int i = 0; i < KEY_CNT; ++i) {
       if (test_bit(i, keys)) {
         ButtonState button;
-        button.handle = map_button(i);
+        button.handle = map_button(i, _device_class);
 
         int button_index = (int)_buttons.size();
         if (button.handle == ButtonHandle::none()) {
@@ -378,10 +393,22 @@ init_device() {
         ControlAxis axis = C_none;
         switch (i) {
         case ABS_X:
-          axis = InputDevice::C_left_x;
+          if (_device_class == DC_gamepad) {
+            axis = InputDevice::C_left_x;
+          } else if (_device_class == DC_flight_stick) {
+            axis = InputDevice::C_roll;
+          } else {
+            axis = InputDevice::C_x;
+          }
           break;
         case ABS_Y:
-          axis = InputDevice::C_left_y;
+          if (_device_class == DC_gamepad) {
+            axis = InputDevice::C_left_y;
+          } else if (_device_class == DC_flight_stick) {
+            axis = InputDevice::C_pitch;
+          } else {
+            axis = InputDevice::C_y;
+          }
           break;
         case ABS_Z:
           if (quirks & QB_rstick_from_z) {
@@ -408,11 +435,15 @@ init_device() {
           } else if (_device_class == DC_gamepad) {
             axis = InputDevice::C_right_trigger;
           } else {
-            axis = InputDevice::C_twist;
+            axis = InputDevice::C_yaw;
           }
           break;
         case ABS_THROTTLE:
-          axis = InputDevice::C_rudder;
+          if (quirks & QB_rudder_from_throttle) {
+            axis = InputDevice::C_rudder;
+          } else {
+            axis = InputDevice::C_throttle;
+          }
           break;
         case ABS_RUDDER:
           axis = InputDevice::C_rudder;
@@ -438,20 +469,26 @@ init_device() {
           if (emulate_dpad) {
             _dpad_x_axis = i;
             _dpad_left_button = (int)_buttons.size();
-            _buttons.push_back(ButtonState(GamepadButton::dpad_left()));
-            _buttons.push_back(ButtonState(GamepadButton::dpad_right()));
-          } else {
-            axis = C_hat_x;
+            if (_device_class == DC_gamepad) {
+              _buttons.push_back(ButtonState(GamepadButton::dpad_left()));
+              _buttons.push_back(ButtonState(GamepadButton::dpad_right()));
+            } else {
+              _buttons.push_back(ButtonState(GamepadButton::hat_left()));
+              _buttons.push_back(ButtonState(GamepadButton::hat_right()));
+            }
           }
           break;
         case ABS_HAT0Y:
           if (emulate_dpad) {
             _dpad_y_axis = i;
             _dpad_up_button = (int)_buttons.size();
-            _buttons.push_back(ButtonState(GamepadButton::dpad_up()));
-            _buttons.push_back(ButtonState(GamepadButton::dpad_down()));
-          } else {
-            axis = C_hat_y;
+            if (_device_class == DC_gamepad) {
+              _buttons.push_back(ButtonState(GamepadButton::dpad_up()));
+              _buttons.push_back(ButtonState(GamepadButton::dpad_down()));
+            } else {
+              _buttons.push_back(ButtonState(GamepadButton::hat_up()));
+              _buttons.push_back(ButtonState(GamepadButton::hat_down()));
+            }
           }
           break;
         }
@@ -461,8 +498,9 @@ init_device() {
         if (ioctl(_fd, EVIOCGABS(i), &absinfo) >= 0) {
           int index;
           // We'd like to reverse the Y axis to match the XInput behavior.
+          // Also reverse the yaw axis to match right-hand coordinate system.
           // Also T.Flight Hotas X throttle is reversed and can go backwards.
-          if (axis == C_y || axis == C_left_y || axis == C_right_y ||
+          if (axis == C_yaw || axis == C_left_y || axis == C_right_y ||
               (axis == C_throttle && (quirks & QB_reversed_throttle) != 0)) {
             swap(absinfo.maximum, absinfo.minimum);
           }
@@ -647,7 +685,7 @@ process_events() {
  * Static function to map an evdev code to a ButtonHandle.
  */
 ButtonHandle EvdevInputDevice::
-map_button(int code) {
+map_button(int code, DeviceClass device_class) {
   if (code >= 0 && code < 0x80) {
     // See linux/input.h for the source of this mapping.
     static const ButtonHandle keyboard_map[] = {
@@ -802,12 +840,33 @@ map_button(int code) {
     } else {
       return MouseButton::button(code - BTN_MOUSE);
     }
+
+  } else if ((code & 0xfff0) == BTN_JOYSTICK) {
+    if (device_class == DC_gamepad) {
+      // Based on "Jess Tech Colour Rumble Pad"
+      static const ButtonHandle mapping[] = {
+        GamepadButton::action_x(),
+        GamepadButton::action_y(),
+        GamepadButton::action_a(),
+        GamepadButton::action_b(),
+        GamepadButton::lshoulder(),
+        GamepadButton::ltrigger(),
+        GamepadButton::rshoulder(),
+        GamepadButton::rtrigger(),
+        GamepadButton::back(),
+        GamepadButton::start(),
+        GamepadButton::lstick(),
+        GamepadButton::rstick(),
+      };
+      if ((code & 0xf) < 12) {
+        return mapping[code & 0xf];
+      }
+    } else {
+      return GamepadButton::joystick(code & 0xf);
+    }
   }
 
   switch (code) {
-  case BTN_TRIGGER:
-    return GamepadButton::trigger();
-
   case BTN_A:
     return GamepadButton::action_a();
 

+ 1 - 1
panda/src/device/evdevInputDevice.h

@@ -54,7 +54,7 @@ private:
   int _dpad_up_button;
 
 public:
-  static ButtonHandle map_button(int code);
+  static ButtonHandle map_button(int code, DeviceClass device_class = DC_unknown);
 
 public:
   static TypeHandle get_class_type() {

+ 73 - 75
panda/src/device/inputDevice.cxx

@@ -143,14 +143,17 @@ add_control(ControlAxis axis, int minimum, int maximum, bool centered) {
 int InputDevice::
 add_control(ControlAxis axis, int minimum, int maximum) {
   bool centered = (minimum < 0)
+    || axis == C_x
+    || axis == C_y
+    || axis == C_z
+    || axis == C_yaw
+    || axis == C_pitch
+    || axis == C_roll
     || axis == C_left_x
     || axis == C_left_y
     || axis == C_right_x
     || axis == C_right_y
-    || axis == C_x
-    || axis == C_y
     || axis == C_wheel
-    || axis == C_twist
     || axis == C_rudder;
   return add_control(axis, minimum, maximum, centered);
 }
@@ -499,130 +502,125 @@ void InputDevice::
 do_poll() {
 }
 
-ostream &
-operator << (ostream &out, InputDevice::DeviceClass dc) {
+/**
+ * Returns a string describing the given device class enumerant.
+ */
+string InputDevice::
+format_device_class(DeviceClass dc) {
   switch (dc) {
   case InputDevice::DC_unknown:
-    out << "unknown";
-    break;
+    return "unknown";
 
   case InputDevice::DC_virtual:
-    out << "virtual";
-    break;
+    return "virtual";
 
   case InputDevice::DC_keyboard:
-    out << "keyboard";
-    break;
+    return "keyboard";
 
   case InputDevice::DC_mouse:
-    out << "mouse";
-    break;
+    return "mouse";
 
   case InputDevice::DC_touch:
-    out << "touch";
-    break;
+    return "touch";
 
   case InputDevice::DC_gamepad:
-    out << "gamepad";
-    break;
+    return "gamepad";
 
   case InputDevice::DC_flight_stick:
-    out << "flight_stick";
-    break;
+    return "flight_stick";
 
   case InputDevice::DC_steering_wheel:
-    out << "steering_wheel";
-    break;
+    return "steering_wheel";
 
   case InputDevice::DC_dance_pad:
-    out << "dance_pad";
-    break;
+    return "dance_pad";
 
   case InputDevice::DC_hmd:
-    out << "hmd";
-    break;
+    return "hmd";
+
+  case InputDevice::DC_3d_mouse:
+    return "3d_mouse";
 
   case InputDevice::DC_COUNT:
     break;
   }
-  return out;
+  return "**invalid**";
 }
 
-ostream &
-operator << (ostream &out, InputDevice::ControlAxis axis) {
+/**
+ * Returns a string describing the given axis enumerant.
+ */
+string InputDevice::
+format_axis(ControlAxis axis) {
   switch (axis) {
   case InputDevice::C_none:
-    out << "none";
-    break;
+    return "none";
+
+  case InputDevice::C_x:
+    return "x";
+
+  case InputDevice::C_y:
+    return "y";
+
+  case InputDevice::C_z:
+    return "z";
+
+  case InputDevice::C_yaw:
+    return "yaw";
+
+  case InputDevice::C_pitch:
+    return "pitch";
+
+  case InputDevice::C_roll:
+    return "roll";
 
   case InputDevice::C_left_x:
-    out << "left_x";
-    break;
+    return "left_x";
 
   case InputDevice::C_left_y:
-    out << "left_y";
-    break;
+    return "left_y";
 
   case InputDevice::C_left_trigger:
-    out << "left_trigger";
-    break;
+    return "left_trigger";
 
   case InputDevice::C_right_x:
-    out << "right_x";
-    break;
+    return "right_x";
 
   case InputDevice::C_right_y:
-    out << "right_y";
-    break;
+    return "right_y";
 
   case InputDevice::C_right_trigger:
-    out << "right_trigger";
-    break;
-
-  case InputDevice::C_x:
-    out << "x";
-    break;
-
-  case InputDevice::C_y:
-    out << "y";
-    break;
+    return "right_trigger";
 
-  case InputDevice::C_trigger:
-    out << "trigger";
-    break;
+  //case InputDevice::C_trigger:
+  //  return "trigger";
 
   case InputDevice::C_throttle:
-    out << "throttle";
-    break;
-
-  case InputDevice::C_twist:
-    out << "twist";
-    break;
+    return "throttle";
 
   case InputDevice::C_rudder:
-    out << "rudder";
-    break;
-
-  case InputDevice::C_hat_x:
-    out << "hat_x";
-    break;
-
-  case InputDevice::C_hat_y:
-    out << "hat_y";
-    break;
+    return "rudder";
 
   case InputDevice::C_wheel:
-    out << "wheel";
-    break;
+    return "wheel";
 
   case InputDevice::C_accelerator:
-    out << "accelerator";
-    break;
+    return "accelerator";
 
   case InputDevice::C_brake:
-    out << "brake";
-    break;
+    return "brake";
   }
+  return "**invalid**";
+}
+
+ostream &
+operator << (ostream &out, InputDevice::DeviceClass dc) {
+  out << InputDevice::format_device_class(dc);
+  return out;
+}
 
+ostream &
+operator << (ostream &out, InputDevice::ControlAxis axis) {
+  out << InputDevice::format_axis(axis);
   return out;
 }

+ 17 - 8
panda/src/device/inputDevice.h

@@ -78,6 +78,9 @@ PUBLISHED:
     // Head-mounted display.
     DC_hmd,
 
+    // 3D mouse, such as produced by 3Dconnexion.
+    DC_3d_mouse,
+
     // Count of this enum, used for loops
     DC_COUNT,
   };
@@ -95,6 +98,16 @@ PUBLISHED:
   enum ControlAxis {
     C_none,
 
+    // Generic translational axes
+    C_x,
+    C_y,
+    C_z,
+
+    // Generic rotational axes, used by joysticks and 3D mice
+    C_yaw,
+    C_pitch,
+    C_roll,
+
     // Gamepad
     C_left_x,
     C_left_y,
@@ -103,15 +116,9 @@ PUBLISHED:
     C_right_y,
     C_right_trigger,
 
-    // Flight stick
-    C_x,
-    C_y,
-    C_trigger,
+    // Flight stick specific
     C_throttle,
-    C_twist,
-    C_rudder,
-    C_hat_x,
-    C_hat_y,
+    C_rudder, // When available separately from yaw
 
     // Steering wheel / pedals
     C_wheel,
@@ -183,6 +190,8 @@ PUBLISHED:
   PT(PointerEventList) get_pointer_events();
 
   virtual void output(ostream &out) const;
+  static string format_device_class(DeviceClass dc);
+  static string format_axis(ControlAxis axis);
 
 protected:
   // Called during the constructor to add new controls or buttons

+ 19 - 13
panda/src/device/linuxJoystickDevice.cxx

@@ -251,7 +251,7 @@ open_device() {
         if (_device_class == DC_gamepad) {
           axis = C_left_trigger;
         } else {
-          axis = C_trigger;
+          //axis = C_trigger;
         }
         break;
 
@@ -288,28 +288,34 @@ open_device() {
         break;
 
       case ABS_HAT0X:
-        if (_dpad_left_button == -1 && _device_class == DC_gamepad) {
-          // Emulate D-Pad.
+        if (_dpad_left_button == -1) {
+          // Emulate D-Pad or hat switch.
           _dpad_x_axis = i;
           _dpad_left_button = (int)_buttons.size();
-          _buttons.push_back(ButtonState(GamepadButton::dpad_left()));
-          _buttons.push_back(ButtonState(GamepadButton::dpad_right()));
+          if (_device_class == DC_gamepad) {
+            _buttons.push_back(ButtonState(GamepadButton::dpad_left()));
+            _buttons.push_back(ButtonState(GamepadButton::dpad_right()));
+          } else {
+            _buttons.push_back(ButtonState(GamepadButton::hat_left()));
+            _buttons.push_back(ButtonState(GamepadButton::hat_right()));
+          }
           axis = C_none;
-        } else {
-          axis = C_hat_x;
         }
         break;
 
       case ABS_HAT0Y:
-        if (_dpad_up_button == -1 && _device_class == DC_gamepad) {
+        if (_dpad_up_button == -1) {
           // Emulate D-Pad.
           _dpad_y_axis = i;
           _dpad_up_button = (int)_buttons.size();
-          _buttons.push_back(ButtonState(GamepadButton::dpad_up()));
-          _buttons.push_back(ButtonState(GamepadButton::dpad_down()));
+          if (_device_class == DC_gamepad) {
+            _buttons.push_back(ButtonState(GamepadButton::dpad_up()));
+            _buttons.push_back(ButtonState(GamepadButton::dpad_down()));
+          } else {
+            _buttons.push_back(ButtonState(GamepadButton::hat_up()));
+            _buttons.push_back(ButtonState(GamepadButton::hat_down()));
+          }
           axis = C_none;
-        } else {
-          axis = C_hat_y;
         }
         break;
 
@@ -323,7 +329,7 @@ open_device() {
       }
       _controls[i].axis = axis;
 
-      if (axis == C_left_trigger || axis == C_right_trigger || axis == C_trigger) {
+      if (axis == C_left_trigger || axis == C_right_trigger) {
         // We'd like to use 0.0 to indicate the resting position.
         _controls[i]._scale = 1.0 / 65534.0;
         _controls[i]._bias = 0.5;

+ 1 - 1
panda/src/device/linuxJoystickDevice.h

@@ -39,7 +39,7 @@ private:
   int _fd;
   int _index;
 
-  // These are used for D-pad emulation.
+  // These are used for D-pad / hat switch emulation.
   int _dpad_x_axis;
   int _dpad_y_axis;
   int _dpad_left_button;

+ 3 - 3
panda/src/device/xInputDevice.cxx

@@ -271,10 +271,10 @@ init_device(const XINPUT_CAPABILITIES &caps, const XINPUT_STATE &state) {
 
   case XINPUT_DEVSUBTYPE_FLIGHT_STICK:
     _device_class = DC_flight_stick;
-    set_control_map(0, C_rudder);
+    set_control_map(0, C_yaw);
     set_control_map(1, C_throttle);
-    set_control_map(2, C_x);
-    set_control_map(3, C_y);
+    set_control_map(2, C_roll);
+    set_control_map(3, C_pitch);
     set_control_map(4, C_hat_x);
     set_control_map(5, C_hat_y);
     break;

+ 30 - 0
panda/src/putil/gamepadButton.cxx

@@ -48,6 +48,32 @@ DEFINE_GAMEPAD_BUTTON_HANDLE(action_1)
 DEFINE_GAMEPAD_BUTTON_HANDLE(action_2)
 
 DEFINE_GAMEPAD_BUTTON_HANDLE(trigger)
+DEFINE_GAMEPAD_BUTTON_HANDLE(hat_up)
+DEFINE_GAMEPAD_BUTTON_HANDLE(hat_down)
+DEFINE_GAMEPAD_BUTTON_HANDLE(hat_left)
+DEFINE_GAMEPAD_BUTTON_HANDLE(hat_right)
+
+/**
+ * Returns the ButtonHandle associated with the particular numbered joystick
+ * button (zero-based), if there is one, or ButtonHandle::none() if there is
+ * not.
+ */
+ButtonHandle GamepadButton::
+joystick(int button_number) {
+  if (button_number >= 0) {
+    // "button1" does not exist, it is called "trigger" instead
+    static pvector<ButtonHandle> buttons(1, _trigger);
+    while (button_number >= buttons.size()) {
+      char numstr[20];
+      sprintf(numstr, "joystick%d", (int)buttons.size() + 1);
+      ButtonHandle handle;
+      ButtonRegistry::ptr()->register_button(handle, numstr);
+      buttons.push_back(handle);
+    }
+    return buttons[button_number];
+  }
+  return ButtonHandle::none();
+}
 
 /**
  * This is intended to be called only once, by the static initialization
@@ -85,4 +111,8 @@ init_gamepad_buttons() {
   ButtonRegistry::ptr()->register_button(_action_2, "action_2");
 
   ButtonRegistry::ptr()->register_button(_trigger, "trigger");
+  ButtonRegistry::ptr()->register_button(_hat_up, "hat_up");
+  ButtonRegistry::ptr()->register_button(_hat_down, "hat_down");
+  ButtonRegistry::ptr()->register_button(_hat_left, "hat_left");
+  ButtonRegistry::ptr()->register_button(_hat_right, "hat_right");
 }

+ 6 - 0
panda/src/putil/gamepadButton.h

@@ -53,7 +53,13 @@ PUBLISHED:
   static ButtonHandle action_1();
   static ButtonHandle action_2();
 
+  // Flight stick buttons, takes zero-based index.  First is always trigger.
   static ButtonHandle trigger();
+  static ButtonHandle joystick(int button_number);
+  static ButtonHandle hat_up();
+  static ButtonHandle hat_down();
+  static ButtonHandle hat_left();
+  static ButtonHandle hat_right();
 
 public:
   static void init_gamepad_buttons();