ソースを参照

device: overhaul InputDevice API:

- Rename "controls" terminology for analog inputs to "axes"
- Change some naming of accessors
- Unexpose methods where they are available as properties
- Add serial_number field
- Put battery levels under a "battery" field
rdb 7 年 前
コミット
8edc019307

+ 3 - 3
panda/src/device/analogNode.I

@@ -35,7 +35,7 @@ is_valid() const {
  */
 INLINE int AnalogNode::
 get_num_controls() const {
-  return _analog->get_num_controls();
+  return _analog->get_num_axes();
 }
 
 /**
@@ -45,7 +45,7 @@ get_num_controls() const {
  */
 INLINE double AnalogNode::
 get_control_state(int index) const {
-  return _analog->get_control_state(index);
+  return _analog->get_axis_value(index);
 }
 
 /**
@@ -54,7 +54,7 @@ get_control_state(int index) const {
  */
 INLINE bool AnalogNode::
 is_control_known(int index) const {
-  return _analog->is_control_known(index);
+  return _analog->is_axis_known(index);
 }
 
 /**

+ 9 - 7
panda/src/device/analogNode.cxx

@@ -81,7 +81,7 @@ write(std::ostream &out, int indent_level) const {
   DataNode::write(out, indent_level);
 
   if (_analog != nullptr) {
-    _analog->write_controls(out, indent_level + 2);
+    _analog->write_axes(out, indent_level + 2);
   }
 }
 
@@ -101,12 +101,14 @@ do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &,
 
     LPoint2 out(0.0f, 0.0f);
     for (int i = 0; i < max_outputs; i++) {
-      if (_outputs[i]._index >= 0 &&
-          _analog->is_control_known(_outputs[i]._index)) {
-        if (_outputs[i]._flip) {
-          out[i] = -_analog->get_control_state(_outputs[i]._index);
-        } else {
-          out[i] = _analog->get_control_state(_outputs[i]._index);
+      if (_outputs[i]._index >= 0) {
+        InputDevice::AxisState state = _analog->get_axis(_outputs[i]._index);
+        if (state.known) {
+          if (_outputs[i]._flip) {
+            out[i] = -state.value;
+          } else {
+            out[i] = state.value;
+          }
         }
       }
     }

+ 2 - 2
panda/src/device/buttonNode.I

@@ -43,7 +43,7 @@ get_num_buttons() const {
  */
 INLINE void ButtonNode::
 set_button_map(int index, ButtonHandle button) {
-  _device->set_button_map(index, button);
+  _device->map_button(index, button);
 }
 
 /**
@@ -62,7 +62,7 @@ get_button_map(int index) const {
  */
 INLINE bool ButtonNode::
 get_button_state(int index) const {
-  return _device->get_button_state(index);
+  return _device->is_button_pressed(index);
 }
 
 /**

+ 1 - 1
panda/src/device/clientAnalogDevice.cxx

@@ -23,5 +23,5 @@ TypeHandle ClientAnalogDevice::_type_handle;
 void ClientAnalogDevice::
 write(std::ostream &out, int indent_level) const {
   indent(out, indent_level) << get_type() << " " << get_name() << ":\n";
-  write_controls(out, indent_level + 2);
+  write_axes(out, indent_level + 2);
 }

+ 15 - 15
panda/src/device/evdevInputDevice.cxx

@@ -392,10 +392,10 @@ init_device() {
         }
 
         if (test_bit(i, states)) {
-          button.state = S_down;
+          button._state = S_down;
           all_values_zero = false;
         } else {
-          button.state = S_up;
+          button._state = S_up;
         }
         if (button.handle == GamepadButton::dpad_left()) {
           emulate_dpad = false;
@@ -415,7 +415,7 @@ init_device() {
   }
 
   if (has_axes) {
-    _control_indices.resize(num_bits, -1);
+    _axis_indices.resize(num_bits, -1);
 
     for (int i = 0; i < num_bits; ++i) {
       if (test_bit(i, axes)) {
@@ -545,12 +545,12 @@ init_device() {
             std::swap(absinfo.maximum, absinfo.minimum);
           }
           if (axis == Axis::throttle && (quirks & QB_centered_throttle) != 0) {
-            index = add_control(axis, absinfo.maximum, absinfo.minimum, true);
+            index = add_axis(axis, absinfo.maximum, absinfo.minimum, true);
           } else {
-            index = add_control(axis, absinfo.minimum, absinfo.maximum);
+            index = add_axis(axis, absinfo.minimum, absinfo.maximum);
           }
-          control_changed(index, absinfo.value);
-          _control_indices[i] = index;
+          axis_changed(index, absinfo.value);
+          _axis_indices[i] = index;
 
           if (absinfo.value != 0) {
             all_values_zero = false;
@@ -583,9 +583,9 @@ init_device() {
 
   if (_ltrigger_code >= 0 && _rtrigger_code >= 0 && !have_analog_triggers) {
     // Emulate analog triggers.
-    _ltrigger_control = (int)_controls.size();
-    add_control(Axis::left_trigger, 0, 1, false);
-    add_control(Axis::right_trigger, 0, 1, false);
+    _ltrigger_axis = (int)_axes.size();
+    add_axis(Axis::left_trigger, 0, 1, false);
+    add_axis(Axis::right_trigger, 0, 1, false);
   } else {
     _ltrigger_code = -1;
     _rtrigger_code = -1;
@@ -709,10 +709,10 @@ process_events() {
         button_changed(_dpad_up_button, events[i].value < 0);
         button_changed(_dpad_up_button+1, events[i].value > 0);
       }
-      nassertd(code >= 0 && (size_t)code < _control_indices.size()) break;
-      index = _control_indices[code];
+      nassertd(code >= 0 && (size_t)code < _axis_indices.size()) break;
+      index = _axis_indices[code];
       if (index >= 0) {
-        control_changed(index, events[i].value);
+        axis_changed(index, events[i].value);
       }
       break;
 
@@ -723,9 +723,9 @@ process_events() {
         button_changed(index, events[i].value != 0);
       }
       if (code == _ltrigger_code) {
-        control_changed(_ltrigger_control, events[i].value);
+        axis_changed(_ltrigger_axis, events[i].value);
       } else if (code == _rtrigger_code) {
-        control_changed(_ltrigger_control + 1, events[i].value);
+        axis_changed(_ltrigger_axis + 1, events[i].value);
       }
       break;
 

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

@@ -49,7 +49,7 @@ private:
   int _ff_strong;
   int _ff_weak;
 
-  pvector<int> _control_indices;
+  pvector<int> _axis_indices;
   pvector<int> _button_indices;
 
   // These are used for D-pad emulation.
@@ -59,7 +59,7 @@ private:
   int _dpad_up_button;
 
   // This is used for axis emulation.
-  int _ltrigger_control;
+  int _ltrigger_axis;
   int _ltrigger_code;
   int _rtrigger_code;
 

+ 73 - 100
panda/src/device/inputDevice.I

@@ -24,9 +24,7 @@ InputDevice() :
   _product_id(0),
   _is_connected(false),
   _event_sequence(0),
-  _enable_pointer_events(false),
-  _battery_level(-1),
-  _max_battery_level(-1)
+  _enable_pointer_events(false)
 {
   _button_events = new ButtonEventList;
 }
@@ -50,6 +48,16 @@ get_manufacturer() const {
   return _manufacturer;
 }
 
+/**
+ * Returns a string containing the serial number of the device, if this
+ * information is known.
+ */
+INLINE std::string InputDevice::
+get_serial_number() const {
+  LightMutexHolder holder(_lock);
+  return _serial_number;
+}
+
 /**
  * Returns a string containing the USB vendor ID of the device, if this
  * information is known.
@@ -160,23 +168,12 @@ get_tracker() const {
 
 /**
  * Returns a rough indication of the battery level, ranging from 0 (completely
- * empty battery) to the number reported by get_max_battery_level(), which
- * represents a full battery.  If this information is not known, returns -1.
+ * empty battery) to the indicated max_level value.
  */
-INLINE short InputDevice::
-get_battery_level() const {
+INLINE InputDevice::BatteryData InputDevice::
+get_battery() const {
   LightMutexHolder holder(_lock);
-  return _battery_level;
-}
-
-/**
- * Returns the maximum value that may be reported by get_battery_level(),
- * representing a full battery.  Returns -1 if no battery information is known.
- */
-INLINE short InputDevice::
-get_max_battery_level() const {
-  LightMutexHolder holder(_lock);
-  return _max_battery_level;
+  return _battery_data;
 }
 
 /**
@@ -202,7 +199,7 @@ get_num_buttons() const {
  * generate ButtonEvents when the buttons change state.
  */
 INLINE void InputDevice::
-set_button_map(size_t index, ButtonHandle button) {
+map_button(size_t index, ButtonHandle button) {
   LightMutexHolder holder(_lock);
   if (index >= _buttons.size()) {
     _buttons.resize(index + 1, ButtonState());
@@ -213,7 +210,7 @@ set_button_map(size_t index, ButtonHandle button) {
 
 /**
  * Returns the ButtonHandle that was previously associated with the given index
- * number by a call to set_button_map(), or ButtonHandle::none() if no button
+ * number by a call to map_button(), or ButtonHandle::none() if no button
  * was associated.
  */
 INLINE ButtonHandle InputDevice::
@@ -230,9 +227,9 @@ get_button_map(size_t index) const {
  * currently known to be down, or false if it is up or unknown.
  */
 INLINE bool InputDevice::
-get_button_state(size_t index) const {
+is_button_pressed(size_t index) const {
   if (index < _buttons.size()) {
-    return (_buttons[index].state == S_down);
+    return (_buttons[index]._state == S_down);
   } else {
     return false;
   }
@@ -245,14 +242,14 @@ get_button_state(size_t index) const {
 INLINE bool InputDevice::
 is_button_known(size_t index) const {
   if (index < _buttons.size()) {
-    return _buttons[index].state != S_unknown;
+    return _buttons[index]._state != S_unknown;
   } else {
     return false;
   }
 }
 
 /**
- * Returns the ButtonState that is set at the given index, or throw an assection
+ * Returns the ButtonState that is set at the given index, or throw an assert
  * if the index was not found in the list.
  */
 INLINE InputDevice::ButtonState InputDevice::
@@ -261,13 +258,13 @@ get_button(size_t index) const {
     return _buttons[index];
   } else {
     device_cat.error()
-      << "Index " << index << " was not found in the controls list\n";
+      << "Index " << index << " was not found in the axes list\n";
     return ButtonState();
   }
 }
 
 /**
- * Returns the first ButtonState found with the given axis, or throw an assection
+ * Returns the first ButtonState found with the given axis, or throw an assert
  * if the button handle was not found in the list.
  */
 INLINE InputDevice::ButtonState InputDevice::
@@ -278,103 +275,89 @@ find_button(ButtonHandle handle) const {
     }
   }
   device_cat.error()
-    << "Handle " << handle.get_name() << " was not found in the controls list\n";
+    << "Handle " << handle.get_name() << " was not found in the axes list\n";
   return ButtonState();
 }
 
 /**
- * Returns the number of analog controls known to the InputDevice.  This number
- * may change as more controls are discovered.
+ * Returns the number of analog axes known to the InputDevice.  This number
+ * may change as more axes are discovered.
  */
 INLINE size_t InputDevice::
-get_num_controls() const {
-  return _controls.size();
+get_num_axes() const {
+  return _axes.size();
 }
 
 /**
- * Associates the indicated Axis with the control of the indicated index
+ * Associates the indicated Axis with the axis of the indicated index
  * number.  Pass Axis::none to turn off any association.
  *
  * It is not necessary to call this if you simply want to query the state of
- * the various controls by index number.
+ * the various axes by index number.
  */
 INLINE void InputDevice::
-set_control_map(size_t index, InputDevice::Axis axis) {
+map_axis(size_t index, InputDevice::Axis axis) {
   LightMutexHolder holder(_lock);
-  if (index >= _controls.size()) {
-    _controls.resize(index + 1, AnalogState());
+  if (index >= _axes.size()) {
+    _axes.resize(index + 1, AxisState());
   }
 
-  _controls[index].axis = axis;
+  _axes[index].axis = axis;
 }
 
 /**
- * Returns the Axis that was previously associated with the given index
- * number by a call to set_control_map(), or Axis::none if no control was
- * associated.
- */
-INLINE InputDevice::Axis InputDevice::
-get_control_map(size_t index) const {
-  if (index < _controls.size()) {
-    return _controls[index].axis;
-  } else {
-    return Axis::none;
-  }
-}
-
-/**
- * Returns the current position of indicated analog control (identified by its
- * index number), or 0.0 if the control is unknown.  The normal range of a
- * single control is -1.0 to 1.0.
+ * Returns the current position of indicated analog axis (identified by its
+ * index number), or 0.0 if the axis is unknown.  The normal range of a
+ * single axis is -1.0 to 1.0.
  */
 INLINE double InputDevice::
-get_control_state(size_t index) const {
-  if (index < _controls.size()) {
-    return _controls[index].state;
+get_axis_value(size_t index) const {
+  if (index < _axes.size()) {
+    return _axes[index].value;
   } else {
     return 0.0;
   }
 }
 
 /**
- * Returns the AnalogAxis that is set at the given index, or throw an assection
+ * Returns the axis state that is set at the given index, or throw an assert
  * if the index was not found in the list.
  */
-INLINE InputDevice::AnalogState InputDevice::
-get_control(size_t index) const {
-  if (index < _controls.size()) {
-    return _controls[index];
+INLINE InputDevice::AxisState InputDevice::
+get_axis(size_t index) const {
+  if (index < _axes.size()) {
+    return _axes[index];
   } else {
     device_cat.error()
-      << "Index " << index<< " was not found in the controls list\n";
-    return AnalogState();
+      << "Index " << index << " was not found in the axes list\n";
+    return AxisState();
   }
 }
 
 /**
- * Returns the first AnalogAxis found with the given axis, or throw an assection
+ * Returns the first AnalogAxis found with the given axis, or throw an assert
  * if the axis was not found in the list.
  */
-INLINE InputDevice::AnalogState InputDevice::
-find_control(InputDevice::Axis axis) const {
-  for (size_t i = 0; i < _controls.size(); ++i) {
-    if (_controls[i].axis == axis) {
-      return _controls[i];
+INLINE InputDevice::AxisState InputDevice::
+find_axis(InputDevice::Axis axis) const {
+  for (size_t i = 0; i < _axes.size(); ++i) {
+    if (_axes[i].axis == axis) {
+      return _axes[i];
     }
   }
   device_cat.error()
-    << "Axis " << axis << " was not found in the controls list\n";
-  return AnalogState();
+    << "Axis " << axis << " was not found in the axes list\n";
+  return AxisState();
 }
 
 /**
- * Returns true if the state of the indicated analog control is known, or false
- * if we have never heard anything about this particular control.
+ * Returns true if the state of the indicated analog axis is known, or false
+ * if we have never heard anything about this particular axis.
  */
 INLINE bool InputDevice::
-is_control_known(size_t index) const {
-  if (index < _controls.size()) {
-    return _controls[index].known;
+is_axis_known(size_t index) const {
+  if (index < _axes.size()) {
+    return _axes[index].known;
   } else {
     return false;
   }
@@ -382,8 +365,8 @@ is_control_known(size_t index) const {
 
 /**
  * Sets the strength of the vibration effect, if supported.  The values are
- * clamped to 0-1 range. The first value controls the low-frequency rumble
- * motor, whereas the second controls the high-frequency motor, if present.
+ * clamped to 0-1 range. The first value axes the low-frequency rumble
+ * motor, whereas the second axes the high-frequency motor, if present.
  */
 INLINE void InputDevice::
 set_vibration(double strong, double weak) {
@@ -423,33 +406,23 @@ set_connected(bool connected) {
 /**
  *
  */
-INLINE bool InputDevice::
-operator == (const InputDevice &) const {
-  return true;
-}
-
-/**
- *
- */
-INLINE bool InputDevice::
-operator != (const InputDevice &) const {
-  return false;
+INLINE InputDevice::ButtonState::
+ButtonState(ButtonHandle handle) :
+  handle(handle) {
 }
 
 /**
- *
+ * True if the button state is currently known.
  */
-INLINE bool InputDevice::
-operator < (const InputDevice &) const {
-  return false;
+ALWAYS_INLINE bool InputDevice::ButtonState::
+is_known() const {
+  return (_state != S_unknown);
 }
 
 /**
- *
+ * True if the button is currently known to be pressed.
  */
-INLINE InputDevice::ButtonState::
-ButtonState(ButtonHandle handle) :
-  handle(handle),
-  state(S_unknown)
-{
+ALWAYS_INLINE bool InputDevice::ButtonState::
+is_pressed() const {
+  return (_state == S_down);
 }

+ 68 - 61
panda/src/device/inputDevice.cxx

@@ -32,8 +32,6 @@ InputDevice(const std::string &name, DeviceClass dev_class, int flags) :
   _is_connected(true),
   _event_sequence(0),
   _enable_pointer_events(false),
-  _battery_level(-1),
-  _max_battery_level(-1),
   _lock("InputDevice")
 {
   _button_events = new ButtonEventList;
@@ -119,13 +117,22 @@ get_pointer_events() {
   return result;
 }
 
+/**
+ * Called by the implementation to add a new known button.
+ */
+int InputDevice::
+add_button(ButtonHandle button) {
+  int index = (int)_buttons.size();
+  _buttons.push_back(ButtonState(button));
+  return index;
+}
 
 /**
- * Called by the implementation to add a new known control.
+ * Called by the implementation to add a new known axis.
  */
 int InputDevice::
-add_control(Axis axis, int minimum, int maximum, bool centered) {
-  AnalogState state;
+add_axis(Axis axis, int minimum, int maximum, bool centered) {
+  AxisState state;
   state.axis = axis;
   if (centered) {
     // Centered, eg. for sticks.
@@ -136,17 +143,17 @@ add_control(Axis axis, int minimum, int maximum, bool centered) {
     state._scale = 1.0 / maximum;
     state._bias = 0.0;
   }
-  int index = (int)_controls.size();
-  _controls.push_back(state);
+  int index = (int)_axes.size();
+  _axes.push_back(state);
   return index;
 }
 
 /**
- * Called by the implementation to add a new known control.  This version
- * tries to guess whether the control is centered or not.
+ * Called by the implementation to add a new known axis.  This version tries
+ * to guess whether the axis is centered or not.
  */
 int InputDevice::
-add_control(Axis axis, int minimum, int maximum) {
+add_axis(Axis axis, int minimum, int maximum) {
   bool centered = (minimum < 0)
     || axis == Axis::x
     || axis == Axis::y
@@ -160,7 +167,7 @@ add_control(Axis axis, int minimum, int maximum) {
     || axis == Axis::right_y
     || axis == Axis::wheel
     || axis == Axis::rudder;
-  return add_control(axis, minimum, maximum, centered);
+  return add_axis(axis, minimum, maximum, centered);
 }
 
 /**
@@ -246,10 +253,10 @@ button_changed(int index, bool down) {
   }
 
   State new_state = down ? S_down : S_up;
-  if (_buttons[index].state == new_state) {
+  if (_buttons[index]._state == new_state) {
     return;
   }
-  _buttons[index].state = new_state;
+  _buttons[index]._state = new_state;
 
   ButtonHandle handle = _buttons[index].handle;
 
@@ -272,65 +279,67 @@ button_changed(int index, bool down) {
 /**
  * Sets the state of the indicated analog index.  The caller should ensure that
  * the lock is held while this call is made.  This should be a number in the
- * range -1.0 to 1.0, representing the current position of the control within
- * its total range of movement.
+ * range -1.0 to 1.0, representing the current position of the axis within its
+ * total range of movement.
  */
 void InputDevice::
-set_control_state(int index, double state) {
-  nassertv(_lock.debug_is_locked());
+set_axis_value(int index, double value) {
+  LightMutexHolder holder(_lock);
+
   nassertv(index >= 0);
-  if (index >= (int)_controls.size()) {
-    _controls.resize(index + 1, AnalogState());
+  if ((size_t)index >= _axes.size()) {
+    _axes.resize((size_t)index + 1u, AxisState());
   }
 
-  if (device_cat.is_spam() && _controls[index].state != state) {
+  if (device_cat.is_spam() && _axes[index].value != value) {
     device_cat.spam()
-      << "Changed control " << index;
+      << "Changed axis " << index;
 
-    if (_controls[index].axis != Axis::none) {
-      device_cat.spam(false) << " (" << _controls[index].axis << ")";
+    if (_axes[index].axis != Axis::none) {
+      device_cat.spam(false) << " (" << _axes[index].axis << ")";
     }
 
-    device_cat.spam(false) << " to " << state << "\n";
+    device_cat.spam(false) << " to " << value << "\n";
   }
 
-  _controls[index].state = state;
-  _controls[index].known = true;
+  _axes[index].value = value;
+  _axes[index].known = true;
 }
 
 /**
- * Like set_control_state, but instead passes a raw, unscaled value.
+ * Called by the implementation during do_poll to indicate that the indicated
+ * axis has received a new raw value.  Assumes the lock is held.
  */
 void InputDevice::
-control_changed(int index, int state) {
+axis_changed(int index, int state) {
   nassertv(_lock.debug_is_locked());
   nassertv(index >= 0);
-  if (index >= (int)_controls.size()) {
-    _controls.resize(index + 1, AnalogState());
+  if ((size_t)index >= _axes.size()) {
+    _axes.resize((size_t)index + 1u, AxisState());
   }
 
-  double new_state = fma((double)state, _controls[index]._scale, _controls[index]._bias);
+  double value = fma((double)state, _axes[index]._scale, _axes[index]._bias);
 
-  if (device_cat.is_spam() && _controls[index].state != new_state) {
+  if (device_cat.is_spam() && !IS_NEARLY_EQUAL(_axes[index].value, value)) {
     device_cat.spam()
-      << "Changed control " << index;
+      << "Changed axis " << index;
 
-    if (_controls[index].axis != Axis::none) {
-      device_cat.spam(false) << " (" << _controls[index].axis << ")";
+    if (_axes[index].axis != Axis::none) {
+      device_cat.spam(false) << " (" << _axes[index].axis << ")";
     }
 
-    device_cat.spam(false) << " to " << new_state << " (raw value " << state << ")\n";
+    device_cat.spam(false) << " to " << value << " (raw value " << state << ")\n";
   }
 
-  _controls[index].state = new_state;
-  _controls[index].known = true;
+  _axes[index].value = value;
+  _axes[index].known = true;
 }
 
 /**
  * Records that a tracker movement has taken place.
  */
 void InputDevice::
-set_tracker(const LPoint3 &pos, const LOrientation &orient, double time) {
+tracker_changed(const LPoint3 &pos, const LOrientation &orient, double time) {
   nassertv(_lock.debug_is_locked());
 
   _tracker_data.set_pos(pos);
@@ -364,11 +373,9 @@ output(std::ostream &out) const {
     }
   }
 
-  if (_controls.size() > 0) {
-    out << ", " << _controls.size() << " control";
-    if (_controls.size() != 1) {
-      out.put('s');
-    }
+  if (_axes.size() > 0) {
+    out << ", " << _axes.size() << " ax"
+        << (_axes.size() != 1 ? 'e' : 'i') << 's';
   }
 
   if (_flags & IDF_has_pointer) {
@@ -386,13 +393,13 @@ output(std::ostream &out) const {
   if (_flags & IDF_has_battery) {
     out << ", battery";
 
-    if (_battery_level > 0 && _max_battery_level > 0) {
+    if (_battery_data.level > 0 && _battery_data.max_level > 0) {
       out << " [";
       short i = 0;
-      for (; i < _battery_level; ++i) {
+      for (; i < _battery_data.level; ++i) {
         out << '=';
       }
-      for (; i < _max_battery_level; ++i) {
+      for (; i < _battery_data.max_level; ++i) {
         out << ' ';
       }
       out << ']';
@@ -411,13 +418,13 @@ output_buttons(std::ostream &out) const {
   Buttons::const_iterator bi;
   for (bi = _buttons.begin(); bi != _buttons.end(); ++bi) {
     const ButtonState &state = (*bi);
-    if (state.state != S_unknown) {
+    if (state.is_known()) {
       if (any_buttons) {
         out << ", ";
       }
       any_buttons = true;
       out << (int)(bi - _buttons.begin()) << "=";
-      if (state.state == S_up) {
+      if (state._state == S_up) {
         out << "up";
       } else {
         out << "down";
@@ -439,7 +446,7 @@ write_buttons(std::ostream &out, int indent_level) const {
   Buttons::const_iterator bi;
   for (bi = _buttons.begin(); bi != _buttons.end(); ++bi) {
     const ButtonState &state = (*bi);
-    if (state.state != S_unknown) {
+    if (state.is_known()) {
       any_buttons = true;
 
       indent(out, indent_level)
@@ -449,7 +456,7 @@ write_buttons(std::ostream &out, int indent_level) const {
         out << "(" << state.handle << ") ";
       }
 
-      if (state.state == S_up) {
+      if (state._state == S_up) {
         out << "up";
       } else {
         out << "down";
@@ -465,27 +472,27 @@ write_buttons(std::ostream &out, int indent_level) const {
 }
 
 /**
- * Writes a multi-line description of the current analog control states.
+ * Writes a multi-line description of the current analog axis states.
  */
 void InputDevice::
-write_controls(std::ostream &out, int indent_level) const {
+write_axes(std::ostream &out, int indent_level) const {
   LightMutexHolder holder(_lock);
 
-  bool any_controls = false;
-  Controls::const_iterator ai;
-  for (ai = _controls.begin(); ai != _controls.end(); ++ai) {
-    const AnalogState &state = (*ai);
+  bool any_axis = false;
+  Axes::const_iterator ai;
+  for (ai = _axes.begin(); ai != _axes.end(); ++ai) {
+    const AxisState &state = (*ai);
     if (state.known) {
-      any_controls = true;
+      any_axis = true;
 
       indent(out, indent_level)
-        << (int)(ai - _controls.begin()) << ". " << state.state << "\n";
+        << (int)(ai - _axes.begin()) << ". " << state.value << "\n";
     }
   }
 
-  if (!any_controls) {
+  if (!any_axis) {
     indent(out, indent_level)
-      << "(no known analog controls)\n";
+      << "(no known analog axes)\n";
   }
 }
 

+ 101 - 86
panda/src/device/inputDevice.h

@@ -33,12 +33,12 @@ typedef MouseData PointerData;
 
 /**
  * This is a structure representing a single input device.  Input devices may
- * have zero or more buttons, pointers, or controls associated with them, and
+ * have zero or more buttons, pointers, or axes associated with them, and
  * optionally a motion tracker.
  *
  * These devices are brought under a common interface because there is such a
  * large range of devices out there that may support any number of these types
- * of controls, we couldn't even begin to cover them with type-specific
+ * of axes, we couldn't even begin to cover them with type-specific
  * subclasses.
  *
  * Use the various has_() and get_num_() methods to determine information about
@@ -85,16 +85,6 @@ PUBLISHED:
     DC_COUNT,
   };
 
-protected:
-  InputDevice(const std::string &name, DeviceClass dev_class, int flags);
-
-public:
-  InputDevice();
-  InputDevice(const InputDevice &copy);
-  void operator = (const InputDevice &copy);
-  ~InputDevice();
-
-PUBLISHED:
   enum class Axis {
     none,
 
@@ -126,19 +116,94 @@ PUBLISHED:
     brake,
   };
 
+  enum State {
+    S_unknown,
+    S_up,
+    S_down
+  };
+
+  class ButtonState {
+  public:
+    constexpr ButtonState() = default;
+    INLINE ButtonState(ButtonHandle handle);
+    ALWAYS_INLINE bool is_known() const;
+    ALWAYS_INLINE bool is_pressed() const;
+
+  PUBLISHED:
+    MAKE_PROPERTY(known, is_known);
+    MAKE_PROPERTY(pressed, is_pressed);
+
+    ButtonHandle handle = ButtonHandle::none();
+
+  public:
+    State _state = S_unknown;
+  };
+
+  class AxisState {
+  public:
+    constexpr AxisState() = default;
+
+  PUBLISHED:
+    Axis axis = Axis::none;
+    double value = 0.0;
+    bool known = false;
+
+  public:
+    double _scale = 1.0;
+    double _bias = 0.0;
+  };
+
+  class BatteryData {
+  PUBLISHED:
+    // Ranges from 0 through max_level.
+    short level = -1;
+
+    // Maximum value of 'level' field.
+    short max_level = -1;
+  };
+
+protected:
+  InputDevice(const std::string &name, DeviceClass dev_class, int flags);
+
+public:
+  InputDevice();
+  InputDevice(const InputDevice &copy);
+  void operator = (const InputDevice &copy);
+  ~InputDevice();
+
   INLINE std::string get_name() const;
   INLINE std::string get_manufacturer() const;
+  INLINE std::string get_serial_number() const;
   INLINE unsigned short get_vendor_id() const;
   INLINE unsigned short get_product_id() const;
   INLINE bool is_connected() const;
   INLINE DeviceClass get_device_class() const;
 
+  INLINE PointerData get_pointer() const;
+  INLINE TrackerData get_tracker() const;
+  INLINE BatteryData get_battery() const;
+
+  INLINE size_t get_num_buttons() const;
+  INLINE ButtonHandle get_button_map(size_t index) const;
+  INLINE bool is_button_pressed(size_t index) const;
+  INLINE bool is_button_known(size_t index) const;
+  INLINE ButtonState get_button(size_t index) const;
+
+  INLINE size_t get_num_axes() const;
+  INLINE double get_axis_value(size_t index) const;
+  INLINE bool is_axis_known(size_t index) const;
+  INLINE AxisState get_axis(size_t index) const;
+
+PUBLISHED:
   // The human-readable name of this input device.
   MAKE_PROPERTY(name, get_name);
 
   // The device's manufacturer, or the empty string if not known.
   MAKE_PROPERTY(manufacturer, get_manufacturer);
 
+  // The device's serial number, or the empty string if not known.
+  MAKE_PROPERTY(serial_number, get_serial_number);
+
   // USB vendor ID of the device, or 0 if not known.
   MAKE_PROPERTY(vendor_id, get_vendor_id);
 
@@ -159,24 +224,22 @@ PUBLISHED:
   INLINE bool has_vibration() const;
   INLINE bool has_battery() const;
 
-  INLINE PointerData get_pointer() const;
-  INLINE TrackerData get_tracker() const;
-
-  INLINE short get_battery_level() const;
-  INLINE short get_max_battery_level() const;
+  // Getters for the various types of device data.
+  MAKE_PROPERTY2(pointer, has_pointer, get_pointer);
+  MAKE_PROPERTY2(tracker, has_tracker, get_tracker);
+  MAKE_PROPERTY2(battery, has_battery, get_battery);
 
-  INLINE size_t get_num_buttons() const;
-  INLINE void set_button_map(size_t index, ButtonHandle button);
-  INLINE ButtonHandle get_button_map(size_t index) const;
-  INLINE bool get_button_state(size_t index) const;
-  INLINE bool is_button_known(size_t index) const;
+  // Make device buttons and axes iterable
+  MAKE_SEQ_PROPERTY(buttons, get_num_buttons, get_button);
+  MAKE_SEQ_PROPERTY(axes, get_num_axes, get_axis);
 
-  INLINE size_t get_num_controls() const;
-  INLINE void set_control_map(size_t index, Axis axis);
-  INLINE Axis get_control_map(size_t index) const;
-  INLINE double get_control_state(size_t index) const;
-  INLINE bool is_control_known(size_t index) const;
+  // Associate buttons/axes with symbolic handles.
+  INLINE void map_button(size_t index, ButtonHandle handle);
+  INLINE void map_axis(size_t index, Axis axis);
+  INLINE ButtonState find_button(ButtonHandle handle) const;
+  INLINE AxisState find_axis(Axis axis) const;
 
+  // Enable rumble force-feedback effects
   INLINE void set_vibration(double strong, double weak);
 
   INLINE void enable_pointer_events();
@@ -194,19 +257,20 @@ PUBLISHED:
   static std::string format_axis(Axis axis);
 
 protected:
-  // Called during the constructor to add new controls or buttons
-  int add_control(Axis axis, int minimum, int maximum, bool centered);
-  int add_control(Axis axis, int minimum, int maximum);
+  // Called during the constructor to add new axes or buttons
+  int add_button(ButtonHandle handle);
+  int add_axis(Axis axis, int minimum, int maximum, bool centered);
+  int add_axis(Axis axis, int minimum, int maximum);
 
   void set_pointer(bool inwin, double x, double y, double time);
   void set_pointer_out_of_window(double time);
 
   void pointer_moved(double x, double y, double time);
   void button_changed(int index, bool down);
-  void control_changed(int index, int value);
-  void set_control_state(int index, double state);
+  void axis_changed(int index, int value);
+  void set_axis_value(int index, double state);
 
-  void set_tracker(const LPoint3 &pos, const LOrientation &orient, double time);
+  void tracker_changed(const LPoint3 &pos, const LOrientation &orient, double time);
 
   virtual void do_set_vibration(double low, double high);
   virtual void do_poll();
@@ -214,16 +278,9 @@ protected:
 public:
   INLINE void set_connected(bool connected);
 
-  // We need these methods to make VC++ happy when we try to
-  // instantiate a pvector<InputDevice>.  They don't do
-  // anything useful.
-  INLINE bool operator == (const InputDevice &other) const;
-  INLINE bool operator != (const InputDevice &other) const;
-  INLINE bool operator < (const InputDevice &other) const;
-
   void output_buttons(std::ostream &out) const;
   void write_buttons(std::ostream &out, int indent_level) const;
-  void write_controls(std::ostream &out, int indent_level) const;
+  void write_axes(std::ostream &out, int indent_level) const;
 
 protected:
   enum InputDeviceFlags {
@@ -263,56 +320,14 @@ protected:
   PT(PointerEventList) _pointer_events;
 
 PUBLISHED:
-  enum State {
-    S_unknown,
-    S_up,
-    S_down
-  };
-
-  class ButtonState {
-  public:
-    constexpr ButtonState() = default;
-    INLINE ButtonState(ButtonHandle handle);
-
-  PUBLISHED:
-    ButtonHandle handle = ButtonHandle::none();
-    State state = S_unknown;
-  };
   typedef pvector<ButtonState> Buttons;
+  typedef pvector<AxisState> Axes;
   Buttons _buttons;
+  Axes _axes;
 
-  class AnalogState {
-  public:
-    constexpr AnalogState() = default;
-
-  PUBLISHED:
-    Axis axis = Axis::none;
-    double state = 0.0;
-    bool known = false;
-
-  public:
-    double _scale = 1.0;
-    double _bias = 0.0;
-  };
-  typedef pvector<AnalogState> Controls;
-  Controls _controls;
-
-  short _battery_level;
-  short _max_battery_level;
-
+  BatteryData _battery_data;
   TrackerData _tracker_data;
 
-
-  INLINE ButtonState get_button(size_t index) const;
-  INLINE ButtonState find_button(ButtonHandle handle) const;
-
-  INLINE AnalogState get_control(size_t index) const;
-  INLINE AnalogState find_control(Axis axis) const;
-
-  // Make device buttons and controls iterable
-  MAKE_SEQ_PROPERTY(buttons, get_num_buttons, get_button);
-  MAKE_SEQ_PROPERTY(controls, get_num_controls, get_control);
-
 public:
   static TypeHandle get_class_type() {
     return _type_handle;

+ 0 - 3
panda/src/device/inputDeviceManager.h

@@ -46,9 +46,6 @@ PUBLISHED:
 
   INLINE static InputDeviceManager *get_global_ptr();
 
-  // The set of all currently connected devices.
-  MAKE_PROPERTY(devices, get_devices);
-
 protected:
   LightMutex _lock;
 

+ 18 - 0
panda/src/device/inputDeviceNode.cxx

@@ -54,9 +54,27 @@ get_device() const {
 void InputDeviceNode::
 do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &,
                  DataNodeTransmit &output) {
+
+  if (_device == nullptr && !_device->is_connected()) {
+    return;
+  }
+
+  _device->poll();
+
   // get all button events of the device and forward them to the data graph
   if (_device->has_button_event()) {
     PT(ButtonEventList) bel = _device->get_button_events();
+
+    // Register the current state for each button.
+    for (int i = 0; i < bel->get_num_events(); ++i) {
+      const ButtonEvent &event = bel->get_event(i);
+      if (event._type == ButtonEvent::T_down) {
+        _button_states[event._button] = true;
+      } else if (event._type == ButtonEvent::T_down) {
+        _button_states[event._button] = false;
+      }
+    }
+
     output.set_data(_button_events_output, EventParameter(bel));
   }
 

+ 11 - 3
panda/src/device/inputDeviceNode.h

@@ -21,17 +21,22 @@
 #include "linmath_events.h"
 
 /**
- * Reads the controler data sent from the InputDeviceManager, and
- * transmits it down the data graph.
- *
+ * Reads the controller data sent from the InputDeviceManager, and transmits
+ * it down the data graph.
  *
+ * This is intended to only be accessed from the app thread.
  */
 class EXPCL_PANDA_DEVICE InputDeviceNode : public DataNode {
 PUBLISHED:
   InputDeviceNode(InputDevice *device, const std::string &name);
+
+public:
   void set_device(InputDevice *device);
   PT(InputDevice) get_device() const;
 
+PUBLISHED:
+  MAKE_PROPERTY(device, get_device, set_device);
+
 protected:
   // Inherited from DataNode
   virtual void do_transmit_data(DataGraphTraverser *trav,
@@ -39,6 +44,9 @@ protected:
                                 DataNodeTransmit &output);
 
 private:
+  pmap<ButtonHandle, bool> _button_states;
+  pmap<InputDevice::Axis, double> _control_states;
+
   // outputs
   int _button_events_output;
   int _low_battery_event_output;

+ 4 - 4
panda/src/device/ioKitInputDevice.cxx

@@ -287,14 +287,14 @@ parse_element(IOHIDElementRef element) {
       int max = IOHIDElementGetLogicalMax(element);
       if (_vendor_id == 0x044f && _product_id == 0xb108 && axis == Axis::throttle) {
         // T.Flight Hotas X throttle is reversed and can go backwards.
-        add_control(axis, max, min, true);
+        add_axis(axis, max, min, true);
       } else if (axis == Axis::yaw || axis == Axis::rudder || axis == Axis::left_y || axis == Axis::right_y ||
                  (_device_class == DC_3d_mouse && (axis == Axis::y || axis == Axis::z || axis == Axis::roll))) {
         // We'd like to reverse the Y axis to match the XInput behavior.
         // We also reverse yaw to obey the right-hand rule.
-        add_control(axis, max, min);
+        add_axis(axis, max, min);
       } else {
-        add_control(axis, min, max);
+        add_axis(axis, min, max);
       }
 
       _analog_elements.push_back(element);
@@ -734,7 +734,7 @@ do_poll() {
     IOHIDValueRef value_ref;
     if (IOHIDDeviceGetValue(_device, _analog_elements[i], &value_ref) == kIOReturnSuccess) {
       int value = IOHIDValueGetIntegerValue(value_ref);
-      control_changed(i, value);
+      axis_changed(i, value);
     }
   }
 

+ 24 - 24
panda/src/device/linuxJoystickDevice.cxx

@@ -121,7 +121,7 @@ open_device() {
   ioctl(_fd, JSIOCGBUTTONS, &num_buttons);
 
   _buttons.resize(num_buttons);
-  _controls.resize(num_axes);
+  _axes.resize(num_axes);
 
   if (num_buttons > 0) {
     uint16_t btnmap[512];
@@ -225,11 +225,11 @@ open_device() {
           _dpad_x_axis = i;
           _dpad_left_button = (int)_buttons.size();
           if (_device_class == DC_gamepad) {
-            _buttons.push_back(ButtonState(GamepadButton::dpad_left()));
-            _buttons.push_back(ButtonState(GamepadButton::dpad_right()));
+            add_button(GamepadButton::dpad_left());
+            add_button(GamepadButton::dpad_right());
           } else {
-            _buttons.push_back(ButtonState(GamepadButton::hat_left()));
-            _buttons.push_back(ButtonState(GamepadButton::hat_right()));
+            add_button(GamepadButton::hat_left());
+            add_button(GamepadButton::hat_right());
           }
           axis = Axis::none;
         }
@@ -241,11 +241,11 @@ open_device() {
           _dpad_y_axis = i;
           _dpad_up_button = (int)_buttons.size();
           if (_device_class == DC_gamepad) {
-            _buttons.push_back(ButtonState(GamepadButton::dpad_up()));
-            _buttons.push_back(ButtonState(GamepadButton::dpad_down()));
+            add_button(GamepadButton::dpad_up());
+            add_button(GamepadButton::dpad_down());
           } else {
-            _buttons.push_back(ButtonState(GamepadButton::hat_up()));
-            _buttons.push_back(ButtonState(GamepadButton::hat_down()));
+            add_button(GamepadButton::hat_up());
+            add_button(GamepadButton::hat_down());
           }
           axis = Axis::none;
         }
@@ -259,28 +259,28 @@ open_device() {
         axis = Axis::none;
         break;
       }
-      _controls[i].axis = axis;
+      _axes[i].axis = axis;
 
       if (axis == Axis::left_trigger || axis == Axis::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;
+        _axes[i]._scale = 1.0 / 65534.0;
+        _axes[i]._bias = 0.5;
         have_analog_triggers = true;
       } else if (axis == Axis::left_y || axis == Axis::right_y || axis == Axis::y) {
-        _controls[i]._scale = 1.0 / -32767.0;
-        _controls[i]._bias = 0.0;
+        _axes[i]._scale = 1.0 / -32767.0;
+        _axes[i]._bias = 0.0;
       } else {
-        _controls[i]._scale = 1.0 / 32767.0;
-        _controls[i]._bias = 0.0;
+        _axes[i]._scale = 1.0 / 32767.0;
+        _axes[i]._bias = 0.0;
       }
     }
   }
 
   if (_ltrigger_button >= 0 && _rtrigger_button >= 0 && !have_analog_triggers) {
     // Emulate analog triggers.
-    _ltrigger_control = (int)_controls.size();
-    add_control(Axis::left_trigger, 0, 1, false);
-    add_control(Axis::right_trigger, 0, 1, false);
+    _ltrigger_control = (int)_axes.size();
+    add_axis(Axis::left_trigger, 0, 1, false);
+    add_axis(Axis::right_trigger, 0, 1, false);
   } else {
     _ltrigger_button = -1;
     _rtrigger_button = -1;
@@ -343,8 +343,8 @@ open_device() {
   // are all 0, which indicates that the driver hasn't received any data for
   // this gamepad yet (which means it hasn't been plugged in for this session)
   if (strncmp(name, "Xbox 360 Wireless Receiver", 26) == 0) {
-    for (const auto &control : _controls) {
-      if (control.state != 0.0) {
+    for (const auto &control : _axes) {
+      if (control.value != 0.0) {
         _is_connected = true;
         return true;
       }
@@ -398,9 +398,9 @@ process_events() {
 
     if (events[i].type & JS_EVENT_BUTTON) {
       if (index == _ltrigger_button) {
-        control_changed(_ltrigger_control, events[i].value);
+        axis_changed(_ltrigger_control, events[i].value);
       } else if (index == _rtrigger_button) {
-        control_changed(_ltrigger_control + 1, events[i].value);
+        axis_changed(_ltrigger_control + 1, events[i].value);
       }
       button_changed(index, (events[i].value != 0));
 
@@ -413,7 +413,7 @@ process_events() {
         button_changed(_dpad_up_button+1, events[i].value > 1000);
       }
 
-      control_changed(index, events[i].value);
+      axis_changed(index, events[i].value);
     }
   }
 

+ 10 - 10
panda/src/device/winRawInputDevice.cxx

@@ -362,11 +362,11 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) {
     gamepad_buttons = gamepad_buttons_snes;
   }
 
-  // Prepare a mapping of data indices to button/control indices.
+  // Prepare a mapping of data indices to button/axis indices.
   _indices.resize(caps.NumberInputDataIndices);
 
   _buttons.clear();
-  _controls.clear();
+  _axes.clear();
 
   USHORT num_button_caps = caps.NumberInputButtonCaps;
   PHIDP_BUTTON_CAPS button_caps = (PHIDP_BUTTON_CAPS)alloca(num_button_caps * sizeof(HIDP_BUTTON_CAPS));
@@ -553,17 +553,17 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) {
         break;
       }
 
-      int control_index;
+      int axis_index;
       if (_vendor_id == 0x044f && _product_id == 0xb108 && axis == Axis::throttle) {
         // T.Flight Hotas X throttle is reversed and can go backwards.
-        control_index = add_control(axis, cap.LogicalMax, cap.LogicalMin, true);
+        axis_index = add_axis(axis, cap.LogicalMax, cap.LogicalMin, true);
       } else if (!is_signed) {
         // All axes on the weird XInput-style mappings go from -1 to 1
-        control_index = add_control(axis, cap.LogicalMin, cap.LogicalMax, true);
+        axis_index = add_axis(axis, cap.LogicalMin, cap.LogicalMax, true);
       } else {
-        control_index = add_control(axis, cap.LogicalMin, cap.LogicalMax);
+        axis_index = add_axis(axis, cap.LogicalMin, cap.LogicalMax);
       }
-      _indices[data_index] = Index::control(control_index, is_signed);
+      _indices[data_index] = Index::axis(axis_index, is_signed);
     }
   }
 
@@ -635,11 +635,11 @@ on_input(PRAWINPUT input) {
       for (ULONG di = 0; di < count; ++di) {
         if (data[di].DataIndex != _hat_data_index) {
           const Index &idx = _indices[data[di].DataIndex];
-          if (idx._control >= 0) {
+          if (idx._axis >= 0) {
             if (idx._signed) {
-              control_changed(idx._control, (SHORT)data[di].RawValue);
+              axis_changed(idx._axis, (SHORT)data[di].RawValue);
             } else {
-              control_changed(idx._control, data[di].RawValue);
+              axis_changed(idx._axis, data[di].RawValue);
             }
           }
           if (idx._button >= 0) {

+ 6 - 6
panda/src/device/winRawInputDevice.h

@@ -49,28 +49,28 @@ private:
   // Indexed by report ID
   pvector<BitArray> _report_buttons;
 
-  // Either a button index or a control index.
+  // Either a button index or a axis index.
   struct Index {
-    Index() : _button(-1), _control(-1) {}
+    Index() : _button(-1), _axis(-1) {}
 
     static Index button(int index) {
       Index idx;
       idx._button = index;
       return idx;
     }
-    static Index control(int index, bool is_signed=true) {
+    static Index axis(int index, bool is_signed=true) {
       Index idx;
-      idx._control = index;
+      idx._axis = index;
       idx._signed = is_signed;
       return idx;
     }
 
     int _button;
-    int _control;
+    int _axis;
     bool _signed;
   };
 
-  // Maps a "data index" to either button index or control index.
+  // Maps a "data index" to either button index or axis index.
   pvector<Index> _indices;
   int _hat_data_index;
   int _hat_data_minimum;

+ 72 - 71
panda/src/device/xInputDevice.cxx

@@ -126,7 +126,7 @@ XInputDevice(DWORD user_index) :
 
   nassertv(user_index >= 0 && user_index < XUSER_MAX_COUNT);
 
-  _controls.resize(6);
+  _axes.resize(6);
   _buttons.resize(16);
 }
 
@@ -301,6 +301,7 @@ init_xinput() {
 
 /**
  * Initializes the device.  Called when the device was just connected.
+ * Assumes either the lock is held or this is called from the constructor.
  */
 void XInputDevice::
 init_device(const XINPUT_CAPABILITIES_EX &caps, const XINPUT_STATE &state) {
@@ -315,81 +316,81 @@ init_device(const XINPUT_CAPABILITIES_EX &caps, const XINPUT_STATE &state) {
   default:
   case XINPUT_DEVSUBTYPE_GAMEPAD:
     _device_class = DC_gamepad;
-    set_control_map(0, Axis::left_trigger);
-    set_control_map(1, Axis::right_trigger);
-    set_control_map(2, Axis::left_x);
-    set_control_map(3, Axis::left_y);
-    set_control_map(4, Axis::right_x);
-    set_control_map(5, Axis::right_y);
+    _axes[0].axis = Axis::left_trigger;
+    _axes[1].axis = Axis::right_trigger;
+    _axes[2].axis = Axis::left_x;
+    _axes[3].axis = Axis::left_y;
+    _axes[4].axis = Axis::right_x;
+    _axes[5].axis = Axis::right_y;
     break;
 
   case XINPUT_DEVSUBTYPE_WHEEL:
     _device_class = DC_steering_wheel;
-    set_control_map(0, Axis::brake);
-    set_control_map(1, Axis::accelerator);
-    set_control_map(2, Axis::wheel);
-    set_control_map(3, Axis::none);
-    set_control_map(4, Axis::none);
-    set_control_map(5, Axis::none);
+    _axes[0].axis = Axis::brake;
+    _axes[1].axis = Axis::accelerator;
+    _axes[2].axis = Axis::wheel;
+    _axes[3].axis = Axis::none;
+    _axes[4].axis = Axis::none;
+    _axes[5].axis = Axis::none;
     break;
 
   case XINPUT_DEVSUBTYPE_FLIGHT_STICK:
     _device_class = DC_flight_stick;
-    set_control_map(0, Axis::yaw);
-    set_control_map(1, Axis::throttle);
-    set_control_map(2, Axis::roll);
-    set_control_map(3, Axis::pitch);
-    set_control_map(4, Axis::none);
-    set_control_map(5, Axis::none);
+    _axes[0].axis = Axis::yaw;
+    _axes[1].axis = Axis::throttle;
+    _axes[2].axis = Axis::roll;
+    _axes[3].axis = Axis::pitch;
+    _axes[4].axis = Axis::none;
+    _axes[5].axis = Axis::none;
     break;
 
   case XINPUT_DEVSUBTYPE_DANCE_PAD:
     _device_class = DC_dance_pad;
-    set_control_map(0, Axis::none);
-    set_control_map(1, Axis::none);
-    set_control_map(2, Axis::none);
-    set_control_map(3, Axis::none);
-    set_control_map(4, Axis::none);
-    set_control_map(5, Axis::none);
+    _axes[0].axis = Axis::none;
+    _axes[1].axis = Axis::none;
+    _axes[2].axis = Axis::none;
+    _axes[3].axis = Axis::none;
+    _axes[4].axis = Axis::none;
+    _axes[5].axis = Axis::none;
     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;
+  _axes[0]._scale = 1.0 / 255.0;
+  _axes[1]._scale = 1.0 / 255.0;
+  _axes[2]._scale = 1.0 / 32767.5;
+  _axes[3]._scale = 1.0 / 32767.5;
+  _axes[4]._scale = 1.0 / 32767.5;
+  _axes[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;
+  _axes[2]._bias = 0.5 / 32767.5;
+  _axes[3]._bias = 0.5 / 32767.5;
+  _axes[4]._bias = 0.5 / 32767.5;
+  _axes[5]._bias = 0.5 / 32767.5;
 
   if (caps.Flags & XINPUT_CAPS_NO_NAVIGATION) {
-    set_button_map(0, ButtonHandle::none());
-    set_button_map(1, ButtonHandle::none());
-    set_button_map(2, ButtonHandle::none());
-    set_button_map(3, ButtonHandle::none());
-    set_button_map(4, ButtonHandle::none());
-    set_button_map(5, ButtonHandle::none());
+    _buttons[0].handle = ButtonHandle::none();
+    _buttons[1].handle = ButtonHandle::none();
+    _buttons[2].handle = ButtonHandle::none();
+    _buttons[3].handle = ButtonHandle::none();
+    _buttons[4].handle = ButtonHandle::none();
+    _buttons[5].handle = ButtonHandle::none();
   } else {
-    set_button_map(0, GamepadButton::dpad_up());
-    set_button_map(1, GamepadButton::dpad_down());
-    set_button_map(2, GamepadButton::dpad_left());
-    set_button_map(3, GamepadButton::dpad_right());
-    set_button_map(4, GamepadButton::start());
-    set_button_map(5, GamepadButton::back());
+    _buttons[0].handle = GamepadButton::dpad_up();
+    _buttons[1].handle = GamepadButton::dpad_down();
+    _buttons[2].handle = GamepadButton::dpad_left();
+    _buttons[3].handle = GamepadButton::dpad_right();
+    _buttons[4].handle = GamepadButton::start();
+    _buttons[5].handle = GamepadButton::back();
   }
-  set_button_map(6, GamepadButton::lstick());
-  set_button_map(7, GamepadButton::rstick());
-  set_button_map(8, GamepadButton::lshoulder());
-  set_button_map(9, GamepadButton::rshoulder());
-  set_button_map(10, GamepadButton::guide());
-  set_button_map(11, GamepadButton::face_a());
-  set_button_map(12, GamepadButton::face_b());
-  set_button_map(13, GamepadButton::face_x());
-  set_button_map(14, GamepadButton::face_y());
+  _buttons[6].handle = GamepadButton::lstick();
+  _buttons[7].handle = GamepadButton::rstick();
+  _buttons[8].handle = GamepadButton::lshoulder();
+  _buttons[9].handle = GamepadButton::rshoulder();
+  _buttons[10].handle = GamepadButton::guide();
+  _buttons[11].handle = GamepadButton::face_a();
+  _buttons[12].handle = GamepadButton::face_b();
+  _buttons[13].handle = GamepadButton::face_x();
+  _buttons[14].handle = GamepadButton::face_y();
 
   if (caps.Vibration.wLeftMotorSpeed != 0 ||
       caps.Vibration.wRightMotorSpeed != 0) {
@@ -403,8 +404,8 @@ init_device(const XINPUT_CAPABILITIES_EX &caps, const XINPUT_STATE &state) {
           batt.BatteryType != BATTERY_TYPE_WIRED) {
         // This device has a battery.  Report the battery level.
         _flags |= IDF_has_battery;
-        _battery_level = batt.BatteryLevel;
-        _max_battery_level = BATTERY_LEVEL_FULL;
+        _battery_data.level = batt.BatteryLevel;
+        _battery_data.max_level = BATTERY_LEVEL_FULL;
       }
     }
   }
@@ -413,7 +414,7 @@ init_device(const XINPUT_CAPABILITIES_EX &caps, const XINPUT_STATE &state) {
   WORD mask = 1;
   for (int i = 0; i < 16; ++i) {
     // Set the state without triggering a button event.
-    _buttons[i].state = (buttons & mask) ? S_down : S_up;
+    _buttons[i]._state = (buttons & mask) ? S_down : S_up;
     mask <<= 1;
     if (i == 10) {
       // XInput skips 0x0800.
@@ -421,12 +422,12 @@ init_device(const XINPUT_CAPABILITIES_EX &caps, const XINPUT_STATE &state) {
     }
   }
 
-  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);
+  axis_changed(0, state.Gamepad.bLeftTrigger);
+  axis_changed(1, state.Gamepad.bRightTrigger);
+  axis_changed(2, state.Gamepad.sThumbLX);
+  axis_changed(3, state.Gamepad.sThumbLY);
+  axis_changed(4, state.Gamepad.sThumbRX);
+  axis_changed(5, state.Gamepad.sThumbRY);
 
   _last_buttons = buttons;
   _last_packet = state.dwPacketNumber;
@@ -491,12 +492,12 @@ do_poll() {
     }
   }
 
-  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);
+  axis_changed(0, state.Gamepad.bLeftTrigger);
+  axis_changed(1, state.Gamepad.bRightTrigger);
+  axis_changed(2, state.Gamepad.sThumbLX);
+  axis_changed(3, state.Gamepad.sThumbLY);
+  axis_changed(4, state.Gamepad.sThumbRX);
+  axis_changed(5, state.Gamepad.sThumbRY);
 
   _last_buttons = state.Gamepad.wButtons;
   _last_packet = state.dwPacketNumber;

+ 1 - 7
panda/src/vrpn/vrpnAnalog.cxx

@@ -100,13 +100,7 @@ vrpn_analog_callback(void *userdata, const vrpn_ANALOGCB info) {
   for (di = self->_devices.begin(); di != self->_devices.end(); ++di) {
     VrpnAnalogDevice *device = (*di);
     for (int i = 0; i < info.num_channel; i++) {
-      if (vrpn_cat.is_debug()) {
-        if (device->get_control_state(i) != info.channel[i]) {
-          vrpn_cat.debug()
-            << *self << " got analog " << i << " = " << info.channel[i] << "\n";
-        }
-      }
-      device->set_control_state(i, info.channel[i]);
+      device->set_axis_value(i, info.channel[i]);
     }
   }
 }

+ 12 - 12
panda/src/vrpn/vrpnTracker.cxx

@@ -107,10 +107,10 @@ vrpn_position_callback(void *userdata, const vrpn_TRACKERCB info) {
     VrpnTrackerDevice *device = (*di);
     if (device->get_sensor() == info.sensor &&
         device->get_data_type() == VrpnTrackerDevice::DT_position) {
-      device->set_tracker(LPoint3(info.pos[0], info.pos[1], info.pos[2]),
-                          LOrientation(info.quat[3], info.quat[0],
-                                       info.quat[1], info.quat[2]),
-                          VrpnClient::convert_to_secs(info.msg_time));
+      device->tracker_changed(LPoint3(info.pos[0], info.pos[1], info.pos[2]),
+                              LOrientation(info.quat[3], info.quat[0],
+                                           info.quat[1], info.quat[2]),
+                              VrpnClient::convert_to_secs(info.msg_time));
     }
   }
 }
@@ -132,10 +132,10 @@ vrpn_velocity_callback(void *userdata, const vrpn_TRACKERVELCB info) {
     VrpnTrackerDevice *device = (*di);
     if (device->get_sensor() == info.sensor &&
         device->get_data_type() == VrpnTrackerDevice::DT_velocity) {
-      device->set_tracker(LPoint3(info.vel[0], info.vel[1], info.vel[2]),
-                          LOrientation(info.vel_quat[3], info.vel_quat[0],
-                                       info.vel_quat[1], info.vel_quat[2]),
-                          VrpnClient::convert_to_secs(info.msg_time));
+      device->tracker_changed(LPoint3(info.vel[0], info.vel[1], info.vel[2]),
+                              LOrientation(info.vel_quat[3], info.vel_quat[0],
+                                           info.vel_quat[1], info.vel_quat[2]),
+                              VrpnClient::convert_to_secs(info.msg_time));
     }
   }
 }
@@ -157,10 +157,10 @@ vrpn_acceleration_callback(void *userdata, const vrpn_TRACKERACCCB info) {
     VrpnTrackerDevice *device = (*di);
     if (device->get_sensor() == info.sensor &&
         device->get_data_type() == VrpnTrackerDevice::DT_acceleration) {
-      device->set_tracker(LPoint3(info.acc[0], info.acc[1], info.acc[2]),
-                          LOrientation(info.acc_quat[3], info.acc_quat[0],
-                                       info.acc_quat[1], info.acc_quat[2]),
-                          VrpnClient::convert_to_secs(info.msg_time));
+      device->tracker_changed(LPoint3(info.acc[0], info.acc[1], info.acc[2]),
+                              LOrientation(info.acc_quat[3], info.acc_quat[0],
+                                           info.acc_quat[1], info.acc_quat[2]),
+                              VrpnClient::convert_to_secs(info.msg_time));
     }
   }
 }