Browse Source

input: let InputDevice manage axis remapping, add C_twist axis

rdb 8 years ago
parent
commit
12cfc93b79

+ 12 - 32
panda/src/device/evdevInputDevice.cxx

@@ -371,17 +371,10 @@ init_device() {
   }
   }
 
 
   if (has_axes) {
   if (has_axes) {
-    AxisRange range;
-    range._scale = 1.0;
-    range._bias = 0.0;
-    _axis_ranges.resize(ABS_CNT, range);
-
-
     for (int i = 0; i < num_bits; ++i) {
     for (int i = 0; i < num_bits; ++i) {
       if (test_bit(i, axes)) {
       if (test_bit(i, axes)) {
+        ControlAxis axis = C_none;
         if (i >= ABS_HAT0X) {
         if (i >= ABS_HAT0X) {
-          set_control_map(i, C_none);
-
           // Emulate D-Pad buttons if necessary.
           // Emulate D-Pad buttons if necessary.
           if (i == ABS_HAT0X && emulate_dpad) {
           if (i == ABS_HAT0X && emulate_dpad) {
             _dpad_x_axis = i;
             _dpad_x_axis = i;
@@ -395,38 +388,25 @@ init_device() {
             _buttons.push_back(ButtonState(GamepadButton::dpad_up()));
             _buttons.push_back(ButtonState(GamepadButton::dpad_up()));
             _buttons.push_back(ButtonState(GamepadButton::dpad_down()));
             _buttons.push_back(ButtonState(GamepadButton::dpad_down()));
           } else if (i == ABS_HAT0X) {
           } else if (i == ABS_HAT0X) {
-            set_control_map(i, C_hat_x);
+            axis = C_hat_x;
           } else if (i == ABS_HAT0Y) {
           } else if (i == ABS_HAT0Y) {
-            set_control_map(i, C_hat_y);
+            axis = C_hat_y;
           }
           }
         } else {
         } else {
-          set_control_map(i, axis_map[i]);
+          axis = axis_map[i];
           //cerr << "Axis " << axis_map[i] << " is mapped by the driver to " << i << "\n";
           //cerr << "Axis " << axis_map[i] << " is mapped by the driver to " << i << "\n";
         }
         }
 
 
         // Check the initial value and ranges.
         // Check the initial value and ranges.
         struct input_absinfo absinfo;
         struct input_absinfo absinfo;
         if (ioctl(_fd, EVIOCGABS(i), &absinfo) >= 0) {
         if (ioctl(_fd, EVIOCGABS(i), &absinfo) >= 0) {
-          double factor, bias;
-          if (absinfo.minimum < 0) {
-            // Centered, eg. for sticks.
-            factor = 2.0 / (absinfo.maximum - absinfo.minimum);
-            bias = (absinfo.maximum + absinfo.minimum) / (double)(absinfo.minimum - absinfo.maximum);
-          } else {
-            // 0-based, eg. for triggers.
-            factor = 1.0 / absinfo.maximum;
-            bias = 0.0;
-          }
-
           // Flip Y axis to match Windows implementation.
           // Flip Y axis to match Windows implementation.
           if (i == ABS_Y || i == ABS_RY) {
           if (i == ABS_Y || i == ABS_RY) {
-            factor = -factor;
-            bias = -bias;
+            swap(absinfo.minimum, absinfo.maximum);
           }
           }
 
 
-          _axis_ranges[i]._scale = factor;
-          _axis_ranges[i]._bias = bias;
-          _controls[i].state = fma(absinfo.value, factor, bias);
+          add_control(axis, absinfo.minimum, absinfo.maximum);
+          control_changed(axis, absinfo.value);
 
 
           if (absinfo.value != 0) {
           if (absinfo.value != 0) {
             all_values_zero = false;
             all_values_zero = false;
@@ -562,13 +542,13 @@ process_events() {
 
 
     case EV_ABS:
     case EV_ABS:
       if (code == _dpad_x_axis) {
       if (code == _dpad_x_axis) {
-        set_button_state(_dpad_left_button, events[i].value < 0);
-        set_button_state(_dpad_left_button+1, events[i].value > 0);
+        button_changed(_dpad_left_button, events[i].value < 0);
+        button_changed(_dpad_left_button+1, events[i].value > 0);
       } else if (code == _dpad_y_axis) {
       } else if (code == _dpad_y_axis) {
-        set_button_state(_dpad_up_button, events[i].value < 0);
-        set_button_state(_dpad_up_button+1, events[i].value > 0);
+        button_changed(_dpad_up_button, events[i].value < 0);
+        button_changed(_dpad_up_button+1, events[i].value > 0);
       }
       }
-      set_control_state(code, fma(events[i].value, _axis_ranges[code]._scale, _axis_ranges[code]._bias));
+      control_changed(code, events[i].value);
       break;
       break;
 
 
     case EV_KEY:
     case EV_KEY:

+ 0 - 6
panda/src/device/evdevInputDevice.h

@@ -44,12 +44,6 @@ private:
   int _ff_strong;
   int _ff_strong;
   int _ff_weak;
   int _ff_weak;
 
 
-  struct AxisRange {
-    double _scale;
-    double _bias;
-  };
-  pvector<AxisRange> _axis_ranges;
-
   // These are used for D-pad emulation.
   // These are used for D-pad emulation.
   int _dpad_x_axis;
   int _dpad_x_axis;
   int _dpad_y_axis;
   int _dpad_y_axis;

+ 3 - 1
panda/src/device/inputDevice.I

@@ -461,6 +461,8 @@ INLINE InputDevice::AnalogState::
 AnalogState() :
 AnalogState() :
   axis(C_none),
   axis(C_none),
   state(0.0),
   state(0.0),
-  known(false)
+  known(false),
+  _scale(1.0),
+  _bias(0.0)
 {
 {
 }
 }

+ 80 - 1
panda/src/device/inputDevice.cxx

@@ -114,6 +114,45 @@ get_pointer_events() {
   return result;
   return result;
 }
 }
 
 
+
+/**
+ * Called by the implementation to add a new known control.
+ */
+void InputDevice::
+add_control(ControlAxis axis, int minimum, int maximum, bool centered) {
+  AnalogState state;
+  state.axis = axis;
+  if (centered) {
+    // Centered, eg. for sticks.
+    state._scale = 2.0 / (maximum - minimum);
+    state._bias = (maximum + minimum) / (double)(minimum - maximum);
+  } else {
+    // 0-based, eg. for triggers.
+    state._scale = 1.0 / maximum;
+    state._bias = 0.0;
+  }
+  _controls.push_back(state);
+}
+
+/**
+ * Called by the implementation to add a new known control.  This version
+ * tries to guess whether the control is centered or not.
+ */
+void InputDevice::
+add_control(ControlAxis axis, int minimum, int maximum) {
+  bool centered = (minimum < 0)
+    || 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;
+  add_control(axis, minimum, maximum, centered);
+}
+
 /**
 /**
  * Records that a mouse movement has taken place.
  * Records that a mouse movement has taken place.
  */
  */
@@ -165,6 +204,11 @@ pointer_moved(double x, double y, double time) {
   _pointer_data._xpos += x;
   _pointer_data._xpos += x;
   _pointer_data._ypos += y;
   _pointer_data._ypos += y;
 
 
+  if (device_cat.is_spam() && (x != 0 || y != 0)) {
+    device_cat.spam()
+      << "Pointer moved by " << x << " x " << y << "\n";
+  }
+
   if (_enable_pointer_events) {
   if (_enable_pointer_events) {
     int seq = _event_sequence++;
     int seq = _event_sequence++;
     if (_pointer_events.is_null()) {
     if (_pointer_events.is_null()) {
@@ -184,7 +228,7 @@ pointer_moved(double x, double y, double time) {
  * while this call is made.
  * while this call is made.
  */
  */
 void InputDevice::
 void InputDevice::
-set_button_state(int index, bool down) {
+button_changed(int index, bool down) {
   nassertv(_lock.debug_is_locked());
   nassertv(_lock.debug_is_locked());
   nassertv(index >= 0);
   nassertv(index >= 0);
   if (index >= (int)_buttons.size()) {
   if (index >= (int)_buttons.size()) {
@@ -244,6 +288,34 @@ set_control_state(int index, double state) {
   _controls[index].known = true;
   _controls[index].known = true;
 }
 }
 
 
+/**
+ * Like set_control_state, but instead passes a raw, unscaled value.
+ */
+void InputDevice::
+control_changed(int index, int state) {
+  nassertv(_lock.debug_is_locked());
+  nassertv(index >= 0);
+  if (index >= (int)_controls.size()) {
+    _controls.resize(index + 1, AnalogState());
+  }
+
+  double new_state = fma((double)state, _controls[index]._scale, _controls[index]._bias);
+
+  if (device_cat.is_spam() && _controls[index].state != new_state) {
+    device_cat.spam()
+      << "Changed control " << index;
+
+    if (_controls[index].axis != C_none) {
+      device_cat.spam(false) << " (" << _controls[index].axis << ")";
+    }
+
+    device_cat.spam(false) << " to " << new_state << " (raw value " << state << ")\n";
+  }
+
+  _controls[index].state = new_state;
+  _controls[index].known = true;
+}
+
 /**
 /**
  * Records that a tracker movement has taken place.
  * Records that a tracker movement has taken place.
  */
  */
@@ -467,6 +539,9 @@ operator << (ostream &out, InputDevice::DeviceClass dc) {
   case InputDevice::DC_hmd:
   case InputDevice::DC_hmd:
     out << "hmd";
     out << "hmd";
     break;
     break;
+
+  case InputDevice::DC_COUNT:
+    break;
   }
   }
   return out;
   return out;
 }
 }
@@ -518,6 +593,10 @@ operator << (ostream &out, InputDevice::ControlAxis axis) {
     out << "throttle";
     out << "throttle";
     break;
     break;
 
 
+  case InputDevice::C_twist:
+    out << "twist";
+    break;
+
   case InputDevice::C_rudder:
   case InputDevice::C_rudder:
     out << "rudder";
     out << "rudder";
     break;
     break;

+ 13 - 1
panda/src/device/inputDevice.h

@@ -108,6 +108,7 @@ PUBLISHED:
     C_y,
     C_y,
     C_trigger,
     C_trigger,
     C_throttle,
     C_throttle,
+    C_twist,
     C_rudder,
     C_rudder,
     C_hat_x,
     C_hat_x,
     C_hat_y,
     C_hat_y,
@@ -183,11 +184,18 @@ PUBLISHED:
   virtual void output(ostream &out) const;
   virtual void output(ostream &out) const;
 
 
 protected:
 protected:
+  // Called during the constructor to add new controls or buttons
+  void add_control(ControlAxis axis, int minimum, int maximum, bool centered);
+  void add_control(ControlAxis axis, int minimum, int maximum);
+
   void set_pointer(bool inwin, double x, double y, double time);
   void set_pointer(bool inwin, double x, double y, double time);
   void set_pointer_out_of_window(double time);
   void set_pointer_out_of_window(double time);
+
   void pointer_moved(double x, double y, double time);
   void pointer_moved(double x, double y, double time);
-  void set_button_state(int index, bool down);
+  void button_changed(int index, bool down);
+  void control_changed(int index, int value);
   void set_control_state(int index, double state);
   void set_control_state(int index, double state);
+
   void set_tracker(const LPoint3 &pos, const LOrientation &orient, double time);
   void set_tracker(const LPoint3 &pos, const LOrientation &orient, double time);
 
 
   virtual void do_set_vibration(double low, double high);
   virtual void do_set_vibration(double low, double high);
@@ -271,6 +279,10 @@ PUBLISHED:
     ControlAxis axis;
     ControlAxis axis;
     double state;
     double state;
     bool known;
     bool known;
+
+  public:
+    double _scale;
+    double _bias;
   };
   };
   typedef pvector<AnalogState> Controls;
   typedef pvector<AnalogState> Controls;
   Controls _controls;
   Controls _controls;

+ 18 - 15
panda/src/device/linuxJoystickDevice.cxx

@@ -322,6 +322,18 @@ open_device() {
         break;
         break;
       }
       }
       _controls[i].axis = axis;
       _controls[i].axis = axis;
+
+      if (axis == C_left_trigger || axis == C_right_trigger || axis == C_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;
+      } 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;
+      } else {
+        _controls[i]._scale = 1.0 / 32767.0;
+        _controls[i]._bias = 0.0;
+      }
     }
     }
   }
   }
 
 
@@ -436,27 +448,18 @@ process_events() {
     int index = events[i].number;
     int index = events[i].number;
 
 
     if (events[i].type & JS_EVENT_BUTTON) {
     if (events[i].type & JS_EVENT_BUTTON) {
-      set_button_state(index, (events[i].value != 0));
+      button_changed(index, (events[i].value != 0));
 
 
     } else if (events[i].type & JS_EVENT_AXIS) {
     } else if (events[i].type & JS_EVENT_AXIS) {
       if (index == _dpad_x_axis) {
       if (index == _dpad_x_axis) {
-        set_button_state(_dpad_left_button, events[i].value < -1000);
-        set_button_state(_dpad_left_button+1, events[i].value > 1000);
+        button_changed(_dpad_left_button, events[i].value < -1000);
+        button_changed(_dpad_left_button+1, events[i].value > 1000);
       } else if (index == _dpad_y_axis) {
       } else if (index == _dpad_y_axis) {
-        set_button_state(_dpad_up_button, events[i].value < -1000);
-        set_button_state(_dpad_up_button+1, events[i].value > 1000);
+        button_changed(_dpad_up_button, events[i].value < -1000);
+        button_changed(_dpad_up_button+1, events[i].value > 1000);
       }
       }
 
 
-      ControlAxis axis = _controls[index].axis;
-
-      if (axis == C_left_trigger || axis == C_right_trigger || axis == C_trigger) {
-        // We'd like to use 0.0 to indicate the resting position.
-        set_control_state(index, (events[i].value + 32767) / 65534.0);
-      } else if (axis == C_left_y || axis == C_right_y || axis == C_y) {
-        set_control_state(index, events[i].value / -32767.0);
-      } else {
-        set_control_state(index, events[i].value / 32767.0);
-      }
+      control_changed(index, events[i].value);
     }
     }
   }
   }
 
 

+ 25 - 13
panda/src/device/xInputDevice.cxx

@@ -290,6 +290,18 @@ init_device(const XINPUT_CAPABILITIES &caps, const XINPUT_STATE &state) {
     break;
     break;
   }
   }
 
 
+  _controls[0]._scale = 1.0 / 255.0;
+  _controls[1]._scale = 1.0 / 255.0;
+  _controls[2]._scale = 1.0 / 32767.5;
+  _controls[3]._scale = 1.0 / 32767.5;
+  _controls[4]._scale = 1.0 / 32767.5;
+  _controls[5]._scale = 1.0 / 32767.5;
+
+  _controls[2]._bias = 0.5 / 32767.5;
+  _controls[3]._bias = 0.5 / 32767.5;
+  _controls[4]._bias = 0.5 / 32767.5;
+  _controls[5]._bias = 0.5 / 32767.5;
+
   if (caps.Flags & XINPUT_CAPS_NO_NAVIGATION) {
   if (caps.Flags & XINPUT_CAPS_NO_NAVIGATION) {
     set_button_map(0, ButtonHandle::none());
     set_button_map(0, ButtonHandle::none());
     set_button_map(1, ButtonHandle::none());
     set_button_map(1, ButtonHandle::none());
@@ -387,12 +399,12 @@ init_device(const XINPUT_CAPABILITIES &caps, const XINPUT_STATE &state) {
     }
     }
   }
   }
 
 
-  set_control_state(0, state.Gamepad.bLeftTrigger / 255.0);
-  set_control_state(1, state.Gamepad.bRightTrigger / 255.0);
-  set_control_state(2, state.Gamepad.sThumbLX / 32767.0);
-  set_control_state(3, state.Gamepad.sThumbLY / 32767.0);
-  set_control_state(4, state.Gamepad.sThumbRX / 32767.0);
-  set_control_state(5, state.Gamepad.sThumbRY / 32767.0);
+  control_changed(0, state.Gamepad.bLeftTrigger);
+  control_changed(1, state.Gamepad.bRightTrigger);
+  control_changed(2, state.Gamepad.sThumbLX);
+  control_changed(3, state.Gamepad.sThumbLY);
+  control_changed(4, state.Gamepad.sThumbRX);
+  control_changed(5, state.Gamepad.sThumbRY);
 
 
   _last_buttons = buttons;
   _last_buttons = buttons;
   _last_packet = state.dwPacketNumber;
   _last_packet = state.dwPacketNumber;
@@ -453,7 +465,7 @@ do_poll() {
   WORD mask = 1;
   WORD mask = 1;
   for (int i = 0; i < 16; ++i) {
   for (int i = 0; i < 16; ++i) {
     if (changed_buttons & mask) {
     if (changed_buttons & mask) {
-      set_button_state(i, (state.Gamepad.wButtons & mask) != 0);
+      button_changed(i, (state.Gamepad.wButtons & mask) != 0);
     }
     }
     mask <<= 1;
     mask <<= 1;
     if (i == 10) {
     if (i == 10) {
@@ -462,12 +474,12 @@ do_poll() {
     }
     }
   }
   }
 
 
-  set_control_state(0, state.Gamepad.bLeftTrigger / 255.0);
-  set_control_state(1, state.Gamepad.bRightTrigger / 255.0);
-  set_control_state(2, (state.Gamepad.sThumbLX + 0.5) / 32767.5);
-  set_control_state(3, (state.Gamepad.sThumbLY + 0.5) / 32767.5);
-  set_control_state(4, (state.Gamepad.sThumbRX + 0.5) / 32767.5);
-  set_control_state(5, (state.Gamepad.sThumbRY + 0.5) / 32767.5);
+  control_changed(0, state.Gamepad.bLeftTrigger);
+  control_changed(1, state.Gamepad.bRightTrigger);
+  control_changed(2, state.Gamepad.sThumbLX);
+  control_changed(3, state.Gamepad.sThumbLY);
+  control_changed(4, state.Gamepad.sThumbRX);
+  control_changed(5, state.Gamepad.sThumbRY);
 
 
   _last_buttons = state.Gamepad.wButtons;
   _last_buttons = state.Gamepad.wButtons;
   _last_packet = state.dwPacketNumber;
   _last_packet = state.dwPacketNumber;

+ 1 - 1
panda/src/vrpn/vrpnButton.cxx

@@ -103,6 +103,6 @@ vrpn_button_callback(void *userdata, const vrpn_BUTTONCB info) {
   Devices::iterator di;
   Devices::iterator di;
   for (di = self->_devices.begin(); di != self->_devices.end(); ++di) {
   for (di = self->_devices.begin(); di != self->_devices.end(); ++di) {
     VrpnButtonDevice *device = (*di);
     VrpnButtonDevice *device = (*di);
-    device->set_button_state(info.button, info.state != 0);
+    device->button_changed(info.button, info.state != 0);
   }
   }
 }
 }