Ver código fonte

Generalised input framework for raw mice, gamepads, trackers (incl. HMDs like Oculus Rift)

rdb 10 anos atrás
pai
commit
bd0683d101
64 arquivos alterados com 2970 adições e 1619 exclusões
  1. 15 15
      makepanda/makepanda.py
  2. 3 12
      panda/src/device/analogNode.I
  3. 18 7
      panda/src/device/analogNode.cxx
  4. 2 1
      panda/src/device/analogNode.h
  5. 6 20
      panda/src/device/buttonNode.I
  6. 22 20
      panda/src/device/buttonNode.cxx
  7. 2 4
      panda/src/device/buttonNode.h
  8. 0 74
      panda/src/device/clientAnalogDevice.I
  9. 1 46
      panda/src/device/clientAnalogDevice.cxx
  10. 0 23
      panda/src/device/clientAnalogDevice.h
  11. 0 1
      panda/src/device/clientBase.cxx
  12. 0 110
      panda/src/device/clientButtonDevice.I
  13. 2 111
      panda/src/device/clientButtonDevice.cxx
  14. 0 38
      panda/src/device/clientButtonDevice.h
  15. 0 53
      panda/src/device/clientDevice.I
  16. 11 14
      panda/src/device/clientDevice.cxx
  17. 6 21
      panda/src/device/clientDevice.h
  18. 1 13
      panda/src/device/clientTrackerDevice.I
  19. 0 6
      panda/src/device/clientTrackerDevice.h
  20. 9 2
      panda/src/device/config_device.cxx
  21. 3 12
      panda/src/device/dialNode.I
  22. 14 0
      panda/src/device/evdevInputDevice.I
  23. 424 0
      panda/src/device/evdevInputDevice.cxx
  24. 63 0
      panda/src/device/evdevInputDevice.h
  25. 445 0
      panda/src/device/inputDevice.I
  26. 517 0
      panda/src/device/inputDevice.cxx
  27. 279 0
      panda/src/device/inputDevice.h
  28. 27 0
      panda/src/device/inputDeviceManager.I
  29. 240 0
      panda/src/device/inputDeviceManager.cxx
  30. 64 0
      panda/src/device/inputDeviceManager.h
  31. 14 0
      panda/src/device/linuxJoystickDevice.I
  32. 313 0
      panda/src/device/linuxJoystickDevice.cxx
  33. 60 0
      panda/src/device/linuxJoystickDevice.h
  34. 4 1
      panda/src/device/p3device_composite1.cxx
  35. 0 1
      panda/src/device/p3device_composite2.cxx
  36. 1 2
      panda/src/device/trackerNode.I
  37. 9 10
      panda/src/device/trackerNode.cxx
  38. 8 8
      panda/src/device/trackerNode.h
  39. 1 19
      panda/src/display/callbackGraphicsWindow.cxx
  40. 0 1
      panda/src/display/callbackGraphicsWindow.h
  41. 5 1
      panda/src/display/config_display.cxx
  42. 30 87
      panda/src/display/graphicsWindow.cxx
  43. 7 11
      panda/src/display/graphicsWindow.h
  44. 6 226
      panda/src/display/graphicsWindowInputDevice.I
  45. 21 196
      panda/src/display/graphicsWindowInputDevice.cxx
  46. 38 98
      panda/src/display/graphicsWindowInputDevice.h
  47. 13 16
      panda/src/display/mouseAndKeyboard.cxx
  48. 1 2
      panda/src/display/mouseAndKeyboard.h
  49. 1 0
      panda/src/display/p3display_composite2.cxx
  50. 2 0
      panda/src/putil/config_util.cxx
  51. 75 0
      panda/src/putil/gamepadButton.cxx
  52. 57 0
      panda/src/putil/gamepadButton.h
  53. 0 1
      panda/src/putil/p3putil_composite1.cxx
  54. 2 0
      panda/src/putil/p3putil_composite2.cxx
  55. 16 16
      panda/src/tinydisplay/tinyOsxGraphicsWindow.mm
  56. 9 11
      panda/src/tinydisplay/tinySDLGraphicsWindow.cxx
  57. 9 11
      panda/src/tinydisplay/tinyXGraphicsWindow.cxx
  58. 0 2
      panda/src/vrpn/vrpnAnalog.cxx
  59. 0 2
      panda/src/vrpn/vrpnButton.cxx
  60. 0 2
      panda/src/vrpn/vrpnDial.cxx
  61. 12 19
      panda/src/vrpn/vrpnTracker.cxx
  62. 3 3
      panda/src/windisplay/winGraphicsWindow.cxx
  63. 78 269
      panda/src/x11display/x11GraphicsWindow.cxx
  64. 1 1
      panda/src/x11display/x11GraphicsWindow.h

+ 15 - 15
makepanda/makepanda.py

@@ -3641,6 +3641,21 @@ if (not RUNTIME):
   TargetAdd('libp3dgraph.in', opts=['IMOD:panda3d.core', 'ILIB:libp3dgraph', 'SRCDIR:panda/src/dgraph'])
   TargetAdd('libp3dgraph.in', opts=['IMOD:panda3d.core', 'ILIB:libp3dgraph', 'SRCDIR:panda/src/dgraph'])
   TargetAdd('libp3dgraph_igate.obj', input='libp3dgraph.in', opts=["DEPENDENCYONLY"])
   TargetAdd('libp3dgraph_igate.obj', input='libp3dgraph.in', opts=["DEPENDENCYONLY"])
 
 
+#
+# DIRECTORY: panda/src/device/
+#
+
+if (not RUNTIME):
+  OPTS=['DIR:panda/src/device', 'BUILDING:PANDA']
+  TargetAdd('p3device_composite1.obj', opts=OPTS, input='p3device_composite1.cxx')
+  TargetAdd('p3device_composite2.obj', opts=OPTS, input='p3device_composite2.cxx')
+
+  OPTS=['DIR:panda/src/device']
+  IGATEFILES=GetDirectoryContents('panda/src/device', ["*.h", "*_composite*.cxx"])
+  TargetAdd('libp3device.in', opts=OPTS, input=IGATEFILES)
+  TargetAdd('libp3device.in', opts=['IMOD:panda3d.core', 'ILIB:libp3device', 'SRCDIR:panda/src/device'])
+  TargetAdd('libp3device_igate.obj', input='libp3device.in', opts=["DEPENDENCYONLY"])
+
 #
 #
 # DIRECTORY: panda/src/display/
 # DIRECTORY: panda/src/display/
 #
 #
@@ -3665,21 +3680,6 @@ if (not RUNTIME):
     TargetAdd('subprocessWindowBuffer.obj', opts=OPTS, input='subprocessWindowBuffer.cxx')
     TargetAdd('subprocessWindowBuffer.obj', opts=OPTS, input='subprocessWindowBuffer.cxx')
     TargetAdd('libp3subprocbuffer.ilb', input='subprocessWindowBuffer.obj')
     TargetAdd('libp3subprocbuffer.ilb', input='subprocessWindowBuffer.obj')
 
 
-#
-# DIRECTORY: panda/src/device/
-#
-
-if (not RUNTIME):
-  OPTS=['DIR:panda/src/device', 'BUILDING:PANDA']
-  TargetAdd('p3device_composite1.obj', opts=OPTS, input='p3device_composite1.cxx')
-  TargetAdd('p3device_composite2.obj', opts=OPTS, input='p3device_composite2.cxx')
-
-  OPTS=['DIR:panda/src/device']
-  IGATEFILES=GetDirectoryContents('panda/src/device', ["*.h", "*_composite*.cxx"])
-  TargetAdd('libp3device.in', opts=OPTS, input=IGATEFILES)
-  TargetAdd('libp3device.in', opts=['IMOD:panda3d.core', 'ILIB:libp3device', 'SRCDIR:panda/src/device'])
-  TargetAdd('libp3device_igate.obj', input='libp3device.in', opts=["DEPENDENCYONLY"])
-
 #
 #
 # DIRECTORY: panda/src/pnmtext/
 # DIRECTORY: panda/src/pnmtext/
 #
 #

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

@@ -44,10 +44,7 @@ is_valid() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE int AnalogNode::
 INLINE int AnalogNode::
 get_num_controls() const {
 get_num_controls() const {
-  _analog->acquire();
-  int result = _analog->get_num_controls();
-  _analog->unlock();
-  return result;
+  return _analog->get_num_controls();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -60,10 +57,7 @@ get_num_controls() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE double AnalogNode::
 INLINE double AnalogNode::
 get_control_state(int index) const {
 get_control_state(int index) const {
-  _analog->acquire();
-  double result = _analog->get_control_state(index);
-  _analog->unlock();
-  return result;
+  return _analog->get_control_state(index);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -75,10 +69,7 @@ get_control_state(int index) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool AnalogNode::
 INLINE bool AnalogNode::
 is_control_known(int index) const {
 is_control_known(int index) const {
-  _analog->acquire();
-  bool result = _analog->is_control_known(index);
-  _analog->unlock();
-  return result;
+  return _analog->is_control_known(index);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

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

@@ -30,7 +30,7 @@ AnalogNode(ClientBase *client, const string &device_name) :
   DataNode(device_name)
   DataNode(device_name)
 {
 {
   _xy_output = define_output("xy", EventStoreVec2::get_class_type());
   _xy_output = define_output("xy", EventStoreVec2::get_class_type());
-  _xy = new EventStoreVec2(LPoint2(0.0f, 0.0f));
+  _xy = new EventStoreVec2(LPoint2(0));
 
 
   nassertv(client != (ClientBase *)NULL);
   nassertv(client != (ClientBase *)NULL);
   PT(ClientDevice) device =
   PT(ClientDevice) device =
@@ -49,7 +49,23 @@ AnalogNode(ClientBase *client, const string &device_name) :
     return;
     return;
   }
   }
 
 
-  _analog = DCAST(ClientAnalogDevice, device);
+  _analog = device;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnalogNode::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+AnalogNode::
+AnalogNode(InputDevice *device) :
+  DataNode(device->get_name()),
+  _analog(device)
+{
+  _xy_output = define_output("xy", EventStoreVec2::get_class_type());
+  _xy = new EventStoreVec2(LPoint2(0));
+
+  nassertv(device != (InputDevice *)NULL);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -74,9 +90,7 @@ write(ostream &out, int indent_level) const {
   DataNode::write(out, indent_level);
   DataNode::write(out, indent_level);
 
 
   if (_analog != (ClientAnalogDevice *)NULL) {
   if (_analog != (ClientAnalogDevice *)NULL) {
-    _analog->acquire();
     _analog->write_controls(out, indent_level + 2);
     _analog->write_controls(out, indent_level + 2);
-    _analog->unlock();
   }
   }
 }
 }
 
 
@@ -100,8 +114,6 @@ do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &,
     _analog->poll();
     _analog->poll();
 
 
     LPoint2 out(0.0f, 0.0f);
     LPoint2 out(0.0f, 0.0f);
-
-    _analog->acquire();
     for (int i = 0; i < max_outputs; i++) {
     for (int i = 0; i < max_outputs; i++) {
       if (_outputs[i]._index >= 0 &&
       if (_outputs[i]._index >= 0 &&
           _analog->is_control_known(_outputs[i]._index)) {
           _analog->is_control_known(_outputs[i]._index)) {
@@ -112,7 +124,6 @@ do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &,
         }
         }
       }
       }
     }
     }
-    _analog->unlock();
     _xy->set_value(out);
     _xy->set_value(out);
     output.set_data(_xy_output, EventParameter(_xy));
     output.set_data(_xy_output, EventParameter(_xy));
   }
   }

+ 2 - 1
panda/src/device/analogNode.h

@@ -45,6 +45,7 @@
 class EXPCL_PANDA_DEVICE AnalogNode : public DataNode {
 class EXPCL_PANDA_DEVICE AnalogNode : public DataNode {
 PUBLISHED:
 PUBLISHED:
   AnalogNode(ClientBase *client, const string &device_name);
   AnalogNode(ClientBase *client, const string &device_name);
+  AnalogNode(InputDevice *device);
   virtual ~AnalogNode();
   virtual ~AnalogNode();
 
 
   INLINE bool is_valid() const;
   INLINE bool is_valid() const;
@@ -73,7 +74,7 @@ private:
   enum { max_outputs = 2 };
   enum { max_outputs = 2 };
   OutputData _outputs[max_outputs];
   OutputData _outputs[max_outputs];
 
 
-  PT(ClientAnalogDevice) _analog;
+  PT(InputDevice) _analog;
 
 
 protected:
 protected:
   // Inherited from DataNode
   // Inherited from DataNode

+ 6 - 20
panda/src/device/buttonNode.I

@@ -21,7 +21,7 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool ButtonNode::
 INLINE bool ButtonNode::
 is_valid() const {
 is_valid() const {
-  return (_button != (ClientButtonDevice *)NULL) && _button->is_connected();
+  return (_device != (ClientButtonDevice *)NULL) && _device->is_connected();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -36,10 +36,7 @@ is_valid() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE int ButtonNode::
 INLINE int ButtonNode::
 get_num_buttons() const {
 get_num_buttons() const {
-  _button->acquire();
-  int result = _button->get_num_buttons();
-  _button->unlock();
-  return result;
+  return _device->get_num_buttons();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -58,9 +55,7 @@ get_num_buttons() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void ButtonNode::
 INLINE void ButtonNode::
 set_button_map(int index, ButtonHandle button) {
 set_button_map(int index, ButtonHandle button) {
-  _button->acquire();
-  _button->set_button_map(index, button);
-  _button->unlock();
+  _device->set_button_map(index, button);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -73,10 +68,7 @@ set_button_map(int index, ButtonHandle button) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE ButtonHandle ButtonNode::
 INLINE ButtonHandle ButtonNode::
 get_button_map(int index) const {
 get_button_map(int index) const {
-  _button->acquire();
-  ButtonHandle result = _button->get_button_map(index);
-  _button->unlock();
-  return result;
+  return _device->get_button_map(index);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -88,10 +80,7 @@ get_button_map(int index) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool ButtonNode::
 INLINE bool ButtonNode::
 get_button_state(int index) const {
 get_button_state(int index) const {
-  _button->acquire();
-  bool result = _button->get_button_state(index);
-  _button->unlock();
-  return result;
+  return _device->get_button_state(index);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -103,8 +92,5 @@ get_button_state(int index) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool ButtonNode::
 INLINE bool ButtonNode::
 is_button_known(int index) const {
 is_button_known(int index) const {
-  _button->acquire();
-  bool result = _button->is_button_known(index);
-  _button->unlock();
-  return result;
+  return _device->is_button_known(index);
 }
 }

+ 22 - 20
panda/src/device/buttonNode.cxx

@@ -30,7 +30,6 @@ ButtonNode(ClientBase *client, const string &device_name) :
   DataNode(device_name)
   DataNode(device_name)
 {
 {
   _button_events_output = define_output("button_events", ButtonEventList::get_class_type());
   _button_events_output = define_output("button_events", ButtonEventList::get_class_type());
-  _button_events = new ButtonEventList;
 
 
   nassertv(client != (ClientBase *)NULL);
   nassertv(client != (ClientBase *)NULL);
   PT(ClientDevice) device =
   PT(ClientDevice) device =
@@ -49,7 +48,21 @@ ButtonNode(ClientBase *client, const string &device_name) :
     return;
     return;
   }
   }
 
 
-  _button = DCAST(ClientButtonDevice, device);
+  _device = device;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ButtonNode::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+ButtonNode::
+ButtonNode(InputDevice *device) :
+  DataNode(device->get_name()),
+  _device(device)
+{
+  _button_events_output = define_output("button_events", ButtonEventList::get_class_type());
+  _device = device;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -59,7 +72,7 @@ ButtonNode(ClientBase *client, const string &device_name) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 ButtonNode::
 ButtonNode::
 ~ButtonNode() {
 ~ButtonNode() {
-  // When the _button pointer destructs, the ClientButtonDevice
+  // When the _device pointer destructs, the ClientButtonDevice
   // disconnects itself from the ClientBase, and everything that needs
   // disconnects itself from the ClientBase, and everything that needs
   // to get turned off does.  Magic.
   // to get turned off does.  Magic.
 }
 }
@@ -73,11 +86,9 @@ void ButtonNode::
 output(ostream &out) const {
 output(ostream &out) const {
   DataNode::output(out);
   DataNode::output(out);
 
 
-  if (_button != (ClientButtonDevice *)NULL) {
+  if (_device != (InputDevice *)NULL) {
     out << " (";
     out << " (";
-    _button->acquire();
-    _button->output_buttons(out);
-    _button->unlock();
+    _device->output_buttons(out);
     out << ")";
     out << ")";
   }
   }
 }
 }
@@ -91,10 +102,8 @@ void ButtonNode::
 write(ostream &out, int indent_level) const {
 write(ostream &out, int indent_level) const {
   DataNode::write(out, indent_level);
   DataNode::write(out, indent_level);
 
 
-  if (_button != (ClientButtonDevice *)NULL) {
-    _button->acquire();
-    _button->write_buttons(out, indent_level + 2);
-    _button->unlock();
+  if (_device != (InputDevice *)NULL) {
+    _device->write_buttons(out, indent_level + 2);
   }
   }
 }
 }
 
 
@@ -115,14 +124,7 @@ void ButtonNode::
 do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &, 
 do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &, 
                  DataNodeTransmit &output) {
                  DataNodeTransmit &output) {
   if (is_valid()) {
   if (is_valid()) {
-    _button->poll();
-    _button->acquire();
-
-    (*_button_events) = (*_button->get_button_events());
-
-    _button->get_button_events()->clear();
-    _button->unlock();
-
-    output.set_data(_button_events_output, EventParameter(_button_events));
+    PT(ButtonEventList) bel = _device->get_button_events();
+    output.set_data(_button_events_output, EventParameter(bel));
   }
   }
 }
 }

+ 2 - 4
panda/src/device/buttonNode.h

@@ -20,8 +20,6 @@
 #include "clientBase.h"
 #include "clientBase.h"
 #include "clientButtonDevice.h"
 #include "clientButtonDevice.h"
 #include "dataNode.h"
 #include "dataNode.h"
-#include "buttonEventList.h"
-
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : ButtonNode
 //       Class : ButtonNode
@@ -41,6 +39,7 @@
 class EXPCL_PANDA_DEVICE ButtonNode : public DataNode {
 class EXPCL_PANDA_DEVICE ButtonNode : public DataNode {
 PUBLISHED:
 PUBLISHED:
   ButtonNode(ClientBase *client, const string &device_name);
   ButtonNode(ClientBase *client, const string &device_name);
+  ButtonNode(InputDevice *device);
   virtual ~ButtonNode();
   virtual ~ButtonNode();
 
 
   INLINE bool is_valid() const;
   INLINE bool is_valid() const;
@@ -58,7 +57,7 @@ public:
   virtual void write(ostream &out, int indent_level = 0) const;
   virtual void write(ostream &out, int indent_level = 0) const;
 
 
 private:
 private:
-  PT(ClientButtonDevice) _button;
+  PT(InputDevice) _device;
 
 
 protected:
 protected:
   // Inherited from DataNode
   // Inherited from DataNode
@@ -69,7 +68,6 @@ protected:
 private:
 private:
   // outputs
   // outputs
   int _button_events_output;
   int _button_events_output;
-  PT(ButtonEventList) _button_events;
 
 
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {

+ 0 - 74
panda/src/device/clientAnalogDevice.I

@@ -13,18 +13,6 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: ClientAnalogDevice::AnalogState::Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE ClientAnalogDevice::AnalogState::
-AnalogState() :
-  _state(0.0),
-  _known(false)
-{
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: ClientAnalogDevice::Constructor
 //     Function: ClientAnalogDevice::Constructor
 //       Access: Protected
 //       Access: Protected
@@ -35,65 +23,3 @@ ClientAnalogDevice(ClientBase *client, const string &device_name):
   ClientDevice(client, get_class_type(), device_name)
   ClientDevice(client, get_class_type(), device_name)
 {
 {
 }
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: ClientAnalogDevice::get_num_controls
-//       Access: Public
-//  Description: Returns the number of analog controls known to the
-//               ClientAnalogDevice.  This number may change as
-//               more controls are discovered.
-////////////////////////////////////////////////////////////////////
-INLINE int ClientAnalogDevice::
-get_num_controls() const {
-  return _controls.size();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ClientAnalogDevice::set_control_state
-//       Access: Public
-//  Description: Sets the state of the indicated analog index.  The
-//               caller should ensure that acquire() is in effect 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.
-////////////////////////////////////////////////////////////////////
-INLINE void ClientAnalogDevice::
-set_control_state(int index, double state) {
-  ensure_control_index(index);
-  nassertv(index >= 0 && index < (int)_controls.size());
-  _controls[index]._state = state;
-  _controls[index]._known = true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ClientAnalogDevice::get_control_state
-//       Access: Public
-//  Description: 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.
-////////////////////////////////////////////////////////////////////
-INLINE double ClientAnalogDevice::
-get_control_state(int index) const {
-  if (index >= 0 && index < (int)_controls.size()) {
-    return _controls[index]._state;
-  } else {
-    return 0.0;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ClientAnalogDevice::is_control_known
-//       Access: Public
-//  Description: Returns true if the state of the indicated analog
-//               control is known, or false if we have never heard
-//               anything about this particular control.
-////////////////////////////////////////////////////////////////////
-INLINE bool ClientAnalogDevice::
-is_control_known(int index) const {
-  if (index >= 0 && index < (int)_controls.size()) {
-    return _controls[index]._known;
-  } else {
-    return false;
-  }
-}

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

@@ -19,25 +19,6 @@
 
 
 TypeHandle ClientAnalogDevice::_type_handle;
 TypeHandle ClientAnalogDevice::_type_handle;
 
 
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: ClientAnalogDevice::ensure_control_index
-//       Access: Private
-//  Description: Guarantees that there is a slot in the array for the
-//               indicated index number, by filling the array up to
-//               that index if necessary.
-////////////////////////////////////////////////////////////////////
-void ClientAnalogDevice::
-ensure_control_index(int index) {
-  nassertv(index >= 0);
-
-  _controls.reserve(index + 1);
-  while ((int)_controls.size() <= index) {
-    _controls.push_back(AnalogState());
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: ClientAnalogDevice::write
 //     Function: ClientAnalogDevice::write
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -45,32 +26,6 @@ ensure_control_index(int index) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void ClientAnalogDevice::
 void ClientAnalogDevice::
 write(ostream &out, int indent_level) const {
 write(ostream &out, int indent_level) const {
-  indent(out, indent_level) << get_type() << " " << get_device_name() << ":\n";
+  indent(out, indent_level) << get_type() << " " << get_name() << ":\n";
   write_controls(out, indent_level + 2);
   write_controls(out, indent_level + 2);
 }
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: ClientAnalogDevice::write_analogs
-//       Access: Public
-//  Description: Writes a multi-line description of the current analog
-//               control states.
-////////////////////////////////////////////////////////////////////
-void ClientAnalogDevice::
-write_controls(ostream &out, int indent_level) const {
-  bool any_controls = false;
-  Controls::const_iterator ai;
-  for (ai = _controls.begin(); ai != _controls.end(); ++ai) {
-    const AnalogState &state = (*ai);
-    if (state._known) {
-      any_controls = true;
-
-      indent(out, indent_level)
-        << (int)(ai - _controls.begin()) << ". " << state._state << "\n";
-    }
-  }
-
-  if (!any_controls) {
-    indent(out, indent_level)
-      << "(no known analog controls)\n";
-  }
-}

+ 0 - 23
panda/src/device/clientAnalogDevice.h

@@ -36,30 +36,7 @@ protected:
   INLINE ClientAnalogDevice(ClientBase *client, const string &device_name);
   INLINE ClientAnalogDevice(ClientBase *client, const string &device_name);
 
 
 public:
 public:
-  INLINE int get_num_controls() const;
-
-  INLINE void set_control_state(int index, double state);
-  INLINE double get_control_state(int index) const;
-  INLINE bool is_control_known(int index) const;
-
   virtual void write(ostream &out, int indent_level = 0) const;
   virtual void write(ostream &out, int indent_level = 0) const;
-  void write_controls(ostream &out, int indent_level) const;
-
-private:
-  void ensure_control_index(int index);
-
-protected:
-  class AnalogState {
-  public:
-    INLINE AnalogState();
-
-    double _state;
-    bool _known;
-  };
-
-  typedef pvector<AnalogState> Controls;
-  Controls _controls;
-
 
 
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {

+ 0 - 1
panda/src/device/clientBase.cxx

@@ -144,7 +144,6 @@ get_device(TypeHandle device_type, const string &device_name) {
 
 
   if (device != (ClientDevice *)NULL) {
   if (device != (ClientDevice *)NULL) {
     dbn.insert(DevicesByName::value_type(device_name, device));
     dbn.insert(DevicesByName::value_type(device_name, device));
-    device->_is_connected = true;
   }
   }
 
 
   return device;
   return device;

+ 0 - 110
panda/src/device/clientButtonDevice.I

@@ -12,113 +12,3 @@
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
-
-////////////////////////////////////////////////////////////////////
-//     Function: ClientButtonDevice::ButtonState::Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE ClientButtonDevice::ButtonState::
-ButtonState() :
-  _handle(ButtonHandle::none()),
-  _state(S_unknown)
-{
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: ClientButtonDevice::get_num_buttons
-//       Access: Public
-//  Description: Returns the number of buttons known to the
-//               ClientButtonDevice.  This includes those buttons
-//               whose state has been seen, as well as buttons that
-//               have been associated with a ButtonHandle even if
-//               their state is unknown.  This number may change as
-//               more buttons are discovered.
-////////////////////////////////////////////////////////////////////
-INLINE int ClientButtonDevice::
-get_num_buttons() const {
-  return _buttons.size();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ClientButtonDevice::set_button_map
-//       Access: Public
-//  Description: Associates the indicated ButtonHandle with the button
-//               of the indicated index number.  When the given button
-//               index changes state, a corresponding ButtonEvent will
-//               be generated with the given ButtonHandle.  Pass
-//               ButtonHandle::none() to turn off any association.
-//
-//               It is not necessary to call this if you simply want
-//               to query the state of the various buttons by index
-//               number; this is only necessary in order to generate
-//               ButtonEvents when the buttons change state.
-////////////////////////////////////////////////////////////////////
-INLINE void ClientButtonDevice::
-set_button_map(int index, ButtonHandle button) {
-  ensure_button_index(index);
-  nassertv(index >= 0 && index < (int)_buttons.size());
-  _buttons[index]._handle = button;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ClientButtonDevice::get_button_map
-//       Access: Public
-//  Description: 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 was associated.
-////////////////////////////////////////////////////////////////////
-INLINE ButtonHandle ClientButtonDevice::
-get_button_map(int index) const {
-  if (index >= 0 && index < (int)_buttons.size()) {
-    return _buttons[index]._handle;
-  } else {
-    return ButtonHandle::none();
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ClientButtonDevice::get_button_state
-//       Access: Public
-//  Description: Returns true if the indicated button (identified by
-//               its index number) is currently known to be down, or
-//               false if it is up or unknown.
-////////////////////////////////////////////////////////////////////
-INLINE bool ClientButtonDevice::
-get_button_state(int index) const {
-  if (index >= 0 && index < (int)_buttons.size()) {
-    return (_buttons[index]._state == S_down);
-  } else {
-    return false;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ClientButtonDevice::is_button_known
-//       Access: Public
-//  Description: Returns true if the state of the indicated button is
-//               known, or false if we have never heard anything about
-//               this particular button.
-////////////////////////////////////////////////////////////////////
-INLINE bool ClientButtonDevice::
-is_button_known(int index) const {
-  if (index >= 0 && index < (int)_buttons.size()) {
-    return _buttons[index]._state != S_unknown;
-  } else {
-    return false;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ClientButtonDevice::get_button_events
-//       Access: Public
-//  Description: Returns the list of recently-generated ButtonEvents.
-//               This must be periodically cleared, or the buttons
-//               will accumulate.
-////////////////////////////////////////////////////////////////////
-INLINE ButtonEventList *ClientButtonDevice::
-get_button_events() const {
-  return _button_events;
-}

+ 2 - 111
panda/src/device/clientButtonDevice.cxx

@@ -28,47 +28,6 @@ ClientButtonDevice::
 ClientButtonDevice(ClientBase *client, const string &device_name):
 ClientButtonDevice(ClientBase *client, const string &device_name):
   ClientDevice(client, get_class_type(), device_name)
   ClientDevice(client, get_class_type(), device_name)
 {
 {
-  _button_events = new ButtonEventList();
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: ClientButtonDevice::set_button_state
-//       Access: Public
-//  Description: Sets the state of the indicated button index, where
-//               true indicates down, and false indicates up.  This
-//               may generate a ButtonEvent if the button has an
-//               associated ButtonHandle.  The caller should ensure
-//               that acquire() is in effect while this call is made.
-////////////////////////////////////////////////////////////////////
-void ClientButtonDevice::
-set_button_state(int index, bool down) {
-  ensure_button_index(index);
-  nassertv(index >= 0 && index < (int)_buttons.size());
-  _buttons[index]._state = down ? S_down : S_up;
-
-  ButtonHandle handle = _buttons[index]._handle;
-  if (handle != ButtonHandle::none()) {
-    _button_events->add_event(ButtonEvent(handle, down ? ButtonEvent::T_down : ButtonEvent::T_up));
-  }
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: ClientButtonDevice::ensure_button_index
-//       Access: Private
-//  Description: Guarantees that there is a slot in the array for the
-//               indicated index number, by filling the array up to
-//               that index if necessary.
-////////////////////////////////////////////////////////////////////
-void ClientButtonDevice::
-ensure_button_index(int index) {
-  nassertv(index >= 0);
-
-  _buttons.reserve(index + 1);
-  while ((int)_buttons.size() <= index) {
-    _buttons.push_back(ButtonState());
-  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -78,7 +37,7 @@ ensure_button_index(int index) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void ClientButtonDevice::
 void ClientButtonDevice::
 output(ostream &out) const {
 output(ostream &out) const {
-  out << get_type() << " " << get_device_name() << " (";
+  out << get_type() << " " << get_name() << " (";
   output_buttons(out);
   output_buttons(out);
   out << ")";
   out << ")";
 }
 }
@@ -90,74 +49,6 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void ClientButtonDevice::
 void ClientButtonDevice::
 write(ostream &out, int indent_level) const {
 write(ostream &out, int indent_level) const {
-  indent(out, indent_level) << get_type() << " " << get_device_name() << ":\n";
+  indent(out, indent_level) << get_type() << " " << get_name() << ":\n";
   write_buttons(out, indent_level + 2);
   write_buttons(out, indent_level + 2);
 }
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: ClientButtonDevice::output_buttons
-//       Access: Public
-//  Description: Writes a one-line string of all of the current button
-//               states.
-////////////////////////////////////////////////////////////////////
-void ClientButtonDevice::
-output_buttons(ostream &out) const {
-  bool any_buttons = false;
-  Buttons::const_iterator bi;
-  for (bi = _buttons.begin(); bi != _buttons.end(); ++bi) {
-    const ButtonState &state = (*bi);
-    if (state._state != S_unknown) {
-      if (any_buttons) {
-        out << ", ";
-      }
-      any_buttons = true;
-      out << (int)(bi - _buttons.begin()) << "=";
-      if (state._state == S_up) {
-        out << "up";
-      } else {
-        out << "down";
-      }
-    }
-  }
-
-  if (!any_buttons) {
-    out << "no known buttons";
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ClientButtonDevice::write_buttons
-//       Access: Public
-//  Description: Writes a multi-line description of the current button
-//               states.
-////////////////////////////////////////////////////////////////////
-void ClientButtonDevice::
-write_buttons(ostream &out, int indent_level) const {
-  bool any_buttons = false;
-  Buttons::const_iterator bi;
-  for (bi = _buttons.begin(); bi != _buttons.end(); ++bi) {
-    const ButtonState &state = (*bi);
-    if (state._state != S_unknown) {
-      any_buttons = true;
-
-      indent(out, indent_level)
-        << (int)(bi - _buttons.begin()) << ". ";
-
-      if (state._handle != ButtonHandle::none()) {
-        out << "(" << state._handle << ") ";
-      }
-
-      if (state._state == S_up) {
-        out << "up";
-      } else {
-        out << "down";
-      }
-      out << "\n";
-    }
-  }
-
-  if (!any_buttons) {
-    indent(out, indent_level)
-      << "(no known buttons)\n";
-  }
-}

+ 0 - 38
panda/src/device/clientButtonDevice.h

@@ -39,46 +39,9 @@ protected:
   ClientButtonDevice(ClientBase *client, const string &device_name);
   ClientButtonDevice(ClientBase *client, const string &device_name);
 
 
 public:
 public:
-  INLINE int get_num_buttons() const;
-
-  INLINE void set_button_map(int index, ButtonHandle button);
-  INLINE ButtonHandle get_button_map(int index) const;
-
-  void set_button_state(int index, bool down);
-  INLINE bool get_button_state(int index) const;
-  INLINE bool is_button_known(int index) const;
-
-  INLINE ButtonEventList *get_button_events() const;
-
   virtual void output(ostream &out) const;
   virtual void output(ostream &out) const;
   virtual void write(ostream &out, int indent_level = 0) const;
   virtual void write(ostream &out, int indent_level = 0) const;
 
 
-  void output_buttons(ostream &out) const;
-  void write_buttons(ostream &out, int indent_level) const;
-
-private:
-  void ensure_button_index(int index);
-
-protected:
-  enum State {
-    S_unknown,
-    S_up,
-    S_down
-  };
-
-  class ButtonState {
-  public:
-    INLINE ButtonState();
-
-    ButtonHandle _handle;
-    State _state;
-  };
-
-  typedef pvector<ButtonState> Buttons;
-  Buttons _buttons;
-
-  PT(ButtonEventList) _button_events;
-
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;
@@ -95,7 +58,6 @@ public:
 
 
 private:
 private:
   static TypeHandle _type_handle;
   static TypeHandle _type_handle;
-  friend class ButtonState;
 };
 };
 
 
 #include "clientButtonDevice.I"
 #include "clientButtonDevice.I"

+ 0 - 53
panda/src/device/clientDevice.I

@@ -24,17 +24,6 @@ get_client() const {
   return _client;
   return _client;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: ClientDevice::is_connected
-//       Access: Public
-//  Description: Returns true if the device is still connected to its
-//               ClientBase, false otherwise.
-////////////////////////////////////////////////////////////////////
-INLINE bool ClientDevice::
-is_connected() const {
-  return _is_connected;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: ClientDevice::get_device_type
 //     Function: ClientDevice::get_device_type
 //       Access: Public
 //       Access: Public
@@ -50,45 +39,3 @@ INLINE TypeHandle ClientDevice::
 get_device_type() const {
 get_device_type() const {
   return _device_type;
   return _device_type;
 }
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: ClientDevice::get_device_name
-//       Access: Public
-//  Description: Returns the device name reported to the ClientBase.
-//               This has some implementation-defined meaning to
-//               identify particular devices.
-////////////////////////////////////////////////////////////////////
-INLINE const string &ClientDevice::
-get_device_name() const {
-  return _device_name;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ClientDevice::acquire
-//       Access: Public
-//  Description: Grabs the mutex associated with this particular
-//               device.  The device will not update asynchronously
-//               while the mutex is held, allowing the user to copy
-//               the data out without fear of getting a partial update
-//               during the copy.
-////////////////////////////////////////////////////////////////////
-INLINE void ClientDevice::
-acquire() {
-#ifdef OLD_HAVE_IPC
-  _lock.acquire();
-#endif
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ClientDevice::unlock
-//       Access: Public
-//  Description: Releases the mutex associated with this particular
-//               device.  This should be called after all the data has
-//               been successfully copied out.  See acquire().
-////////////////////////////////////////////////////////////////////
-INLINE void ClientDevice::
-unlock() {
-#ifdef OLD_HAVE_IPC
-  _lock.unlock();
-#endif
-}

+ 11 - 14
panda/src/device/clientDevice.cxx

@@ -27,15 +27,14 @@ TypeHandle ClientDevice::_type_handle;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 ClientDevice::
 ClientDevice::
 ClientDevice(ClientBase *client, TypeHandle device_type,
 ClientDevice(ClientBase *client, TypeHandle device_type,
-             const string &device_name) :
+             const string &device_name, int device_flags) :
+  InputDevice(device_name, DC_unknown, device_flags),
   _client(client),
   _client(client),
-  _device_type(device_type),
-  _device_name(device_name)
+  _device_type(device_type)
 {
 {
   // We have to explicitly ref the client pointer, since we can't use
   // We have to explicitly ref the client pointer, since we can't use
   // a PT(ClientBase) for circular include reasons.
   // a PT(ClientBase) for circular include reasons.
   _client->ref();
   _client->ref();
-  _is_connected = false;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -49,7 +48,7 @@ ClientDevice(ClientBase *client, TypeHandle device_type,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 ClientDevice::
 ClientDevice::
 ~ClientDevice() {
 ~ClientDevice() {
-  nassertv(!_is_connected);
+  nassertv(!is_connected());
 
 
   // And now we explicitly unref the client pointer.
   // And now we explicitly unref the client pointer.
   unref_delete(_client);
   unref_delete(_client);
@@ -72,19 +71,17 @@ ClientDevice::
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void ClientDevice::
 void ClientDevice::
 disconnect() {
 disconnect() {
-  if (_is_connected) {
-    acquire();
+  if (is_connected()) {
     bool disconnected =
     bool disconnected =
-      _client->disconnect_device(_device_type, _device_name, this);
-    _is_connected = false;
-    unlock();
+      _client->disconnect_device(_device_type, get_name(), this);
+    set_connected(false);
     nassertv(disconnected);
     nassertv(disconnected);
   }
   }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: ClientDevice::poll
-//       Access: Public
+//     Function: ClientDevice::do_poll
+//       Access: Public, Virtual, Final
 //  Description: Causes the connected ClientBase to poll all of its
 //  Description: Causes the connected ClientBase to poll all of its
 //               clients, if necessary.  This will be a no-op if the
 //               clients, if necessary.  This will be a no-op if the
 //               client is running in forked mode, or if it has
 //               client is running in forked mode, or if it has
@@ -94,7 +91,7 @@ disconnect() {
 //               data in this ClientDevice to ensure that it is fresh.
 //               data in this ClientDevice to ensure that it is fresh.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void ClientDevice::
 void ClientDevice::
-poll() {
+do_poll() {
   _client->poll();
   _client->poll();
 }
 }
 
 
@@ -105,7 +102,7 @@ poll() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void ClientDevice::
 void ClientDevice::
 output(ostream &out) const {
 output(ostream &out) const {
-  out << get_type() << " " << get_device_name();
+  out << get_type() << " " << get_name();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 6 - 21
panda/src/device/clientDevice.h

@@ -16,12 +16,7 @@
 #define CLIENTDEVICE_H
 #define CLIENTDEVICE_H
 
 
 #include "pandabase.h"
 #include "pandabase.h"
-
-#include "typedReferenceCount.h"
-
-#ifdef OLD_HAVE_IPC
-#include <ipc_mutex.h>
-#endif
+#include "inputDevice.h"
 
 
 class ClientBase;
 class ClientBase;
 
 
@@ -32,24 +27,20 @@ class ClientBase;
 //               This is an abstract interface; the actual
 //               This is an abstract interface; the actual
 //               implementations are in ClientTrackerDevice, etc.
 //               implementations are in ClientTrackerDevice, etc.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA_DEVICE ClientDevice : public TypedReferenceCount {
+class EXPCL_PANDA_DEVICE ClientDevice : public InputDevice {
 protected:
 protected:
   ClientDevice(ClientBase *client, TypeHandle device_type,
   ClientDevice(ClientBase *client, TypeHandle device_type,
-               const string &device_name);
+               const string &device_name, int device_flags=0);
 
 
 public:
 public:
   virtual ~ClientDevice();
   virtual ~ClientDevice();
 
 
   INLINE ClientBase *get_client() const;
   INLINE ClientBase *get_client() const;
   INLINE TypeHandle get_device_type() const;
   INLINE TypeHandle get_device_type() const;
-  INLINE const string &get_device_name() const;
 
 
-  INLINE bool is_connected() const;
   void disconnect();
   void disconnect();
 
 
-  void poll();
-  INLINE void acquire();
-  INLINE void unlock();
+  virtual void do_poll() FINAL;
 
 
   virtual void output(ostream &out) const;
   virtual void output(ostream &out) const;
   virtual void write(ostream &out, int indent_level = 0) const;
   virtual void write(ostream &out, int indent_level = 0) const;
@@ -57,21 +48,15 @@ public:
 private:
 private:
   ClientBase *_client;
   ClientBase *_client;
   TypeHandle _device_type;
   TypeHandle _device_type;
-  string _device_name;
-  bool _is_connected;
-
-#ifdef OLD_HAVE_IPC
-  mutex _lock;
-#endif
 
 
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;
   }
   }
   static void init_type() {
   static void init_type() {
-    TypedReferenceCount::init_type();
+    InputDevice::init_type();
     register_type(_type_handle, "ClientDevice",
     register_type(_type_handle, "ClientDevice",
-                  TypedReferenceCount::get_class_type());
+                  InputDevice::get_class_type());
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 1 - 13
panda/src/device/clientTrackerDevice.I

@@ -20,18 +20,6 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE ClientTrackerDevice::
 INLINE ClientTrackerDevice::
 ClientTrackerDevice(ClientBase *client, const string &device_name):
 ClientTrackerDevice(ClientBase *client, const string &device_name):
-  ClientDevice(client, get_class_type(), device_name)
+  ClientDevice(client, get_class_type(), device_name, IDF_has_tracker)
 {
 {
 }
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: ClientTrackerDevice::get_data
-//       Access: Public
-//  Description: Returns the TrackerData that this device is
-//               reporting.
-////////////////////////////////////////////////////////////////////
-INLINE const TrackerData &ClientTrackerDevice::
-get_data() const {
-  return _data;
-}
-

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

@@ -30,12 +30,6 @@ class EXPCL_PANDA_DEVICE ClientTrackerDevice : public ClientDevice {
 protected:
 protected:
   INLINE ClientTrackerDevice(ClientBase *client, const string &device_name);
   INLINE ClientTrackerDevice(ClientBase *client, const string &device_name);
 
 
-public:
-  INLINE const TrackerData &get_data() const;
-
-protected:
-  TrackerData _data;
-
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;

+ 9 - 2
panda/src/device/config_device.cxx

@@ -23,7 +23,9 @@
 #include "clientDialDevice.h"
 #include "clientDialDevice.h"
 #include "clientTrackerDevice.h"
 #include "clientTrackerDevice.h"
 #include "dialNode.h"
 #include "dialNode.h"
-#include "mouseAndKeyboard.h"
+#include "evdevInputDevice.h"
+#include "inputDevice.h"
+#include "linuxJoystickDevice.h"
 #include "trackerNode.h"
 #include "trackerNode.h"
 #include "virtualMouse.h"
 #include "virtualMouse.h"
 
 
@@ -64,7 +66,12 @@ init_libdevice() {
   ClientDialDevice::init_type();
   ClientDialDevice::init_type();
   ClientTrackerDevice::init_type();
   ClientTrackerDevice::init_type();
   DialNode::init_type();
   DialNode::init_type();
-  MouseAndKeyboard::init_type();
+  InputDevice::init_type();
   TrackerNode::init_type();
   TrackerNode::init_type();
   VirtualMouse::init_type();
   VirtualMouse::init_type();
+
+#ifdef PHAVE_LINUX_INPUT_H
+  EvdevInputDevice::init_type();
+  LinuxJoystickDevice::init_type();
+#endif
 }
 }

+ 3 - 12
panda/src/device/dialNode.I

@@ -33,10 +33,7 @@ is_valid() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE int DialNode::
 INLINE int DialNode::
 get_num_dials() const {
 get_num_dials() const {
-  _dial->acquire();
-  int result = _dial->get_num_dials();
-  _dial->unlock();
-  return result;
+  return _dial->get_num_dials();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -49,10 +46,7 @@ get_num_dials() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE double DialNode::
 INLINE double DialNode::
 read_dial(int index) {
 read_dial(int index) {
-  _dial->acquire();
-  double result = _dial->read_dial(index);
-  _dial->unlock();
-  return result;
+  return _dial->read_dial(index);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -64,8 +58,5 @@ read_dial(int index) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool DialNode::
 INLINE bool DialNode::
 is_dial_known(int index) const {
 is_dial_known(int index) const {
-  _dial->acquire();
-  bool result = _dial->is_dial_known(index);
-  _dial->unlock();
-  return result;
+  return _dial->is_dial_known(index);
 }
 }

+ 14 - 0
panda/src/device/evdevInputDevice.I

@@ -0,0 +1,14 @@
+// Filename: evdevInputDevice.I
+// Created by:  rdb (24Aug15)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+

+ 424 - 0
panda/src/device/evdevInputDevice.cxx

@@ -0,0 +1,424 @@
+// Filename: evdevInputDevice.cxx
+// Created by:  rdb (24Aug15)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "evdevInputDevice.h"
+
+#ifdef PHAVE_LINUX_INPUT_H
+
+#include "gamepadButton.h"
+#include "keyboardButton.h"
+#include "mouseButton.h"
+
+#include <fcntl.h>
+#include <linux/input.h>
+
+#define test_bit(bit, array) ((array)[(bit)/8] & (1<<((bit)&7)))
+
+TypeHandle EvdevInputDevice::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: EvdevInputDevice::Constructor
+//       Access: Published
+//  Description: Creates a new device using the Linux joystick
+//               device using the given file descriptor.  It will
+//               be closed when this object destructs.
+////////////////////////////////////////////////////////////////////
+EvdevInputDevice::
+EvdevInputDevice(int fd) :
+  _fd(fd) {
+  init_device();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EvdevInputDevice::Constructor
+//       Access: Published
+//  Description: Creates a new device using the Linux joystick
+//               device using the given device filename.
+////////////////////////////////////////////////////////////////////
+EvdevInputDevice::
+EvdevInputDevice(const string &fn) {
+  _fd = open(fn.c_str(), O_RDONLY | O_NONBLOCK);
+
+  if (_fd >= 0) {
+    init_device();
+  } else {
+    _is_connected = false;
+    device_cat.error()
+      << "Opening raw input device: " << strerror(errno) << " " << fn << "\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EvdevInputDevice::Destructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+EvdevInputDevice::
+~EvdevInputDevice() {
+  if (_fd != -1) {
+    close(_fd);
+    _fd = -1;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EvdevInputDevice::do_poll
+//       Access: Private, Virtual
+//  Description: Polls the input device for new activity, to ensure
+//               it contains the latest events.  This will only have
+//               any effect for some types of input devices; others
+//               may be updated automatically, and this method will
+//               be a no-op.
+////////////////////////////////////////////////////////////////////
+void EvdevInputDevice::
+do_poll() {
+  if (_fd != -1) {
+    while (process_events()) {}
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EvdevInputDevice::init_device
+//       Access: Private
+//  Description: Reads basic properties from the device.
+////////////////////////////////////////////////////////////////////
+bool EvdevInputDevice::
+init_device() {
+  uint8_t evtypes[EV_MAX/8 + 1];
+  char name[256];
+  char uniq[256];
+  if (ioctl(_fd, EVIOCGNAME(sizeof(name)), name) < 0 ||
+      ioctl(_fd, EVIOCGPHYS(sizeof(uniq)), uniq) < 0 ||
+      ioctl(_fd, EVIOCGBIT(0, EV_MAX), &evtypes) < 0) {
+    close(_fd);
+    _fd = -1;
+    _is_connected = false;
+    device_cat.error() << "Opening raw input device: ioctl failed\n";
+    return false;
+  }
+
+  for (char *p=name; *p; p++) {
+    if (((*p<'a')||(*p>'z')) && ((*p<'A')||(*p>'Z')) && ((*p<'0')||(*p>'9'))) {
+      *p = '_';
+    }
+  }
+  for (char *p=uniq; *p; p++) {
+    if (((*p<'a')||(*p>'z')) && ((*p<'A')||(*p>'Z')) && ((*p<'0')||(*p>'9'))) {
+      *p = '_';
+    }
+  }
+
+  _name = ((string)name) + "." + uniq;
+
+  if (test_bit(EV_REL, evtypes)) {
+    _flags |= IDF_has_pointer;
+  }
+
+  if (test_bit(EV_FF, evtypes)) {
+    _flags |= IDF_has_vibration;
+  }
+
+  _is_connected = true;
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EvdevInputDevice::process_events
+//       Access: Private
+//  Description: Reads a number of events from the device.
+////////////////////////////////////////////////////////////////////
+bool EvdevInputDevice::
+process_events() {
+  // Read 8 events at a time.
+  struct input_event events[8];
+
+  int n_read = read(_fd, events, sizeof(events));
+  if (n_read < 0) {
+    if (errno == EAGAIN || errno == EWOULDBLOCK) {
+      // No data available for now.
+
+    } else if (errno == ENODEV || errno == EINVAL) {
+      // The device ceased to exist, so we better close it.
+      close(_fd);
+      _fd = -1;
+      _is_connected = false;
+      errno = 0;
+
+    } else {
+      device_cat.error() << "read: " << strerror(errno) << "\n";
+    }
+    return false;
+  }
+
+  if (n_read == 0) {
+    return false;
+  }
+
+  n_read /= sizeof(struct input_event);
+
+  int x = _pointer_data.get_x();
+  int y = _pointer_data.get_y();
+  double time = ClockObject::get_global_clock()->get_frame_time();
+  ButtonHandle button;
+
+  for (int i = 0; i < n_read; ++i) {
+    switch (events[i].type) {
+    case EV_SYN:
+      break;
+
+    case EV_REL:
+      if (events[i].code == REL_X) x += events[i].value;
+      if (events[i].code == REL_Y) y += events[i].value;
+      break;
+
+    case EV_ABS:
+      if (events[i].code == ABS_X) x = events[i].value;
+      if (events[i].code == ABS_Y) y = events[i].value;
+      break;
+
+    case EV_KEY:
+      button = map_button(events[i].code);
+      _button_events->add_event(ButtonEvent(button, events[i].value ? ButtonEvent::T_down : ButtonEvent::T_up, time));
+      break;
+
+    default:
+      //cerr << "event " << events[i].type << " - " << events[i].code << " - " << events[i].value << "\n";
+      break;
+    }
+  }
+
+  set_pointer(true, x, y, time);
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EvdevInputDevice::map_button
+//       Access: Public, Static
+//  Description: Maps an evdev code to a ButtonHandle.
+////////////////////////////////////////////////////////////////////
+ButtonHandle EvdevInputDevice::
+map_button(int code) {
+  if (code >= 0 && code < 0x80) {
+    // See linux/input.h for the source of this mapping.
+    static const ButtonHandle keyboard_map[] = {
+      ButtonHandle::none(),
+      KeyboardButton::escape(),
+      KeyboardButton::ascii_key('1'),
+      KeyboardButton::ascii_key('2'),
+      KeyboardButton::ascii_key('3'),
+      KeyboardButton::ascii_key('4'),
+      KeyboardButton::ascii_key('5'),
+      KeyboardButton::ascii_key('6'),
+      KeyboardButton::ascii_key('7'),
+      KeyboardButton::ascii_key('8'),
+      KeyboardButton::ascii_key('9'),
+      KeyboardButton::ascii_key('0'),
+      KeyboardButton::ascii_key('-'),
+      KeyboardButton::ascii_key('='),
+      KeyboardButton::backspace(),
+      KeyboardButton::tab(),
+      KeyboardButton::ascii_key('q'),
+      KeyboardButton::ascii_key('w'),
+      KeyboardButton::ascii_key('e'),
+      KeyboardButton::ascii_key('r'),
+      KeyboardButton::ascii_key('t'),
+      KeyboardButton::ascii_key('y'),
+      KeyboardButton::ascii_key('u'),
+      KeyboardButton::ascii_key('i'),
+      KeyboardButton::ascii_key('o'),
+      KeyboardButton::ascii_key('p'),
+      KeyboardButton::ascii_key('['),
+      KeyboardButton::ascii_key(']'),
+      KeyboardButton::enter(),
+      KeyboardButton::lcontrol(),
+      KeyboardButton::ascii_key('a'),
+      KeyboardButton::ascii_key('s'),
+      KeyboardButton::ascii_key('d'),
+      KeyboardButton::ascii_key('f'),
+      KeyboardButton::ascii_key('g'),
+      KeyboardButton::ascii_key('h'),
+      KeyboardButton::ascii_key('j'),
+      KeyboardButton::ascii_key('k'),
+      KeyboardButton::ascii_key('l'),
+      KeyboardButton::ascii_key(';'),
+      KeyboardButton::ascii_key('\''),
+      KeyboardButton::ascii_key('`'),
+      KeyboardButton::lshift(),
+      KeyboardButton::ascii_key('\\'),
+      KeyboardButton::ascii_key('z'),
+      KeyboardButton::ascii_key('x'),
+      KeyboardButton::ascii_key('c'),
+      KeyboardButton::ascii_key('v'),
+      KeyboardButton::ascii_key('b'),
+      KeyboardButton::ascii_key('n'),
+      KeyboardButton::ascii_key('m'),
+      KeyboardButton::ascii_key(','),
+      KeyboardButton::ascii_key('.'),
+      KeyboardButton::ascii_key('/'),
+      KeyboardButton::rshift(),
+      KeyboardButton::ascii_key('*'),
+      KeyboardButton::lalt(),
+      KeyboardButton::space(),
+      KeyboardButton::caps_lock(),
+      KeyboardButton::f1(),
+      KeyboardButton::f2(),
+      KeyboardButton::f3(),
+      KeyboardButton::f4(),
+      KeyboardButton::f5(),
+      KeyboardButton::f6(),
+      KeyboardButton::f7(),
+      KeyboardButton::f8(),
+      KeyboardButton::f9(),
+      KeyboardButton::f10(),
+      KeyboardButton::num_lock(),
+      KeyboardButton::scroll_lock(),
+      KeyboardButton::ascii_key('7'),
+      KeyboardButton::ascii_key('8'),
+      KeyboardButton::ascii_key('9'),
+      KeyboardButton::ascii_key('-'),
+      KeyboardButton::ascii_key('4'),
+      KeyboardButton::ascii_key('5'),
+      KeyboardButton::ascii_key('6'),
+      KeyboardButton::ascii_key('+'),
+      KeyboardButton::ascii_key('1'),
+      KeyboardButton::ascii_key('2'),
+      KeyboardButton::ascii_key('3'),
+      KeyboardButton::ascii_key('0'),
+      KeyboardButton::ascii_key('.'),
+      ButtonHandle::none(),
+      ButtonHandle::none(),
+      ButtonHandle::none(),
+      KeyboardButton::f11(),
+      KeyboardButton::f12(),
+      ButtonHandle::none(),
+      ButtonHandle::none(),
+      ButtonHandle::none(),
+      ButtonHandle::none(),
+      ButtonHandle::none(),
+      ButtonHandle::none(),
+      ButtonHandle::none(),
+      KeyboardButton::enter(),
+      KeyboardButton::rcontrol(),
+      KeyboardButton::ascii_key('/'),
+      KeyboardButton::print_screen(),
+      KeyboardButton::ralt(),
+      ButtonHandle::none(),
+      KeyboardButton::home(),
+      KeyboardButton::up(),
+      KeyboardButton::page_up(),
+      KeyboardButton::left(),
+      KeyboardButton::right(),
+      KeyboardButton::end(),
+      KeyboardButton::down(),
+      KeyboardButton::page_down(),
+      KeyboardButton::insert(),
+      KeyboardButton::del(),
+      ButtonHandle::none(),
+      ButtonHandle::none(),
+      ButtonHandle::none(),
+      ButtonHandle::none(),
+      ButtonHandle::none(),
+      ButtonHandle::none(),
+      ButtonHandle::none(),
+      KeyboardButton::pause(),
+      ButtonHandle::none(),
+      ButtonHandle::none(),
+      ButtonHandle::none(),
+      ButtonHandle::none(),
+      ButtonHandle::none(),
+      KeyboardButton::lmeta(),
+      KeyboardButton::rmeta(),
+      KeyboardButton::menu(),
+    };
+    return keyboard_map[code];
+
+  } else if (code < 0x100) {
+    return ButtonHandle::none();
+
+  } else if ((code & 0xfff0) == BTN_MOUSE) {
+    // The number for these is reversed in Panda.
+    if (code == BTN_RIGHT) {
+      return MouseButton::three();
+    } else if (code == BTN_MIDDLE) {
+      return MouseButton::two();
+    } else {
+      return MouseButton::button(code - BTN_MOUSE);
+    }
+  }
+
+  switch (code) {
+  case BTN_A:
+    return GamepadButton::action_a();
+
+  case BTN_B:
+    return GamepadButton::action_b();
+
+  case BTN_C:
+    return GamepadButton::action_c();
+
+  case BTN_X:
+    return GamepadButton::action_x();
+
+  case BTN_Y:
+    return GamepadButton::action_y();
+
+  case BTN_Z:
+    return GamepadButton::action_z();
+
+  case BTN_TL:
+    return GamepadButton::lshoulder();
+
+  case BTN_TR:
+    return GamepadButton::rshoulder();
+
+  case BTN_TL2:
+    return GamepadButton::ltrigger();
+
+  case BTN_TR2:
+    return GamepadButton::rtrigger();
+
+  case BTN_SELECT:
+    return GamepadButton::back();
+
+  case BTN_START:
+    return GamepadButton::start();
+
+  case BTN_MODE:
+    return GamepadButton::guide();
+
+  case BTN_THUMBL:
+    return GamepadButton::lstick();
+
+  case BTN_THUMBR:
+    return GamepadButton::rstick();
+
+  case BTN_TRIGGER_HAPPY1:
+    return GamepadButton::dpad_left();
+
+  case BTN_TRIGGER_HAPPY2:
+    return GamepadButton::dpad_right();
+
+  case BTN_TRIGGER_HAPPY3:
+    return GamepadButton::dpad_up();
+
+  case BTN_TRIGGER_HAPPY4:
+    return GamepadButton::dpad_down();
+
+  default:
+    return ButtonHandle::none();
+  }
+}
+
+#endif

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

@@ -0,0 +1,63 @@
+// Filename: evdevInputDevice.h
+// Created by:  rdb (24Aug15)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef EVDEVINPUTDEVICE_H
+#define EVDEVINPUTDEVICE_H
+
+#include "inputDevice.h"
+
+#ifdef PHAVE_LINUX_INPUT_H
+
+////////////////////////////////////////////////////////////////////
+//       Class : EvdevInputDevice
+// Description : This is a type of device that uses the Linux
+//               /dev/input/event# API to read data from a raw mouse.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA_DEVICE EvdevInputDevice : public InputDevice {
+PUBLISHED:
+  EvdevInputDevice(int fd);
+  EvdevInputDevice(const string &device);
+  virtual ~EvdevInputDevice();
+
+private:
+  virtual void do_poll();
+
+  bool init_device();
+  bool process_events();
+
+private:
+  int _fd;
+
+public:
+  static ButtonHandle map_button(int code);
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    InputDevice::init_type();
+    register_type(_type_handle, "EvdevInputDevice",
+                  InputDevice::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "evdevInputDevice.I"
+
+#endif  // PHAVE_LINUX_INPUT_H
+
+#endif  // EVDEVINPUTDEVICE_H

+ 445 - 0
panda/src/device/inputDevice.I

@@ -0,0 +1,445 @@
+// Filename: inputDevice.I
+// Created by:  drose (24May00)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::Default Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE InputDevice::
+InputDevice() :
+  _flags(0),
+  _device_class(DC_unknown),
+  _is_connected(false),
+  _event_sequence(0),
+  _enable_pointer_events(false),
+  _battery_level(-1),
+  _max_battery_level(-1)
+{
+  _button_events = new ButtonEventList;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::get_name
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE string InputDevice::
+get_name() const {
+  LightMutexHolder holder(_lock);
+  return _name;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::is_connected
+//       Access: Public
+//  Description: Returns true if the device is still connected and
+//               able to receive data, false otherwise.  May return
+//               false positives.
+////////////////////////////////////////////////////////////////////
+INLINE bool InputDevice::
+is_connected() const {
+  LightMutexHolder holder(_lock);
+  return _is_connected;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::get_device_class
+//       Access: Public
+//  Description: Returns an identification of the general type of
+//               device.  If this could not be determined, returns
+//               DC_unknown.
+////////////////////////////////////////////////////////////////////
+INLINE InputDevice::DeviceClass InputDevice::
+get_device_class() const {
+  LightMutexHolder holder(_lock);
+  return _device_class;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::has_pointer
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool InputDevice::
+has_pointer() const {
+  LightMutexHolder holder(_lock);
+  return ((_flags & IDF_has_pointer) != 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::has_keyboard
+//       Access: Public
+//  Description: Returns true if the device has a physical keyboard
+//               designed for text entry.
+////////////////////////////////////////////////////////////////////
+INLINE bool InputDevice::
+has_keyboard() const {
+  LightMutexHolder holder(_lock);
+  return ((_flags & IDF_has_keyboard) != 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::has_tracker
+//       Access: Public
+//  Description: Returns true if the device features a tracker that
+//               can track position and/or orientation in 3D space.
+////////////////////////////////////////////////////////////////////
+INLINE bool InputDevice::
+has_tracker() const {
+  LightMutexHolder holder(_lock);
+  return ((_flags & IDF_has_tracker) != 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::has_battery
+//       Access: Public
+//  Description: Returns true if the device may be able to provide
+//               information about its battery life.
+////////////////////////////////////////////////////////////////////
+INLINE bool InputDevice::
+has_battery() const {
+  LightMutexHolder holder(_lock);
+  return ((_flags & IDF_has_battery) != 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::has_axis
+//       Access: Public
+//  Description: Returns true if the device has the given axis.
+////////////////////////////////////////////////////////////////////
+/*
+INLINE bool InputDevice::
+has_axis(Axis axis) const {
+  LightMutexHolder holder(_lock);
+  return ((_has_axes & (1 << axis)) != 0);
+}*/
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::get_pointer
+//       Access: Public
+//  Description: Returns the PointerData associated with the input
+//               device's pointer.  This only makes sense if
+//               has_pointer() also returns true.
+////////////////////////////////////////////////////////////////////
+INLINE PointerData InputDevice::
+get_pointer() const {
+  LightMutexHolder holder(_lock);
+  return _pointer_data;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::get_tracker
+//       Access: Public
+//  Description: Returns the TrackerData associated with the input
+//               device's tracker.  This only makes sense if
+//               has_tracker() also returns true.
+////////////////////////////////////////////////////////////////////
+INLINE TrackerData InputDevice::
+get_tracker() const {
+  LightMutexHolder holder(_lock);
+  return _tracker_data;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::get_battery_level
+//       Access: Public
+//  Description: 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.
+////////////////////////////////////////////////////////////////////
+INLINE short InputDevice::
+get_battery_level() const {
+  LightMutexHolder holder(_lock);
+  return _battery_level;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::get_max_battery_level
+//       Access: Public
+//  Description: 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;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::get_num_buttons
+//       Access: Public
+//  Description: Returns the number of buttons known to the
+//               ClientButtonDevice.  This includes those buttons
+//               whose state has been seen, as well as buttons that
+//               have been associated with a ButtonHandle even if
+//               their state is unknown.  This number may change as
+//               more buttons are discovered.
+////////////////////////////////////////////////////////////////////
+INLINE int InputDevice::
+get_num_buttons() const {
+  LightMutexHolder holder(_lock);
+  return _buttons.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::set_button_map
+//       Access: Public
+//  Description: Associates the indicated ButtonHandle with the button
+//               of the indicated index number.  When the given button
+//               index changes state, a corresponding ButtonEvent will
+//               be generated with the given ButtonHandle.  Pass
+//               ButtonHandle::none() to turn off any association.
+//
+//               It is not necessary to call this if you simply want
+//               to query the state of the various buttons by index
+//               number; this is only necessary in order to generate
+//               ButtonEvents when the buttons change state.
+////////////////////////////////////////////////////////////////////
+INLINE void InputDevice::
+set_button_map(int index, ButtonHandle button) {
+  LightMutexHolder holder(_lock);
+  nassertv(index >= 0);
+  if (index >= (int)_buttons.size()) {
+    _buttons.resize(index + 1, ButtonState());
+  }
+
+  _buttons[index]._handle = button;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::get_button_map
+//       Access: Public
+//  Description: 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 was associated.
+////////////////////////////////////////////////////////////////////
+INLINE ButtonHandle InputDevice::
+get_button_map(int index) const {
+  if (index >= 0 && index < (int)_buttons.size()) {
+    return _buttons[index]._handle;
+  } else {
+    return ButtonHandle::none();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::get_button_state
+//       Access: Public
+//  Description: Returns true if the indicated button (identified by
+//               its index number) is currently known to be down, or
+//               false if it is up or unknown.
+////////////////////////////////////////////////////////////////////
+INLINE bool InputDevice::
+get_button_state(int index) const {
+  if (index >= 0 && index < (int)_buttons.size()) {
+    return (_buttons[index]._state == S_down);
+  } else {
+    return false;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::is_button_known
+//       Access: Public
+//  Description: Returns true if the state of the indicated button is
+//               known, or false if we have never heard anything about
+//               this particular button.
+////////////////////////////////////////////////////////////////////
+INLINE bool InputDevice::
+is_button_known(int index) const {
+  if (index >= 0 && index < (int)_buttons.size()) {
+    return _buttons[index]._state != S_unknown;
+  } else {
+    return false;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::get_num_controls
+//       Access: Public
+//  Description: Returns the number of analog controls known to the
+//               InputDevice.  This number may change as
+//               more controls are discovered.
+////////////////////////////////////////////////////////////////////
+INLINE int InputDevice::
+get_num_controls() const {
+  return _controls.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::set_control_map
+//       Access: Public
+//  Description: Associates the indicated ControlAxis with the
+//               control of the indicated index number.  Pass
+//               C_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.
+////////////////////////////////////////////////////////////////////
+INLINE void InputDevice::
+set_control_map(int index, ControlAxis axis) {
+  LightMutexHolder holder(_lock);
+  nassertv(index >= 0);
+  if (index >= (int)_controls.size()) {
+    _controls.resize(index + 1, AnalogState());
+  }
+
+  _controls[index]._axis = axis;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::get_control_map
+//       Access: Public
+//  Description: Returns the ControlAxis that was previously
+//               associated with the given index number by
+//               a call to set_control_map(), or C_none
+//               if no control was associated.
+////////////////////////////////////////////////////////////////////
+INLINE InputDevice::ControlAxis InputDevice::
+get_control_map(int index) const {
+  if (index >= 0 && index < (int)_controls.size()) {
+    return _controls[index]._axis;
+  } else {
+    return C_none;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::get_control_state
+//       Access: Public
+//  Description: 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.
+////////////////////////////////////////////////////////////////////
+INLINE double InputDevice::
+get_control_state(int index) const {
+  if (index >= 0 && index < (int)_controls.size()) {
+    return _controls[index]._state;
+  } else {
+    return 0.0;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::is_control_known
+//       Access: Public
+//  Description: Returns true if the state of the indicated analog
+//               control is known, or false if we have never heard
+//               anything about this particular control.
+////////////////////////////////////////////////////////////////////
+INLINE bool InputDevice::
+is_control_known(int index) const {
+  if (index >= 0 && index < (int)_controls.size()) {
+    return _controls[index]._known;
+  } else {
+    return false;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::enable_pointer_events
+//       Access: Public
+//  Description: Enables the generation of mouse-movement events.
+////////////////////////////////////////////////////////////////////
+INLINE void InputDevice::
+enable_pointer_events() {
+  LightMutexHolder holder(_lock);
+  _enable_pointer_events = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::disable_pointer_events
+//       Access: Public
+//  Description: Disables the generation of mouse-movement events.
+////////////////////////////////////////////////////////////////////
+INLINE void InputDevice::
+disable_pointer_events() {
+  LightMutexHolder holder(_lock);
+  _enable_pointer_events = false;
+  _pointer_events.clear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::set_connected
+//       Access: Protected
+//  Description: Called to indicate that the device has been
+//               disconnected or connected from its host.
+////////////////////////////////////////////////////////////////////
+INLINE void InputDevice::
+set_connected(bool connected) {
+  LightMutexHolder holder(_lock);
+  _is_connected = connected;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::operator ==
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool InputDevice::
+operator == (const InputDevice &) const {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::operator !=
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool InputDevice::
+operator != (const InputDevice &) const {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::operator <
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool InputDevice::
+operator < (const InputDevice &) const {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::ButtonState::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE InputDevice::ButtonState::
+ButtonState() :
+  _handle(ButtonHandle::none()),
+  _state(S_unknown)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::AnalogState::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE InputDevice::AnalogState::
+AnalogState() :
+  _axis(C_none),
+  _state(0.0),
+  _known(false)
+{
+}

+ 517 - 0
panda/src/device/inputDevice.cxx

@@ -0,0 +1,517 @@
+// Filename: inputDevice.cxx
+// Created by:  drose (24May00)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "inputDevice.h"
+
+TypeHandle InputDevice::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::Constructor
+//       Access: Private
+//  Description: Defines a new InputDevice for the window.  Most
+//               windows will have exactly one InputDevice: a
+//               keyboard/mouse pair.  Some may also add joystick
+//               data, or additional mice or something.
+//
+//               This private constructor is only used internally by
+//               the named constructors, below.
+////////////////////////////////////////////////////////////////////
+InputDevice::
+InputDevice(const string &name, DeviceClass dev_class, int flags) :
+  _name(name),
+  _flags(flags),
+  _device_class(dev_class),
+  _is_connected(true),
+  _event_sequence(0),
+  _enable_pointer_events(false),
+  _battery_level(-1),
+  _max_battery_level(-1)
+{
+  _button_events = new ButtonEventList;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+InputDevice::
+InputDevice(const InputDevice &copy) {
+  *this = copy;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::Copy Assignment Operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+void InputDevice::
+operator = (const InputDevice &copy) {
+  LightMutexHolder holder(_lock);
+  LightMutexHolder holder1(copy._lock);
+  _name = copy._name;
+  _flags = copy._flags;
+  _is_connected = copy._is_connected;
+  _event_sequence = copy._event_sequence;
+  _enable_pointer_events = copy._enable_pointer_events;
+  _pointer_data = copy._pointer_data;
+  _button_events = copy._button_events;
+  _pointer_events = copy._pointer_events;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+InputDevice::
+~InputDevice() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::poll
+//       Access: Public, Virtual
+//  Description: Polls the input device for new activity, to ensure
+//               it contains the latest events.  This will only have
+//               any effect for some types of input devices; others
+//               may be updated automatically, and this method will
+//               be a no-op.
+////////////////////////////////////////////////////////////////////
+void InputDevice::
+poll() {
+  LightMutexHolder holder(_lock);
+  do_poll();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::has_button_event
+//       Access: Public
+//  Description: Returns true if this device has a pending button
+//               event (a mouse button or keyboard button down/up),
+//               false otherwise.  If this returns true, the
+//               particular event may be extracted via
+//               get_button_event().
+////////////////////////////////////////////////////////////////////
+bool InputDevice::
+has_button_event() const {
+  LightMutexHolder holder(_lock);
+  return !_button_events.is_null() && _button_events->get_num_events() > 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::get_button_events
+//       Access: Public
+//  Description: Returns the list of recently-generated ButtonEvents.
+//               The list is also cleared.
+////////////////////////////////////////////////////////////////////
+PT(ButtonEventList) InputDevice::
+get_button_events() {
+  LightMutexHolder holder(_lock);
+  PT(ButtonEventList) result = new ButtonEventList;
+  swap(_button_events, result);
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::has_pointer_event
+//       Access: Public
+//  Description: Returns true if this device has a pending pointer
+//               event (a mouse movement), or false otherwise.  If
+//               this returns true, the particular event may be
+//               extracted via get_pointer_event().
+////////////////////////////////////////////////////////////////////
+bool InputDevice::
+has_pointer_event() const {
+  LightMutexHolder holder(_lock);
+  return (_pointer_events != 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::get_pointer_events
+//       Access: Public
+//  Description: Returns a PointerEventList containing all the recent
+//               pointer events.  Clears the list.
+////////////////////////////////////////////////////////////////////
+PT(PointerEventList) InputDevice::
+get_pointer_events() {
+  LightMutexHolder holder(_lock);
+  PT(PointerEventList) result = _pointer_events;
+  _pointer_events.clear();
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::set_pointer
+//       Access: Protected
+//  Description: Records that a mouse movement has taken place.
+////////////////////////////////////////////////////////////////////
+void InputDevice::
+set_pointer(bool inwin, double x, double y, double time) {
+  nassertv(_lock.debug_is_locked());
+  _pointer_data._in_window = inwin;
+  _pointer_data._xpos = x;
+  _pointer_data._ypos = y;
+
+  if (_enable_pointer_events) {
+    int seq = _event_sequence++;
+    if (_pointer_events.is_null()) {
+      _pointer_events = new PointerEventList();
+    }
+    _pointer_events->add_event(_pointer_data._in_window,
+                               _pointer_data._xpos,
+                               _pointer_data._ypos,
+                               seq, time);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::set_pointer_out_of_window
+//       Access: Protected
+//  Description: Records that the mouse pointer has left the window.
+////////////////////////////////////////////////////////////////////
+void InputDevice::
+set_pointer_out_of_window(double time) {
+  nassertv(_lock.debug_is_locked());
+  _pointer_data._in_window = false;
+
+  if (_enable_pointer_events) {
+    int seq = _event_sequence++;
+    if (_pointer_events.is_null()) {
+      _pointer_events = new PointerEventList();
+    }
+    _pointer_events->add_event(_pointer_data._in_window,
+                               _pointer_data._xpos,
+                               _pointer_data._ypos,
+                               seq, time);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::set_button_state
+//       Access: Protected
+//  Description: Sets the state of the indicated button index, where
+//               true indicates down, and false indicates up.  This
+//               may generate a ButtonEvent if the button has an
+//               associated ButtonHandle.  The caller should ensure
+//               that acquire() is in effect while this call is made.
+////////////////////////////////////////////////////////////////////
+void InputDevice::
+set_button_state(int index, bool down) {
+  nassertv(_lock.debug_is_locked());
+  nassertv(index >= 0);
+  if (index >= (int)_buttons.size()) {
+    _buttons.resize(index + 1, ButtonState());
+  }
+
+  _buttons[index]._state = down ? S_down : S_up;
+
+  ButtonHandle handle = _buttons[index]._handle;
+  if (handle != ButtonHandle::none()) {
+    _button_events->add_event(ButtonEvent(handle, down ? ButtonEvent::T_down : ButtonEvent::T_up));
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::set_control_state
+//       Access: Protected
+//  Description: Sets the state of the indicated analog index.  The
+//               caller should ensure that acquire() is in effect 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.
+////////////////////////////////////////////////////////////////////
+void InputDevice::
+set_control_state(int index, double state) {
+  nassertv(_lock.debug_is_locked());
+  nassertv(index >= 0);
+  if (index >= (int)_controls.size()) {
+    _controls.resize(index + 1, AnalogState());
+  }
+
+  _controls[index]._state = state;
+  _controls[index]._known = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::set_tracker
+//       Access: Protected
+//  Description: Records that a tracker movement has taken place.
+////////////////////////////////////////////////////////////////////
+void InputDevice::
+set_tracker(const LPoint3 &pos, const LOrientation &orient, double time) {
+  nassertv(_lock.debug_is_locked());
+
+  _tracker_data.set_pos(pos);
+  _tracker_data.set_orient(orient);
+  _tracker_data.set_time(time);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::output
+//       Access: Public
+//  Description: Writes a one-line string describing the device.
+////////////////////////////////////////////////////////////////////
+void InputDevice::
+output(ostream &out) const {
+  LightMutexHolder holder(_lock);
+
+  out << _name << " (";
+
+  if (!_is_connected) {
+    out << "dis";
+  }
+
+  out << "connected)";
+
+  if (_device_class != DC_unknown) {
+    out << ", " << _device_class;
+  }
+
+  if (_buttons.size() > 0) {
+    out << ", " << _buttons.size() << " buttons";
+  }
+
+  if (_controls.size() > 0) {
+    out << ", " << _controls.size() << " controls";
+  }
+
+  if (_flags & IDF_has_pointer) {
+    out << ", pointer";
+  }
+  if (_flags & IDF_has_keyboard) {
+    out << ", keyboard";
+  }
+  if (_flags & IDF_has_tracker) {
+    out << ", tracker";
+  }
+  if (_flags & IDF_has_vibration) {
+    out << ", vibration";
+  }
+  if (_flags & IDF_has_battery) {
+    out << ", battery";
+
+    if (_battery_level > 0 && _max_battery_level > 0) {
+      out << " [";
+      short i = 0;
+      for (; i < _battery_level - 1; ++i) {
+        out << '=';
+      }
+      out << '/';
+      for (; i < _max_battery_level; ++i) {
+        out << ' ';
+      }
+      out << ']';
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::output_buttons
+//       Access: Public
+//  Description: Writes a one-line string of all of the current button
+//               states.
+////////////////////////////////////////////////////////////////////
+void InputDevice::
+output_buttons(ostream &out) const {
+  LightMutexHolder holder(_lock);
+
+  bool any_buttons = false;
+  Buttons::const_iterator bi;
+  for (bi = _buttons.begin(); bi != _buttons.end(); ++bi) {
+    const ButtonState &state = (*bi);
+    if (state._state != S_unknown) {
+      if (any_buttons) {
+        out << ", ";
+      }
+      any_buttons = true;
+      out << (int)(bi - _buttons.begin()) << "=";
+      if (state._state == S_up) {
+        out << "up";
+      } else {
+        out << "down";
+      }
+    }
+  }
+
+  if (!any_buttons) {
+    out << "no known buttons";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::write_buttons
+//       Access: Public
+//  Description: Writes a multi-line description of the current button
+//               states.
+////////////////////////////////////////////////////////////////////
+void InputDevice::
+write_buttons(ostream &out, int indent_level) const {
+  bool any_buttons = false;
+  Buttons::const_iterator bi;
+  for (bi = _buttons.begin(); bi != _buttons.end(); ++bi) {
+    const ButtonState &state = (*bi);
+    if (state._state != S_unknown) {
+      any_buttons = true;
+
+      indent(out, indent_level)
+        << (int)(bi - _buttons.begin()) << ". ";
+
+      if (state._handle != ButtonHandle::none()) {
+        out << "(" << state._handle << ") ";
+      }
+
+      if (state._state == S_up) {
+        out << "up";
+      } else {
+        out << "down";
+      }
+      out << "\n";
+    }
+  }
+
+  if (!any_buttons) {
+    indent(out, indent_level)
+      << "(no known buttons)\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::write_controls
+//       Access: Public
+//  Description: Writes a multi-line description of the current analog
+//               control states.
+////////////////////////////////////////////////////////////////////
+void InputDevice::
+write_controls(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);
+    if (state._known) {
+      any_controls = true;
+
+      indent(out, indent_level)
+        << (int)(ai - _controls.begin()) << ". " << state._state << "\n";
+    }
+  }
+
+  if (!any_controls) {
+    indent(out, indent_level)
+      << "(no known analog controls)\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDevice::do_poll
+//       Access: Protected, Virtual
+//  Description: Polls the input device for new activity, to ensure
+//               it contains the latest events.  This will only have
+//               any effect for some types of input devices; others
+//               may be updated automatically, and this method will
+//               be a no-op.
+////////////////////////////////////////////////////////////////////
+void InputDevice::
+do_poll() {
+}
+
+ostream &
+operator << (ostream &out, InputDevice::DeviceClass dc) {
+  switch (dc) {
+  case InputDevice::DC_unknown:
+    out << "unknown";
+    break;
+
+  case InputDevice::DC_virtual:
+    out << "virtual";
+    break;
+
+  case InputDevice::DC_keyboard:
+    out << "keyboard";
+    break;
+
+  case InputDevice::DC_mouse:
+    out << "mouse";
+    break;
+
+  case InputDevice::DC_touch:
+    out << "touch";
+    break;
+
+  case InputDevice::DC_gamepad:
+    out << "gamepad";
+    break;
+
+  case InputDevice::DC_flight_stick:
+    out << "flight_stick";
+    break;
+
+  case InputDevice::DC_steering_wheel:
+    out << "steering_wheel";
+    break;
+  }
+  return out;
+}
+
+ostream &
+operator << (ostream &out, InputDevice::ControlAxis axis) {
+  switch (axis) {
+  case InputDevice::C_none:
+    out << "none";
+    break;
+
+  case InputDevice::C_left_x:
+    out << "left_x";
+    break;
+
+  case InputDevice::C_left_y:
+    out << "left_y";
+    break;
+
+  case InputDevice::C_left_trigger:
+    out << "left_trigger";
+    break;
+
+  case InputDevice::C_right_x:
+    out << "right_x";
+    break;
+
+  case InputDevice::C_right_y:
+    out << "right_y";
+    break;
+
+  case InputDevice::C_right_trigger:
+    out << "right_trigger";
+    break;
+
+  case InputDevice::C_x:
+    out << "x";
+    break;
+
+  case InputDevice::C_y:
+    out << "y";
+    break;
+
+  case InputDevice::C_trigger:
+    out << "trigger";
+    break;
+
+  case InputDevice::C_throttle:
+    out << "throttle";
+    break;
+  }
+
+  return out;
+}

+ 279 - 0
panda/src/device/inputDevice.h

@@ -0,0 +1,279 @@
+// Filename: inputDevice.h
+// Created by:  drose (24May00)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef INPUTDEVICE_H
+#define INPUTDEVICE_H
+
+#include "pandabase.h"
+
+#include "buttonEvent.h"
+#include "buttonEventList.h"
+#include "pointerEvent.h"
+#include "pointerEventList.h"
+#include "mouseData.h"
+#include "trackerData.h"
+#include "clockObject.h"
+
+#include "pdeque.h"
+#include "pvector.h"
+#include "lightMutex.h"
+#include "lightMutexHolder.h"
+
+typedef MouseData PointerData;
+
+////////////////////////////////////////////////////////////////////
+//       Class : InputDevice
+// Description : This is a structure representing a single input
+//               device.  Input devices may have zero or more
+//               buttons, pointers, or controls associated with them,
+//               and optionally a 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 subclasses.
+//
+//               Use the various has_() and get_num_() methods to
+//               determine information about the device capabilities.
+//               For instance, has_keyboard() will give an indication
+//               that you can receive keystroke events from this
+//               device, and get_num_buttons() will tell you that
+//               the device may send button events.
+//
+//               There is the DeviceType enumeration, however, which
+//               will (if known) contain identification about the
+//               general category of devices this fits in, such as
+//               keyboard, mouse, gamepad, or flight stick.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA_DEVICE InputDevice : public TypedReferenceCount {
+PUBLISHED:
+  // This enum contains information that can be used to identify the
+  // type of input device.
+  enum DeviceClass {
+    DC_unknown,
+
+    // This means that the device doesn't correspond to a physical
+    // device, but rather to a dynamic source of input events.
+    DC_virtual,
+
+    // A physical, alphabetical keyboard.
+    DC_keyboard,
+
+    DC_mouse,
+    DC_touch,
+
+    // A gamepad with action buttons, a D-pad, and thumbsticks.
+    DC_gamepad,
+
+    DC_flight_stick,
+    DC_steering_wheel,
+  };
+
+protected:
+  InputDevice(const string &name, DeviceClass dev_class, int flags);
+
+public:
+  InputDevice();
+  InputDevice(const InputDevice &copy);
+  void operator = (const InputDevice &copy);
+  ~InputDevice();
+
+PUBLISHED:
+  enum ControlAxis {
+    C_none,
+
+    // Gamepad
+    C_left_x,
+    C_left_y,
+    C_left_trigger,
+    C_right_x,
+    C_right_y,
+    C_right_trigger,
+
+    // Flight stick
+    C_x,
+    C_y,
+    C_trigger,
+    C_throttle,
+  };
+
+  INLINE string get_name() const;
+  INLINE bool is_connected() const;
+  INLINE DeviceClass get_device_class() const;
+
+  // The human-readable name of this input device.
+  MAKE_PROPERTY(name, get_name);
+
+  // This is false if we know that the device is not currently connected.
+  // May report false positives if we can't know this with certainty.
+  MAKE_PROPERTY(connected, is_connected);
+
+  // This contains an identification of the general type of device.  If
+  // this could not be determined, it is set to DC_unknown.
+  MAKE_PROPERTY(device_class, get_device_class);
+
+  INLINE bool has_pointer() const;
+  INLINE bool has_keyboard() const;
+  INLINE bool has_tracker() 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;
+
+  INLINE int get_num_buttons() const;
+  INLINE void set_button_map(int index, ButtonHandle button);
+  INLINE ButtonHandle get_button_map(int index) const;
+  INLINE bool get_button_state(int index) const;
+  INLINE bool is_button_known(int index) const;
+
+  INLINE int get_num_controls() const;
+  INLINE void set_control_map(int index, ControlAxis axis);
+  INLINE ControlAxis get_control_map(int index) const;
+  INLINE double get_control_state(int index) const;
+  INLINE bool is_control_known(int index) const;
+
+  INLINE void enable_pointer_events();
+  INLINE void disable_pointer_events();
+
+  void poll();
+
+  bool has_button_event() const;
+  PT(ButtonEventList) get_button_events();
+  bool has_pointer_event() const;
+  PT(PointerEventList) get_pointer_events();
+
+  virtual void output(ostream &out) const;
+
+protected:
+  void set_pointer(bool inwin, double x, double y, double time);
+  void set_pointer_out_of_window(double time);
+  void set_button_state(int index, bool down);
+  void set_control_state(int index, double state);
+  void set_tracker(const LPoint3 &pos, const LOrientation &orient, double time);
+
+  virtual void do_poll();
+
+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(ostream &out) const;
+  void write_buttons(ostream &out, int indent_level) const;
+  void write_controls(ostream &out, int indent_level) const;
+
+protected:
+  enum InputDeviceFlags {
+    // The device provides absolute screen coordinates.
+    IDF_has_pointer    = 0x01,
+
+    // The device has an interface for providing text input.
+    IDF_has_keyboard   = 0x02,
+
+    // The device has a motion tracker, such as an HMD.
+    IDF_has_tracker    = 0x04,
+
+    // The device can produce force feedback.
+    IDF_has_vibration  = 0x08,
+
+    // The device provides information about battery life.
+    IDF_has_battery    = 0x10,
+  };
+
+protected:
+  typedef pdeque<ButtonEvent> ButtonEvents;
+
+  LightMutex _lock;
+
+  string _name;
+  DeviceClass _device_class;
+  int _flags;
+  int _event_sequence;
+  bool _is_connected;
+  bool _enable_pointer_events;
+  PointerData _pointer_data;
+  PT(ButtonEventList) _button_events;
+  PT(PointerEventList) _pointer_events;
+
+public:
+  enum State {
+    S_unknown,
+    S_up,
+    S_down
+  };
+
+  class ButtonState {
+  public:
+    INLINE ButtonState();
+
+    ButtonHandle _handle;
+    State _state;
+  };
+  typedef pvector<ButtonState> Buttons;
+  Buttons _buttons;
+
+  class AnalogState {
+  public:
+    INLINE AnalogState();
+
+    ControlAxis _axis;
+    double _state;
+    bool _known;
+  };
+  typedef pvector<AnalogState> Controls;
+  Controls _controls;
+
+  short _battery_level;
+  short _max_battery_level;
+
+  TrackerData _tracker_data;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TypedReferenceCount::init_type();
+    register_type(_type_handle, "InputDevice",
+                  TypedReferenceCount::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+INLINE ostream &operator << (ostream &out, const InputDevice &device) {
+  device.output(out);
+  return out;
+}
+
+ostream &operator << (ostream &out, InputDevice::DeviceClass dc);
+ostream &operator << (ostream &out, InputDevice::ControlAxis axis);
+
+#include "inputDevice.I"
+
+#endif

+ 27 - 0
panda/src/device/inputDeviceManager.I

@@ -0,0 +1,27 @@
+// Filename: inputDeviceManager.I
+// Created by:  rdb (09Dec15)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDeviceManager::get_global_ptr
+//       Access: Published, Static
+//  Description: Returns the singleton instance.
+////////////////////////////////////////////////////////////////////
+INLINE InputDeviceManager *InputDeviceManager::
+get_global_ptr() {
+  if (_global_ptr == (InputDeviceManager *)NULL) {
+    _global_ptr = new InputDeviceManager;
+  }
+  return _global_ptr;
+}

+ 240 - 0
panda/src/device/inputDeviceManager.cxx

@@ -0,0 +1,240 @@
+// Filename: inputDeviceManager.cxx
+// Created by:  rdb (09Dec15)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "inputDeviceManager.h"
+#include "linuxJoystickDevice.h"
+#include "throw_event.h"
+
+#ifdef PHAVE_LINUX_INPUT_H
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/inotify.h>
+#include <sys/ioctl.h>
+#endif
+
+InputDeviceManager *InputDeviceManager::_global_ptr = NULL;
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDeviceManager::Constructor
+//       Access: Private
+//  Description:
+////////////////////////////////////////////////////////////////////
+InputDeviceManager::
+InputDeviceManager() : _inotify_fd(-1) {
+#ifdef PHAVE_LINUX_INPUT_H
+  // Scan /dev/input for a list of input devices.
+  DIR *dir = opendir("/dev/input");
+  if (dir) {
+    dirent *entry = readdir(dir);
+    while (entry != NULL) {
+      if (entry->d_type == DT_CHR) {
+        string name(entry->d_name);
+        if (!consider_add_linux_device(name)) {
+          // We can't access it.  That's pretty normal for most devices.
+          if (device_cat.is_debug()) {
+            device_cat.debug()
+              << "Ignoring input device /dev/input/" << name << ": "
+              << strerror(errno) << "\n";
+          }
+          errno = 0;
+        }
+      }
+      entry = readdir(dir);
+    }
+    closedir(dir);
+  } else {
+    device_cat.error()
+      << "Error opening directory /dev/input: " << strerror(errno) << "\n";
+    return;
+  }
+
+  // Use inotify to watch /dev/input for hotplugging of devices.
+  _inotify_fd = inotify_init1(O_NONBLOCK);
+
+  if (_inotify_fd < 0) {
+    device_cat.error()
+      << "Error initializing inotify: " << strerror(errno) << "\n";
+
+  } else if (inotify_add_watch(_inotify_fd, "/dev/input", IN_CREATE | IN_ATTRIB | IN_DELETE) < 0) {
+    device_cat.error()
+      << "Error adding inotify watch on /dev/input: " << strerror(errno) << "\n";
+  }
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDeviceManager::Destructor
+//       Access: Private
+//  Description:
+////////////////////////////////////////////////////////////////////
+InputDeviceManager::
+~InputDeviceManager() {
+#ifdef PHAVE_LINUX_INPUT_H
+  if (_inotify_fd >= 0) {
+    close(_inotify_fd);
+    _inotify_fd = -1;
+  }
+#endif
+}
+
+#ifdef PHAVE_LINUX_INPUT_H
+////////////////////////////////////////////////////////////////////
+//     Function: InputDeviceManager::consider_add_linux_device
+//       Access: Private
+//  Description: Checks whether the given device is accessible, and
+//               if so, adds it.  Returns false on error.
+////////////////////////////////////////////////////////////////////
+bool InputDeviceManager::
+consider_add_linux_device(const string &name) {
+  // Get the full path name first.
+  string path = "/dev/input/";
+  path += name;
+
+  if (access(path.c_str(), R_OK) < 0) {
+    return false;
+  }
+
+  if (_devices_by_path.count(name)) {
+    // We already have this device.
+    return true;
+  }
+
+  // Check if it's a joystick or game controller device.
+  if (name.size() > 2 && name[0] == 'j' && name[1] == 's' && isdigit(name[2])) {
+    PT(InputDevice) device = new LinuxJoystickDevice(path);
+    if (device_cat.is_info()) {
+      device_cat.info()
+        << "Discovered input device " << *device << "\n";
+    }
+
+    _devices_by_path[name] = device;
+    _all_devices.push_back(MOVE(device));
+    return true;
+  }
+
+  return true;
+}
+#endif
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDeviceManager::add_device
+//       Access: Public
+//  Description: Called when a new device has been discovered.
+////////////////////////////////////////////////////////////////////
+void InputDeviceManager::
+add_device(InputDevice *device) {
+  {
+    LightMutexHolder holder(_lock);
+    _all_devices.push_back(device);
+  }
+  throw_event("device-added", device);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDeviceManager::remove_device
+//       Access: Public
+//  Description: Called when a device has been removed.
+////////////////////////////////////////////////////////////////////
+void InputDeviceManager::
+remove_device(InputDevice *device) {
+  {
+    LightMutexHolder holder(_lock);
+
+    InputDevices::iterator it;
+    it = std::find(_all_devices.begin(), _all_devices.end(), device);
+    nassertv_always(it != _all_devices.end());
+
+    _all_devices.erase(it);
+  }
+
+  throw_event("device-removed", device);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InputDeviceManager::poll
+//       Access: Public
+//  Description: Polls the system to see if there are any new devices.
+////////////////////////////////////////////////////////////////////
+void InputDeviceManager::
+poll() {
+#ifdef PHAVE_LINUX_INPUT_H
+  // We use inotify to tell us whether a device was added, removed,
+  // or has changed permissions to allow us to access it.
+  unsigned int avail;
+  ioctl(_inotify_fd, FIONREAD, &avail);
+  if (avail == 0) {
+    return;
+  }
+
+  char buffer[avail];
+  int n_read = read(_inotify_fd, buffer, avail);
+  if (n_read < 0) {
+    if (errno == EAGAIN || errno == EWOULDBLOCK) {
+      // No data available for now.
+
+    } else {
+      device_cat.error() << "read: " << strerror(errno) << "\n";
+    }
+    return;
+  }
+
+  LightMutexHolder holder(_lock);
+
+  // Iterate over the events in the buffer.
+  char *ptr = buffer;
+  char *end = buffer + avail;
+  while (ptr < end) {
+    inotify_event *event = (inotify_event *)ptr;
+
+    string name(event->name);
+
+    if (event->mask & IN_DELETE) {
+      // The device was deleted.  If we have it, remove it.
+      DevicesByPath::iterator it = _devices_by_path.find(name);
+      if (it != _devices_by_path.end()) {
+        PT(InputDevice) device = it->second;
+        device->set_connected(false);
+
+        InputDevices::iterator it2;
+        _devices_by_path.erase(it);
+        it2 = std::find(_all_devices.begin(), _all_devices.end(), device);
+        _all_devices.erase(it2);
+
+        if (device_cat.is_info()) {
+          device_cat.info()
+            << "Removed input device " << *device << "\n";
+        }
+        throw_event("device-removed", device.p());
+      }
+
+    } else if (event->mask & (IN_CREATE | IN_ATTRIB)) {
+      // The device was created, or it was chmodded to be accessible.
+      DevicesByPath::iterator it = _devices_by_path.find(name);
+      if (it == _devices_by_path.end()) {
+        // We don't know about this device yet.
+        if (!consider_add_linux_device(name) && (event->mask & IN_CREATE) != 0) {
+          if (device_cat.is_debug()) {
+            device_cat.debug()
+              << "Ignoring input device /dev/input/" << name << ": "
+              << strerror(errno) << "\n";
+          }
+        }
+        errno = 0;
+      }
+    }
+
+    ptr += sizeof(inotify_event) + event->len;
+  }
+#endif
+}

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

@@ -0,0 +1,64 @@
+// Filename: inputDeviceManager.h
+// Created by:  rdb (09Dec15)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef INPUTDEVICEMANAGER_H
+#define INPUTDEVICEMANAGER_H
+
+#include "pandabase.h"
+#include "lightMutex.h"
+#include "inputDevice.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : InputDeviceManager
+// Description : This class keeps track of all the devices on a
+//               system, and sends out events when a device has been
+//               hot-plugged.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA_DEVICE InputDeviceManager {
+private:
+  InputDeviceManager();
+  ~InputDeviceManager();
+
+#ifdef PHAVE_LINUX_INPUT_H
+  bool consider_add_linux_device(const string &name);
+#endif
+
+public:
+  void add_device(InputDevice *device);
+  void remove_device(InputDevice *device);
+
+PUBLISHED:
+  void poll();
+
+  INLINE static InputDeviceManager *get_global_ptr();
+
+private:
+  LightMutex _lock;
+
+#ifdef PHAVE_LINUX_INPUT_H
+  int _inotify_fd;
+
+  typedef pmap<string, InputDevice*> DevicesByPath;
+  DevicesByPath _devices_by_path;
+#endif
+
+  typedef pvector<PT(InputDevice)> InputDevices;
+  InputDevices _all_devices;
+
+  static InputDeviceManager *_global_ptr;
+};
+
+#include "inputDeviceManager.I"
+
+#endif

+ 14 - 0
panda/src/device/linuxJoystickDevice.I

@@ -0,0 +1,14 @@
+// Filename: linuxJoystickDevice.I
+// Created by:  rdb (21Aug15)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+

+ 313 - 0
panda/src/device/linuxJoystickDevice.cxx

@@ -0,0 +1,313 @@
+// Filename: linuxJoystickDevice.cxx
+// Created by:  rdb (21Aug15)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "linuxJoystickDevice.h"
+
+#ifdef PHAVE_LINUX_INPUT_H
+
+#include "gamepadButton.h"
+
+#include <fcntl.h>
+#include <linux/joystick.h>
+
+TypeHandle LinuxJoystickDevice::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: LinuxJoystickDevice::Constructor
+//       Access: Private
+//  Description: Creates a new device using the Linux joystick
+//               device using the given device filename.
+////////////////////////////////////////////////////////////////////
+LinuxJoystickDevice::
+LinuxJoystickDevice(const string &device) :
+  _fd(-1),
+  _device(device)
+{
+  LightMutexHolder holder(_lock);
+  if (!open_device()) {
+    device_cat.error()
+      << "Could not open joystick device " << _device
+      << ": " << strerror(errno) << "\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LinuxJoystickDevice::Destructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+LinuxJoystickDevice::
+~LinuxJoystickDevice() {
+  if (_fd != -1) {
+    close(_fd);
+    _fd = -1;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LinuxJoystickDevice::do_poll
+//       Access: Private, Virtual
+//  Description: Polls the input device for new activity, to ensure
+//               it contains the latest events.  This will only have
+//               any effect for some types of input devices; others
+//               may be updated automatically, and this method will
+//               be a no-op.
+////////////////////////////////////////////////////////////////////
+void LinuxJoystickDevice::
+do_poll() {
+  if (_fd != -1) {
+    while (process_events()) {}
+  } else {
+    open_device();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LinuxJoystickDevice::open_device
+//       Access: Private
+//  Description: Opens or reopens the joystick device, and reads out
+//               the button and axis mappings.
+//               Assumes the lock has been held.
+////////////////////////////////////////////////////////////////////
+bool LinuxJoystickDevice::
+open_device() {
+  nassertr(_lock.debug_is_locked(), false);
+
+  _fd = open(_device.c_str(), O_RDONLY | O_NONBLOCK);
+
+  if (_fd == -1) {
+    _is_connected = false;
+    return false;
+  }
+
+  // Read the name from the device.
+  char name[128];
+  name[0] = 0;
+  ioctl(_fd, JSIOCGNAME(sizeof(name)), name);
+  _name = name;
+
+  // Get the number of axes.
+  PN_uint8 num_axes = 0, num_buttons = 0;
+  ioctl(_fd, JSIOCGAXES, &num_axes);
+  ioctl(_fd, JSIOCGBUTTONS, &num_buttons);
+
+  _buttons.resize(num_buttons);
+  _controls.resize(num_axes);
+
+  if (num_buttons > 0) {
+    PN_uint16 btnmap[512];
+    ioctl(_fd, JSIOCGBTNMAP, btnmap);
+
+    for (char 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_SELECT:
+        handle = GamepadButton::back();
+        break;
+
+      case BTN_START:
+        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();
+        break;
+
+      case BTN_TRIGGER_HAPPY2:
+        handle = GamepadButton::dpad_right();
+        break;
+
+      case BTN_TRIGGER_HAPPY3:
+        handle = GamepadButton::dpad_up();
+        break;
+
+      case BTN_TRIGGER_HAPPY4:
+        handle = GamepadButton::dpad_down();
+        break;
+
+      default:
+        handle = ButtonHandle::none();
+        break;
+      }
+      _buttons[i]._handle = handle;
+    }
+  }
+
+  if (num_axes > 0) {
+    PN_uint8 axmap[512];
+    ioctl(_fd, JSIOCGAXMAP, axmap);
+
+    for (char i = 0; i < num_axes; ++i) {
+      ControlAxis axis = C_none;
+
+      switch (axmap[i]) {
+      case ABS_X:
+        if (_device_class == DC_gamepad) {
+          axis = C_left_x;
+        } else {
+          axis = C_x;
+        }
+        break;
+
+      case ABS_Y:
+        if (_device_class == DC_gamepad) {
+          axis = C_left_y;
+        } else {
+          axis = C_y;
+        }
+        break;
+
+      case ABS_Z:
+        if (_device_class == DC_gamepad) {
+          axis = C_left_trigger;
+        } else {
+          axis = C_trigger;
+        }
+        break;
+
+      case ABS_RX:
+        axis = C_right_x;
+        break;
+
+      case ABS_RY:
+        axis = C_right_y;
+        break;
+
+      case ABS_RZ:
+        axis = C_right_trigger;
+        break;
+
+      default:
+        axis = C_none;
+        break;
+      }
+      _controls[i]._axis = axis;
+    }
+  }
+
+  // Read the init events.
+  _is_connected = true;
+  while (process_events()) {};
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LinuxJoystickDevice::process_events
+//       Access: Private
+//  Description: Reads a number of events from the joystick.
+////////////////////////////////////////////////////////////////////
+bool LinuxJoystickDevice::
+process_events() {
+  // Read 8 events at a time.
+  struct js_event events[8];
+
+  int n_read = read(_fd, events, sizeof(events));
+  if (n_read < 0) {
+    if (errno == EAGAIN || errno == EWOULDBLOCK) {
+      // No data available for now.
+
+    } else if (errno == ENODEV) {
+      // The device ceased to exist, so we better close it.
+      close(_fd);
+      _fd = -1;
+      _is_connected = false;
+      errno = 0;
+
+    } else {
+      device_cat.error() << "read: " << strerror(errno) << "\n";
+    }
+    return false;
+  }
+
+  if (n_read == 0) {
+    return false;
+  }
+
+  n_read /= sizeof(struct js_event);
+
+  for (int i = 0; i < n_read; ++i) {
+    int index = events[i].number;
+
+    if (events[i].type & JS_EVENT_BUTTON) {
+      set_button_state(index, (events[i].value != 0));
+
+    } else if (events[i].type & JS_EVENT_AXIS) {
+      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 {
+        set_control_state(index, events[i].value / 32767.0);
+      }
+    }
+  }
+
+  return true;
+}
+
+#endif

+ 60 - 0
panda/src/device/linuxJoystickDevice.h

@@ -0,0 +1,60 @@
+// Filename: linuxJoystickDevice.h
+// Created by:  rdb (21Aug15)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef LINUXJOYSTICKDEVICE_H
+#define LINUXJOYSTICKDEVICE_H
+
+#include "inputDevice.h"
+
+#ifdef PHAVE_LINUX_INPUT_H
+
+////////////////////////////////////////////////////////////////////
+//       Class : LinuxJoystickDevice
+// Description : This is a type of device that uses the Linux
+//               /dev/input/js# API to read data from a game controller.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA_DEVICE LinuxJoystickDevice : public InputDevice {
+PUBLISHED:
+  LinuxJoystickDevice(const string &device);
+  virtual ~LinuxJoystickDevice();
+
+private:
+  virtual void do_poll();
+
+  bool open_device();
+  bool process_events();
+
+private:
+  int _fd;
+  string _device;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    InputDevice::init_type();
+    register_type(_type_handle, "LinuxJoystickDevice",
+                  InputDevice::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "linuxJoystickDevice.I"
+
+#endif  // PHAVE_LINUX_INPUT_H
+
+#endif  // LINUXJOYSTICKDEVICE_H

+ 4 - 1
panda/src/device/p3device_composite1.cxx

@@ -5,4 +5,7 @@
 #include "clientDevice.cxx"
 #include "clientDevice.cxx"
 #include "clientDialDevice.cxx"
 #include "clientDialDevice.cxx"
 #include "clientTrackerDevice.cxx"
 #include "clientTrackerDevice.cxx"
-
+#include "evdevInputDevice.cxx"
+#include "inputDevice.cxx"
+#include "inputDeviceManager.cxx"
+#include "linuxJoystickDevice.cxx"

+ 0 - 1
panda/src/device/p3device_composite2.cxx

@@ -3,7 +3,6 @@
 #include "analogNode.cxx"
 #include "analogNode.cxx"
 #include "buttonNode.cxx"
 #include "buttonNode.cxx"
 #include "dialNode.cxx"
 #include "dialNode.cxx"
-#include "mouseAndKeyboard.cxx"
 #include "trackerData.cxx"
 #include "trackerData.cxx"
 #include "trackerNode.cxx"
 #include "trackerNode.cxx"
 #include "virtualMouse.cxx"
 #include "virtualMouse.cxx"

+ 1 - 2
panda/src/device/trackerNode.I

@@ -20,10 +20,9 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool TrackerNode::
 INLINE bool TrackerNode::
 is_valid() const {
 is_valid() const {
-  return (_tracker != (ClientTrackerDevice *)NULL) && _tracker->is_connected();
+  return (!_tracker.is_null()/* && _tracker->is_connected()*/);
 }
 }
 
 
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: TrackerNode::get_pos
 //     Function: TrackerNode::get_pos
 //       Access: Public
 //       Access: Public

+ 9 - 10
panda/src/device/trackerNode.cxx

@@ -51,7 +51,7 @@ TrackerNode(ClientBase *client, const string &device_name) :
     return;
     return;
   }
   }
 
 
-  _tracker = DCAST(ClientTrackerDevice, device);
+  _tracker = device;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -60,18 +60,19 @@ TrackerNode(ClientBase *client, const string &device_name) :
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 TrackerNode::
 TrackerNode::
-TrackerNode(ClientTrackerDevice *device) :
-  DataNode(device->get_device_name()),
+TrackerNode(InputDevice *device) :
+  DataNode(device->get_name()),
   _tracker(device)
   _tracker(device)
 {
 {
   _transform_output = define_output("transform", TransformState::get_class_type());
   _transform_output = define_output("transform", TransformState::get_class_type());
 
 
   _transform = TransformState::make_identity();
   _transform = TransformState::make_identity();
 
 
-  nassertv(device != (ClientTrackerDevice *)NULL);
-  ClientBase *client = device->get_client();
-  nassertv(client != (ClientBase *)NULL);
-  set_tracker_coordinate_system(client->get_coordinate_system());
+  nassertv(device != (InputDevice *)NULL);
+  nassertv(device->has_tracker());
+
+  //TODO: get coordinate system from tracker object?
+  set_tracker_coordinate_system(CS_default);
   set_graph_coordinate_system(CS_default);
   set_graph_coordinate_system(CS_default);
 }
 }
 
 
@@ -105,9 +106,7 @@ do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &,
                  DataNodeTransmit &output) {
                  DataNodeTransmit &output) {
   if (is_valid()) {
   if (is_valid()) {
     _tracker->poll();
     _tracker->poll();
-    _tracker->acquire();
-    _data = _tracker->get_data();
-    _tracker->unlock();
+    _data = _tracker->get_tracker();
 
 
     _data.get_orient().extract_to_matrix(_mat);
     _data.get_orient().extract_to_matrix(_mat);
     if (_tracker_cs != _graph_cs) {
     if (_tracker_cs != _graph_cs) {

+ 8 - 8
panda/src/device/trackerNode.h

@@ -19,7 +19,7 @@
 
 
 #include "clientBase.h"
 #include "clientBase.h"
 #include "trackerData.h"
 #include "trackerData.h"
-#include "clientTrackerDevice.h"
+#include "inputDevice.h"
 #include "dataNode.h"
 #include "dataNode.h"
 #include "luse.h"
 #include "luse.h"
 #include "linmath_events.h"
 #include "linmath_events.h"
@@ -27,16 +27,16 @@
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : TrackerNode
 //       Class : TrackerNode
-// Description : This is the primary interface to a Tracker object
-//               associated with a ClientBase.  It reads the position
-//               and orientation information from the tracker and
-//               makes it available as a transformation on the data
-//               graph.
+// Description : This class reads the position and orientation
+//               information from a tracker device and makes it
+//               available as a transformation on the data graph.
+//               It is also the primary interface to a Tracker object
+//               associated with a ClientBase.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_DEVICE TrackerNode : public DataNode {
 class EXPCL_PANDA_DEVICE TrackerNode : public DataNode {
 PUBLISHED:
 PUBLISHED:
   TrackerNode(ClientBase *client, const string &device_name);
   TrackerNode(ClientBase *client, const string &device_name);
-  TrackerNode(ClientTrackerDevice *device);
+  TrackerNode(InputDevice *device);
   virtual ~TrackerNode();
   virtual ~TrackerNode();
 
 
   INLINE bool is_valid() const;
   INLINE bool is_valid() const;
@@ -66,7 +66,7 @@ private:
   CPT(TransformState) _transform;
   CPT(TransformState) _transform;
 
 
 private:
 private:
-  PT(ClientTrackerDevice) _tracker;
+  PT(InputDevice) _tracker;
   TrackerData _data;
   TrackerData _data;
   LMatrix4 _mat;
   LMatrix4 _mat;
   CoordinateSystem _tracker_cs, _graph_cs;
   CoordinateSystem _tracker_cs, _graph_cs;

+ 1 - 19
panda/src/display/callbackGraphicsWindow.cxx

@@ -54,22 +54,6 @@ CallbackGraphicsWindow::
 ~CallbackGraphicsWindow() {
 ~CallbackGraphicsWindow() {
 }
 }
 
 
-
-////////////////////////////////////////////////////////////////////
-//     Function: CallbackGraphicsWindow::get_input_device
-//       Access: Published
-//  Description: Returns a writable reference to the nth input device
-//               (mouse).  This is intended to be used for the window
-//               implementation to record mouse and keyboard input
-//               information for the Panda system.
-////////////////////////////////////////////////////////////////////
-GraphicsWindowInputDevice &CallbackGraphicsWindow::
-get_input_device(int device) {
-  LightMutexHolder holder(_input_lock);
-  nassertr(device >= 0 && device < (int)_input_devices.size(), _input_devices[0]);
-  return _input_devices[device];
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CallbackGraphicsWindow::create_input_device
 //     Function: CallbackGraphicsWindow::create_input_device
 //       Access: Published
 //       Access: Published
@@ -79,9 +63,7 @@ get_input_device(int device) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int CallbackGraphicsWindow::
 int CallbackGraphicsWindow::
 create_input_device(const string &name) {
 create_input_device(const string &name) {
-  GraphicsWindowInputDevice device =
-    GraphicsWindowInputDevice::pointer_and_keyboard(this, name);
-  return add_input_device(device);
+  return add_input_device(GraphicsWindowInputDevice::pointer_and_keyboard(this, name));
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 0 - 1
panda/src/display/callbackGraphicsWindow.h

@@ -182,7 +182,6 @@ PUBLISHED:
   INLINE void clear_render_callback();
   INLINE void clear_render_callback();
   INLINE CallbackObject *get_render_callback() const;
   INLINE CallbackObject *get_render_callback() const;
 
 
-  GraphicsWindowInputDevice &get_input_device(int device);
   int create_input_device(const string &name);
   int create_input_device(const string &name);
 
 
 public:
 public:

+ 5 - 1
panda/src/display/config_display.cxx

@@ -22,9 +22,11 @@
 #include "graphicsPipe.h"
 #include "graphicsPipe.h"
 #include "graphicsOutput.h"
 #include "graphicsOutput.h"
 #include "graphicsBuffer.h"
 #include "graphicsBuffer.h"
-#include "graphicsWindow.h"
 #include "graphicsDevice.h"
 #include "graphicsDevice.h"
+#include "graphicsWindow.h"
+#include "graphicsWindowInputDevice.h"
 #include "graphicsWindowProcCallbackData.h"
 #include "graphicsWindowProcCallbackData.h"
+#include "mouseAndKeyboard.h"
 #include "nativeWindowHandle.h"
 #include "nativeWindowHandle.h"
 #include "parasiteBuffer.h"
 #include "parasiteBuffer.h"
 #include "pandaSystem.h"
 #include "pandaSystem.h"
@@ -501,7 +503,9 @@ init_libdisplay() {
   GraphicsPipe::init_type();
   GraphicsPipe::init_type();
   GraphicsStateGuardian::init_type();
   GraphicsStateGuardian::init_type();
   GraphicsWindow::init_type();
   GraphicsWindow::init_type();
+  GraphicsWindowInputDevice::init_type();
   GraphicsWindowProcCallbackData::init_type();
   GraphicsWindowProcCallbackData::init_type();
+  MouseAndKeyboard::init_type();
   NativeWindowHandle::init_type();
   NativeWindowHandle::init_type();
   ParasiteBuffer::init_type();
   ParasiteBuffer::init_type();
   StandardMunger::init_type();
   StandardMunger::init_type();

+ 30 - 87
panda/src/display/graphicsWindow.cxx

@@ -288,6 +288,20 @@ get_num_input_devices() const {
   return result;
   return result;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindow::get_input_device
+//       Access: Published
+//  Description: Returns the nth input device associated with the
+//               window.  Typically, a window will have exactly one
+//               input device: the keyboard/mouse pair.
+////////////////////////////////////////////////////////////////////
+InputDevice *GraphicsWindow::
+get_input_device(int device) const {
+  LightMutexHolder holder(_input_lock);
+  nassertr(device >= 0 && device < (int)_input_devices.size(), NULL);
+  return _input_devices[device];
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindow::get_input_device_name
 //     Function: GraphicsWindow::get_input_device_name
 //       Access: Published
 //       Access: Published
@@ -299,7 +313,7 @@ get_input_device_name(int device) const {
   {
   {
     LightMutexHolder holder(_input_lock);
     LightMutexHolder holder(_input_lock);
     nassertr(device >= 0 && device < (int)_input_devices.size(), "");
     nassertr(device >= 0 && device < (int)_input_devices.size(), "");
-    result = _input_devices[device].get_name();
+    result = _input_devices[device]->get_name();
   }
   }
   return result;
   return result;
 }
 }
@@ -317,7 +331,7 @@ has_pointer(int device) const {
   {
   {
     LightMutexHolder holder(_input_lock);
     LightMutexHolder holder(_input_lock);
     nassertr(device >= 0 && device < (int)_input_devices.size(), false);
     nassertr(device >= 0 && device < (int)_input_devices.size(), false);
-    result = _input_devices[device].has_pointer();
+    result = _input_devices[device]->has_pointer();
   }
   }
   return result;
   return result;
 }
 }
@@ -334,7 +348,7 @@ has_keyboard(int device) const {
   {
   {
     LightMutexHolder holder(_input_lock);
     LightMutexHolder holder(_input_lock);
     nassertr(device >= 0 && device < (int)_input_devices.size(), false);
     nassertr(device >= 0 && device < (int)_input_devices.size(), false);
-    result = _input_devices[device].has_keyboard();
+    result = _input_devices[device]->has_keyboard();
   }
   }
   return result;
   return result;
 }
 }
@@ -359,7 +373,7 @@ void GraphicsWindow::
 enable_pointer_events(int device) {
 enable_pointer_events(int device) {
   LightMutexHolder holder(_input_lock);
   LightMutexHolder holder(_input_lock);
   nassertv(device >= 0 && device < (int)_input_devices.size());
   nassertv(device >= 0 && device < (int)_input_devices.size());
-  _input_devices[device].enable_pointer_events();
+  _input_devices[device]->enable_pointer_events();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -371,7 +385,7 @@ void GraphicsWindow::
 disable_pointer_events(int device) {
 disable_pointer_events(int device) {
   LightMutexHolder holder(_input_lock);
   LightMutexHolder holder(_input_lock);
   nassertv(device >= 0 && device < (int)_input_devices.size());
   nassertv(device >= 0 && device < (int)_input_devices.size());
-  _input_devices[device].disable_pointer_events();
+  _input_devices[device]->disable_pointer_events();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -379,11 +393,11 @@ disable_pointer_events(int device) {
 //       Access: Published
 //       Access: Published
 //  Description: See GraphicsWindowInputDevice::enable_pointer_mode
 //  Description: See GraphicsWindowInputDevice::enable_pointer_mode
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void GraphicsWindow::
+/*void GraphicsWindow::
 enable_pointer_mode(int device, double speed) {
 enable_pointer_mode(int device, double speed) {
   LightMutexHolder holder(_input_lock);
   LightMutexHolder holder(_input_lock);
   nassertv(device >= 0 && device < (int)_input_devices.size());
   nassertv(device >= 0 && device < (int)_input_devices.size());
-  _input_devices[device].enable_pointer_mode(speed);
+  _input_devices[device]->enable_pointer_mode(speed);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -395,8 +409,8 @@ void GraphicsWindow::
 disable_pointer_mode(int device) {
 disable_pointer_mode(int device) {
   LightMutexHolder holder(_input_lock);
   LightMutexHolder holder(_input_lock);
   nassertv(device >= 0 && device < (int)_input_devices.size());
   nassertv(device >= 0 && device < (int)_input_devices.size());
-  _input_devices[device].disable_pointer_mode();
-}
+  _input_devices[device]->disable_pointer_mode();
+}*/
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindow::get_pointer
 //     Function: GraphicsWindow::get_pointer
@@ -412,7 +426,7 @@ get_pointer(int device) const {
   {
   {
     LightMutexHolder holder(_input_lock);
     LightMutexHolder holder(_input_lock);
     nassertr(device >= 0 && device < (int)_input_devices.size(), MouseData());
     nassertr(device >= 0 && device < (int)_input_devices.size(), MouseData());
-    result = _input_devices[device].get_pointer();
+    result = _input_devices[device]->get_pointer();
   }
   }
   return result;
   return result;
 }
 }
@@ -443,81 +457,6 @@ close_ime() {
   return;
   return;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::has_button_event
-//       Access: Public
-//  Description: Returns true if the indicated device has a pending
-//               button event (a mouse button or keyboard button
-//               down/up), false otherwise.  If this returns true, the
-//               particular event may be extracted via
-//               get_button_event().
-////////////////////////////////////////////////////////////////////
-bool GraphicsWindow::
-has_button_event(int device) const {
-  bool result;
-  {
-    LightMutexHolder holder(_input_lock);
-    nassertr(device >= 0 && device < (int)_input_devices.size(), false);
-    result = _input_devices[device].has_button_event();
-  }
-  return result;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::get_button_event
-//       Access: Public
-//  Description: Assuming a previous call to has_button_event()
-//               returned true, this returns the pending button event.
-////////////////////////////////////////////////////////////////////
-ButtonEvent GraphicsWindow::
-get_button_event(int device) {
-  ButtonEvent result;
-  {
-    LightMutexHolder holder(_input_lock);
-    nassertr(device >= 0 && device < (int)_input_devices.size(), ButtonEvent());
-    nassertr(_input_devices[device].has_button_event(), ButtonEvent());
-    result = _input_devices[device].get_button_event();
-  }
-  return result;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::has_pointer_event
-//       Access: Public
-//  Description: Returns true if the indicated device has a pending
-//               pointer event (a mouse movement).  If this returns
-//               true, the particular event may be extracted via
-//               get_pointer_events().
-////////////////////////////////////////////////////////////////////
-bool GraphicsWindow::
-has_pointer_event(int device) const {
-  bool result;
-  {
-    LightMutexHolder holder(_input_lock);
-    nassertr(device >= 0 && device < (int)_input_devices.size(), false);
-    result = _input_devices[device].has_pointer_event();
-  }
-  return result;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::get_pointer_events
-//       Access: Public
-//  Description: Assuming a previous call to has_pointer_event()
-//               returned true, this returns the pending pointer event list.
-////////////////////////////////////////////////////////////////////
-PT(PointerEventList) GraphicsWindow::
-get_pointer_events(int device) {
-  PT(PointerEventList) result;
-  {
-    LightMutexHolder holder(_input_lock);
-    nassertr(device >= 0 && device < (int)_input_devices.size(), NULL);
-    nassertr(_input_devices[device].has_pointer_event(), NULL);
-    result = _input_devices[device].get_pointer_events();
-  }
-  return result;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindow::verify_window_sizes
 //     Function: GraphicsWindow::verify_window_sizes
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -860,11 +799,15 @@ system_changed_size(int x_size, int y_size) {
 //               Returns the index of the new device.
 //               Returns the index of the new device.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int GraphicsWindow::
 int GraphicsWindow::
-add_input_device(const GraphicsWindowInputDevice &device) {
+add_input_device(InputDevice *device) {
   LightMutexHolder holder(_input_lock);
   LightMutexHolder holder(_input_lock);
   int index = (int)_input_devices.size();
   int index = (int)_input_devices.size();
   _input_devices.push_back(device);
   _input_devices.push_back(device);
-  _input_devices.back().set_device_index(index);
+
+  if (device->is_of_type(GraphicsWindowInputDevice::get_class_type())) {
+    ((GraphicsWindowInputDevice *)device)->set_device_index(index);
+  }
+
   return index;
   return index;
 }
 }
 
 

+ 7 - 11
panda/src/display/graphicsWindow.h

@@ -82,10 +82,12 @@ PUBLISHED:
 
 
   INLINE WindowHandle *get_window_handle() const;
   INLINE WindowHandle *get_window_handle() const;
   MAKE_PROPERTY(window_handle, get_window_handle);
   MAKE_PROPERTY(window_handle, get_window_handle);
-  
+
   // Mouse and keyboard routines
   // Mouse and keyboard routines
   int get_num_input_devices() const;
   int get_num_input_devices() const;
+  InputDevice *get_input_device(int i) const;
   string get_input_device_name(int device) const;
   string get_input_device_name(int device) const;
+  MAKE_SEQ(get_input_devices, get_num_input_devices, get_input_device);
   MAKE_SEQ(get_input_device_names, get_num_input_devices, get_input_device_name);
   MAKE_SEQ(get_input_device_names, get_num_input_devices, get_input_device_name);
   bool has_pointer(int device) const;
   bool has_pointer(int device) const;
   bool has_keyboard(int device) const;
   bool has_keyboard(int device) const;
@@ -93,20 +95,14 @@ PUBLISHED:
 
 
   void enable_pointer_events(int device);
   void enable_pointer_events(int device);
   void disable_pointer_events(int device);
   void disable_pointer_events(int device);
-  void enable_pointer_mode(int device, double speed);
-  void disable_pointer_mode(int device);
+  /*void enable_pointer_mode(int device, double speed);
+  void disable_pointer_mode(int device);*/
 
 
   MouseData get_pointer(int device) const;
   MouseData get_pointer(int device) const;
   virtual bool move_pointer(int device, int x, int y);
   virtual bool move_pointer(int device, int x, int y);
   virtual void close_ime();
   virtual void close_ime();
 
 
 public:
 public:
-  // No need to publish these.
-  bool has_button_event(int device) const;
-  ButtonEvent get_button_event(int device);
-  bool has_pointer_event(int device) const;
-  PT(PointerEventList) get_pointer_events(int device);
-
   virtual void add_window_proc( const GraphicsWindowProc* wnd_proc_object ){};
   virtual void add_window_proc( const GraphicsWindowProc* wnd_proc_object ){};
   virtual void remove_window_proc( const GraphicsWindowProc* wnd_proc_object ){};
   virtual void remove_window_proc( const GraphicsWindowProc* wnd_proc_object ){};
   virtual void clear_window_procs(){};
   virtual void clear_window_procs(){};
@@ -146,8 +142,8 @@ protected:
   void system_changed_size(int x_size, int y_size);
   void system_changed_size(int x_size, int y_size);
 
 
 protected:
 protected:
-  int add_input_device(const GraphicsWindowInputDevice &device);
-  typedef vector_GraphicsWindowInputDevice InputDevices;
+  int add_input_device(InputDevice *device);
+  typedef pvector<PT(InputDevice)> InputDevices;
   InputDevices _input_devices;
   InputDevices _input_devices;
   LightMutex _input_lock;
   LightMutex _input_lock;
 
 

+ 6 - 226
panda/src/display/graphicsWindowInputDevice.I

@@ -12,73 +12,14 @@
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindowInputDevice::Default Constructor
 //     Function: GraphicsWindowInputDevice::Default Constructor
 //       Access: Public
 //       Access: Public
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GraphicsWindowInputDevice::
 INLINE GraphicsWindowInputDevice::
-GraphicsWindowInputDevice() {
-  LightMutexHolder holder(_lock);
-  _flags = 0;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::get_name
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE string GraphicsWindowInputDevice::
-get_name() const {
-  LightMutexHolder holder(_lock);
-  return _name;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::has_pointer
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE bool GraphicsWindowInputDevice::
-has_pointer() const {
-  LightMutexHolder holder(_lock);
-  return ((_flags & IDF_has_pointer) != 0);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::has_keyboard
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE bool GraphicsWindowInputDevice::
-has_keyboard() const {
-  LightMutexHolder holder(_lock);
-  return ((_flags & IDF_has_keyboard) != 0);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::get_pointer
-//       Access: Public
-//  Description: Returns the MouseData associated with the input
-//               device's pointer.
-////////////////////////////////////////////////////////////////////
-INLINE  MouseData GraphicsWindowInputDevice::
-get_pointer() const {
-  LightMutexHolder holder(_lock);
-  return _mouse_data;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::get_raw_pointer
-//       Access: Public
-//  Description: Returns the MouseData associated with the input
-//               device's pointer, in raw form (ie, prior to any
-//               pointer_mode interpretation).
-////////////////////////////////////////////////////////////////////
-INLINE  MouseData GraphicsWindowInputDevice::
-get_raw_pointer() const {
-  LightMutexHolder holder(_lock);
-  return _true_mouse_data;
+GraphicsWindowInputDevice() : _host(NULL) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -90,140 +31,9 @@ get_raw_pointer() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void GraphicsWindowInputDevice::
 INLINE void GraphicsWindowInputDevice::
 set_device_index(int index) {
 set_device_index(int index) {
-  LightMutexHolder holder(_lock);
   _device_index = index;
   _device_index = index;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::enable_pointer_events
-//       Access: Public
-//  Description: Enables the generation of mouse-movement events.
-////////////////////////////////////////////////////////////////////
-INLINE void GraphicsWindowInputDevice::
-enable_pointer_events() {
-  LightMutexHolder holder(_lock);
-  _enable_pointer_events = true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::disable_pointer_events
-//       Access: Public
-//  Description: Disables the generation of mouse-movement events.
-////////////////////////////////////////////////////////////////////
-INLINE void GraphicsWindowInputDevice::
-disable_pointer_events() {
-  LightMutexHolder holder(_lock);
-  _enable_pointer_events = false;
-  _pointer_events.clear();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::button_down
-//       Access: Published
-//  Description: Records that the indicated button has been depressed.
-////////////////////////////////////////////////////////////////////
-INLINE void GraphicsWindowInputDevice::
-button_down(ButtonHandle button) {
-  button_down(button, ClockObject::get_global_clock()->get_frame_time());
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::button_resume_down
-//       Access: Published
-//  Description: Records that the indicated button was depressed
-//               earlier, and we only just detected the event after
-//               the fact.  This is mainly useful for tracking the
-//               state of modifier keys.
-////////////////////////////////////////////////////////////////////
-INLINE void GraphicsWindowInputDevice::
-button_resume_down(ButtonHandle button) {
-  button_resume_down(button, ClockObject::get_global_clock()->get_frame_time());
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::button_up
-//       Access: Published
-//  Description: Records that the indicated button has been released.
-////////////////////////////////////////////////////////////////////
-INLINE void GraphicsWindowInputDevice::
-button_up(ButtonHandle button) {
-  button_up(button, ClockObject::get_global_clock()->get_frame_time());
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::keystroke
-//       Access: Published
-//  Description: Records that the indicated keystroke has been
-//               generated.
-////////////////////////////////////////////////////////////////////
-INLINE void GraphicsWindowInputDevice::
-keystroke(int keycode) {
-  keystroke(keycode, ClockObject::get_global_clock()->get_frame_time());
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::focus_lost
-//       Access: Published
-//  Description: This should be called when the window focus is lost,
-//               so that we may miss upcoming button events
-//               (especially "up" events) for the next period of time.
-//               It generates keyboard and mouse "up" events for those
-//               buttons that we previously sent unpaired "down"
-//               events, so that the Panda application will believe
-//               all buttons are now released.
-////////////////////////////////////////////////////////////////////
-INLINE void GraphicsWindowInputDevice::
-focus_lost() {
-  focus_lost(ClockObject::get_global_clock()->get_frame_time());
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::raw_button_down
-//       Access: Published
-//  Description: Records that the indicated button has been depressed.
-////////////////////////////////////////////////////////////////////
-INLINE void GraphicsWindowInputDevice::
-raw_button_down(ButtonHandle button) {
-  raw_button_down(button, ClockObject::get_global_clock()->get_frame_time());
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::raw_button_up
-//       Access: Published
-//  Description: Records that the indicated button has been released.
-////////////////////////////////////////////////////////////////////
-INLINE void GraphicsWindowInputDevice::
-raw_button_up(ButtonHandle button) {
-  raw_button_up(button, ClockObject::get_global_clock()->get_frame_time());
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::set_pointer_in_window
-//       Access: Published
-//  Description: To be called by a particular kind of GraphicsWindow
-//               to indicate that the pointer is within the window, at
-//               the given pixel coordinates.
-////////////////////////////////////////////////////////////////////
-INLINE void GraphicsWindowInputDevice::
-set_pointer_in_window(double x, double y) {
-  // mutex is handled in set pointer .. convience function
-  set_pointer(true, x, y, ClockObject::get_global_clock()->get_frame_time());
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::set_pointer_out_of_window
-//       Access: Published
-//  Description: To be called by a particular kind of GraphicsWindow
-//               to indicate that the pointer is no longer within the
-//               window.
-////////////////////////////////////////////////////////////////////
-INLINE void GraphicsWindowInputDevice::
-set_pointer_out_of_window() {
- // mutex is handled in set pointer .. convience function
-  set_pointer(false, _mouse_data._xpos, _mouse_data._ypos,
-              ClockObject::get_global_clock()->get_frame_time());
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindowInputDevice::set_pointer_in_window
 //     Function: GraphicsWindowInputDevice::set_pointer_in_window
 //       Access: Published
 //       Access: Published
@@ -233,8 +43,8 @@ set_pointer_out_of_window() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void GraphicsWindowInputDevice::
 INLINE void GraphicsWindowInputDevice::
 set_pointer_in_window(double x, double y, double time) {
 set_pointer_in_window(double x, double y, double time) {
- // mutex is handled in set pointer .. convience function
-  set_pointer(true, x, y, time);
+  LightMutexHolder holder(_lock);
+  InputDevice::set_pointer(true, x, y, time);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -246,36 +56,6 @@ set_pointer_in_window(double x, double y, double time) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void GraphicsWindowInputDevice::
 INLINE void GraphicsWindowInputDevice::
 set_pointer_out_of_window(double time) {
 set_pointer_out_of_window(double time) {
- // mutex is handled in set pointer .. convience function
-  set_pointer(false, _mouse_data._xpos, _mouse_data._ypos, time);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::operator ==
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE bool GraphicsWindowInputDevice::
-operator == (const GraphicsWindowInputDevice &) const {
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::operator !=
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE bool GraphicsWindowInputDevice::
-operator != (const GraphicsWindowInputDevice &) const {
-  return false;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::operator <
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE bool GraphicsWindowInputDevice::
-operator < (const GraphicsWindowInputDevice &) const {
-  return false;
+  LightMutexHolder holder(_lock);
+  InputDevice::set_pointer_out_of_window(time);
 }
 }

+ 21 - 196
panda/src/display/graphicsWindowInputDevice.cxx

@@ -18,17 +18,7 @@
 #include "mouseButton.h"
 #include "mouseButton.h"
 #include "keyboardButton.h"
 #include "keyboardButton.h"
 
 
-#define EXPCL EXPCL_PANDA_DISPLAY
-#define EXPTP EXPTP_PANDA_DISPLAY
-#define TYPE GraphicsWindowInputDevice
-#define NAME vector_GraphicsWindowInputDevice
-
-#include "vector_src.cxx"
-
-// Tell GCC that we'll take care of the instantiation explicitly here.
-#ifdef __GNUC__
-#pragma implementation
-#endif
+TypeHandle GraphicsWindowInputDevice::_type_handle;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindowInputDevice::Constructor
 //     Function: GraphicsWindowInputDevice::Constructor
@@ -43,14 +33,8 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GraphicsWindowInputDevice::
 GraphicsWindowInputDevice::
 GraphicsWindowInputDevice(GraphicsWindow *host, const string &name, int flags) :
 GraphicsWindowInputDevice(GraphicsWindow *host, const string &name, int flags) :
-  _host(host),
-  _name(name),
-  _flags(flags),
-  _device_index(0),
-  _event_sequence(0),
-  _pointer_mode_enable(false),
-  _pointer_speed(1.0),
-  _enable_pointer_events(false)
+  InputDevice(name, DC_virtual, flags),
+  _host(host)
 {
 {
 }
 }
 
 
@@ -60,9 +44,9 @@ GraphicsWindowInputDevice(GraphicsWindow *host, const string &name, int flags) :
 //  Description: This named constructor returns an input device that
 //  Description: This named constructor returns an input device that
 //               only has a pointing device, no keyboard.
 //               only has a pointing device, no keyboard.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-GraphicsWindowInputDevice GraphicsWindowInputDevice::
+PT(GraphicsWindowInputDevice) GraphicsWindowInputDevice::
 pointer_only(GraphicsWindow *host, const string &name) {
 pointer_only(GraphicsWindow *host, const string &name) {
-  return GraphicsWindowInputDevice(host, name, IDF_has_pointer);
+  return new GraphicsWindowInputDevice(host, name, IDF_has_pointer);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -71,9 +55,9 @@ pointer_only(GraphicsWindow *host, const string &name) {
 //  Description: This named constructor returns an input device that
 //  Description: This named constructor returns an input device that
 //               only has a keyboard, no pointing device.
 //               only has a keyboard, no pointing device.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-GraphicsWindowInputDevice GraphicsWindowInputDevice::
+PT(GraphicsWindowInputDevice) GraphicsWindowInputDevice::
 keyboard_only(GraphicsWindow *host, const string &name) {
 keyboard_only(GraphicsWindow *host, const string &name) {
-  return GraphicsWindowInputDevice(host, name, IDF_has_keyboard);
+  return new GraphicsWindowInputDevice(host, name, IDF_has_keyboard);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -82,9 +66,9 @@ keyboard_only(GraphicsWindow *host, const string &name) {
 //  Description: This named constructor returns an input device that
 //  Description: This named constructor returns an input device that
 //               has both a keyboard and pointer.
 //               has both a keyboard and pointer.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-GraphicsWindowInputDevice GraphicsWindowInputDevice::
+PT(GraphicsWindowInputDevice) GraphicsWindowInputDevice::
 pointer_and_keyboard(GraphicsWindow *host, const string &name) {
 pointer_and_keyboard(GraphicsWindow *host, const string &name) {
-  return
+  return new
     GraphicsWindowInputDevice(host, name, IDF_has_pointer | IDF_has_keyboard);
     GraphicsWindowInputDevice(host, name, IDF_has_pointer | IDF_has_keyboard);
 }
 }
 
 
@@ -94,9 +78,8 @@ pointer_and_keyboard(GraphicsWindow *host, const string &name) {
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GraphicsWindowInputDevice::
 GraphicsWindowInputDevice::
-GraphicsWindowInputDevice(const GraphicsWindowInputDevice &copy)
-{
-    *this = copy;
+GraphicsWindowInputDevice(const GraphicsWindowInputDevice &copy) {
+  *this = copy;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -105,22 +88,9 @@ GraphicsWindowInputDevice(const GraphicsWindowInputDevice &copy)
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GraphicsWindowInputDevice::
 void GraphicsWindowInputDevice::
-operator = (const GraphicsWindowInputDevice &copy)
-{
-  LightMutexHolder holder(_lock);
-  LightMutexHolder holder1(copy._lock);
+operator = (const GraphicsWindowInputDevice &copy) {
   _host = copy._host;
   _host = copy._host;
-  _name = copy._name;
-  _flags = copy._flags;
-  _device_index = copy._device_index;
-  _event_sequence = copy._event_sequence;
-  _pointer_mode_enable = copy._pointer_mode_enable;
-  _pointer_speed = copy._pointer_speed;
-  _enable_pointer_events = copy._enable_pointer_events;
-  _mouse_data = copy._mouse_data;
-  _true_mouse_data = copy._true_mouse_data;
-  _button_events = copy._button_events;
-  _pointer_events = copy._pointer_events;
+  InputDevice::operator = (copy);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -132,151 +102,6 @@ GraphicsWindowInputDevice::
 ~GraphicsWindowInputDevice() {
 ~GraphicsWindowInputDevice() {
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::has_button_event
-//       Access: Public
-//  Description: Returns true if this device has a pending button
-//               event (a mouse button or keyboard button down/up),
-//               false otherwise.  If this returns true, the
-//               particular event may be extracted via
-//               get_button_event().
-////////////////////////////////////////////////////////////////////
-bool GraphicsWindowInputDevice::
-has_button_event() const {
-  LightMutexHolder holder(_lock);
-  return !_button_events.empty();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::get_button_event
-//       Access: Public
-//  Description: Assuming a previous call to has_button_event()
-//               returned true, this returns the pending button event.
-////////////////////////////////////////////////////////////////////
-ButtonEvent GraphicsWindowInputDevice::
-get_button_event() {
-  LightMutexHolder holder(_lock);
-  ButtonEvent be = _button_events.front();
-  _button_events.pop_front();
-  return be;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::has_pointer_event
-//       Access: Public
-//  Description: Returns true if this device has a pending pointer
-//               event (a mouse movement), or false otherwise.  If
-//               this returns true, the particular event may be
-//               extracted via get_pointer_event().
-////////////////////////////////////////////////////////////////////
-bool GraphicsWindowInputDevice::
-has_pointer_event() const {
-  LightMutexHolder holder(_lock);
-  return (_pointer_events != 0);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::get_pointer_events
-//       Access: Public
-//  Description: Returns a PointerEventList containing all the recent
-//               pointer events.
-////////////////////////////////////////////////////////////////////
-PT(PointerEventList) GraphicsWindowInputDevice::
-get_pointer_events() {
-  LightMutexHolder holder(_lock);
-  PT(PointerEventList) result = _pointer_events;
-  _pointer_events = 0;
-  return result;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::enable_pointer_mode
-//       Access: Public
-//  Description: There are two modes: raw mode, and pointer mode.
-//               In pointer mode, the mouse stops when it reaches the
-//               edges of the window.  In raw mode, the mouse ignores
-//               the screen boundaries and can continue indefinitely,
-//               even into negative coordinates.  In raw mode, each
-//               "blip" from the mouse hardware corresponds to a
-//               change of 1 unit in the mouse's (x,y) coordinate.
-//               In pointer mode, a variety of speed adjustment factors
-//               and concepts like "mouse acceleration" may be applied.
-//
-//               Mouse zero represents the system mouse pointer.  This
-//               is by definition a pointer, not a raw mouse.  It is
-//               an error to try to enable or disable pointer mode on
-//               mouse zero.
-////////////////////////////////////////////////////////////////////
-void GraphicsWindowInputDevice::
-enable_pointer_mode(double speed) {
-  LightMutexHolder holder(_lock);
-  nassertv(_device_index != 0);
-  _pointer_mode_enable = true;
-  _pointer_speed = speed;
-  _mouse_data._xpos = _host->get_x_size() * 0.5;
-  _mouse_data._ypos = _host->get_y_size() * 0.5;
-  _mouse_data._in_window = true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::disable_pointer_mode
-//       Access: Public
-//  Description: see enable_pointer_mode.
-////////////////////////////////////////////////////////////////////
-void GraphicsWindowInputDevice::
-disable_pointer_mode() {
-  LightMutexHolder holder(_lock);
-  nassertv(_device_index != 0);
-  _pointer_mode_enable = false;
-  _pointer_speed = 1.0;
-  _mouse_data = _true_mouse_data;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindowInputDevice::set_pointer
-//       Access: Published
-//  Description: Records that a mouse movement has taken place.
-////////////////////////////////////////////////////////////////////
-void GraphicsWindowInputDevice::
-set_pointer(bool inwin, double x, double y, double time) {
-  LightMutexHolder holder(_lock);
-
-  double delta_x = x - _true_mouse_data._xpos;
-  double delta_y = y - _true_mouse_data._ypos;
-  _true_mouse_data._in_window = inwin;
-  _true_mouse_data._xpos = x;
-  _true_mouse_data._ypos = y;
-
-  if (_pointer_mode_enable) {
-    double pointer_x = _mouse_data._xpos;
-    double pointer_y = _mouse_data._ypos;
-    pointer_x += (delta_x * _pointer_speed);
-    pointer_y += (delta_y * _pointer_speed);
-    double xhi = _host->get_x_size();
-    double yhi = _host->get_y_size();
-    if (pointer_x < 0.0) pointer_x = 0.0;
-    if (pointer_y < 0.0) pointer_y = 0.0;
-    if (pointer_x > xhi) pointer_x = xhi;
-    if (pointer_y > yhi) pointer_y = yhi;
-    _mouse_data._in_window = true;
-    _mouse_data._xpos = pointer_x;
-    _mouse_data._ypos = pointer_y;
-  } else {
-    _mouse_data = _true_mouse_data;
-  }
-
-  if (_enable_pointer_events) {
-    int seq = _event_sequence++;
-    if (_pointer_events == 0) {
-      _pointer_events = new PointerEventList();
-    }
-    _pointer_events->add_event(_mouse_data._in_window,
-                               _mouse_data._xpos,
-                               _mouse_data._ypos,
-                               seq, time);
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindowInputDevice::button_down
 //     Function: GraphicsWindowInputDevice::button_down
 //       Access: Published
 //       Access: Published
@@ -285,7 +110,7 @@ set_pointer(bool inwin, double x, double y, double time) {
 void GraphicsWindowInputDevice::
 void GraphicsWindowInputDevice::
 button_down(ButtonHandle button, double time) {
 button_down(ButtonHandle button, double time) {
   LightMutexHolder holder(_lock);
   LightMutexHolder holder(_lock);
-  _button_events.push_back(ButtonEvent(button, ButtonEvent::T_down, time));
+  _button_events->add_event(ButtonEvent(button, ButtonEvent::T_down, time));
   _buttons_held.insert(button);
   _buttons_held.insert(button);
 }
 }
 
 
@@ -300,7 +125,7 @@ button_down(ButtonHandle button, double time) {
 void GraphicsWindowInputDevice::
 void GraphicsWindowInputDevice::
 button_resume_down(ButtonHandle button, double time) {
 button_resume_down(ButtonHandle button, double time) {
   LightMutexHolder holder(_lock);
   LightMutexHolder holder(_lock);
-  _button_events.push_back(ButtonEvent(button, ButtonEvent::T_resume_down, time));
+  _button_events->add_event(ButtonEvent(button, ButtonEvent::T_resume_down, time));
   _buttons_held.insert(button);
   _buttons_held.insert(button);
 }
 }
 
 
@@ -312,7 +137,7 @@ button_resume_down(ButtonHandle button, double time) {
 void GraphicsWindowInputDevice::
 void GraphicsWindowInputDevice::
 button_up(ButtonHandle button, double time) {
 button_up(ButtonHandle button, double time) {
   LightMutexHolder holder(_lock);
   LightMutexHolder holder(_lock);
-  _button_events.push_back(ButtonEvent(button, ButtonEvent::T_up, time));
+  _button_events->add_event(ButtonEvent(button, ButtonEvent::T_up, time));
   _buttons_held.erase(button);
   _buttons_held.erase(button);
 }
 }
 
 
@@ -325,7 +150,7 @@ button_up(ButtonHandle button, double time) {
 void GraphicsWindowInputDevice::
 void GraphicsWindowInputDevice::
 keystroke(int keycode, double time) {
 keystroke(int keycode, double time) {
   LightMutexHolder holder(_lock);
   LightMutexHolder holder(_lock);
-  _button_events.push_back(ButtonEvent(keycode, time));
+  _button_events->add_event(ButtonEvent(keycode, time));
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -340,7 +165,7 @@ void GraphicsWindowInputDevice::
 candidate(const wstring &candidate_string, size_t highlight_start,
 candidate(const wstring &candidate_string, size_t highlight_start,
           size_t highlight_end, size_t cursor_pos) {
           size_t highlight_end, size_t cursor_pos) {
   LightMutexHolder holder(_lock);
   LightMutexHolder holder(_lock);
-  _button_events.push_back(ButtonEvent(candidate_string,
+  _button_events->add_event(ButtonEvent(candidate_string,
                                        highlight_start, highlight_end,
                                        highlight_start, highlight_end,
                                        cursor_pos));
                                        cursor_pos));
 }
 }
@@ -361,7 +186,7 @@ focus_lost(double time) {
   LightMutexHolder holder(_lock);
   LightMutexHolder holder(_lock);
   ButtonsHeld::iterator bi;
   ButtonsHeld::iterator bi;
   for (bi = _buttons_held.begin(); bi != _buttons_held.end(); ++bi) {
   for (bi = _buttons_held.begin(); bi != _buttons_held.end(); ++bi) {
-    _button_events.push_back(ButtonEvent(*bi, ButtonEvent::T_up, time));
+    _button_events->add_event(ButtonEvent(*bi, ButtonEvent::T_up, time));
   }
   }
   _buttons_held.clear();
   _buttons_held.clear();
 }
 }
@@ -374,7 +199,7 @@ focus_lost(double time) {
 void GraphicsWindowInputDevice::
 void GraphicsWindowInputDevice::
 raw_button_down(ButtonHandle button, double time) {
 raw_button_down(ButtonHandle button, double time) {
   LightMutexHolder holder(_lock);
   LightMutexHolder holder(_lock);
-  _button_events.push_back(ButtonEvent(button, ButtonEvent::T_raw_down, time));
+  _button_events->add_event(ButtonEvent(button, ButtonEvent::T_raw_down, time));
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -385,5 +210,5 @@ raw_button_down(ButtonHandle button, double time) {
 void GraphicsWindowInputDevice::
 void GraphicsWindowInputDevice::
 raw_button_up(ButtonHandle button, double time) {
 raw_button_up(ButtonHandle button, double time) {
   LightMutexHolder holder(_lock);
   LightMutexHolder holder(_lock);
-  _button_events.push_back(ButtonEvent(button, ButtonEvent::T_raw_up, time));
+  _button_events->add_event(ButtonEvent(button, ButtonEvent::T_raw_up, time));
 }
 }

+ 38 - 98
panda/src/display/graphicsWindowInputDevice.h

@@ -16,139 +16,79 @@
 #define GRAPHICSWINDOWINPUTDEVICE_H
 #define GRAPHICSWINDOWINPUTDEVICE_H
 
 
 #include "pandabase.h"
 #include "pandabase.h"
-
-#include "buttonEvent.h"
-#include "pointerEvent.h"
-#include "pointerEventList.h"
-#include "mouseData.h"
-#include "clockObject.h"
-
-#include "pdeque.h"
-#include "pvector.h"
-#include "lightMutex.h"
-#include "lightMutexHolder.h"
+#include "inputDevice.h"
 
 
 // Forward declarations
 // Forward declarations
 class GraphicsWindow;
 class GraphicsWindow;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : GraphicsWindowInputDevice
 //       Class : GraphicsWindowInputDevice
-// Description : This is a structure representing a single input
-//               device that may be associated with a window.
-//               Typically this will be a keyboard/mouse pair, and
-//               there will be exactly one of these associated with
-//               each window, but other variants are possible.
+// Description : This is a virtual input device that represents
+//               the keyboard and mouse pair that is associated with
+//               a particular window.  It collects mouse and keyboard
+//               events from the windowing system while the window is
+//               in focus.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA_DISPLAY GraphicsWindowInputDevice {
+class EXPCL_PANDA_DISPLAY GraphicsWindowInputDevice : public InputDevice {
 private:
 private:
   GraphicsWindowInputDevice(GraphicsWindow *host, const string &name, int flags);
   GraphicsWindowInputDevice(GraphicsWindow *host, const string &name, int flags);
 
 
 public:
 public:
-  static GraphicsWindowInputDevice pointer_only(GraphicsWindow *host, const string &name);
-  static GraphicsWindowInputDevice keyboard_only(GraphicsWindow *host, const string &name);
-  static GraphicsWindowInputDevice pointer_and_keyboard(GraphicsWindow *host, const string &name);
+  static PT(GraphicsWindowInputDevice) pointer_only(GraphicsWindow *host, const string &name);
+  static PT(GraphicsWindowInputDevice) keyboard_only(GraphicsWindow *host, const string &name);
+  static PT(GraphicsWindowInputDevice) pointer_and_keyboard(GraphicsWindow *host, const string &name);
 
 
   INLINE GraphicsWindowInputDevice();
   INLINE GraphicsWindowInputDevice();
   GraphicsWindowInputDevice(const GraphicsWindowInputDevice &copy);
   GraphicsWindowInputDevice(const GraphicsWindowInputDevice &copy);
   void operator = (const GraphicsWindowInputDevice &copy);
   void operator = (const GraphicsWindowInputDevice &copy);
   ~GraphicsWindowInputDevice();
   ~GraphicsWindowInputDevice();
 
 
-  INLINE string get_name() const;
-  INLINE bool has_pointer() const;
-  INLINE bool has_keyboard() const;
-
   INLINE void set_device_index(int index);
   INLINE void set_device_index(int index);
 
 
-  INLINE MouseData get_pointer() const;
-  INLINE MouseData get_raw_pointer() const;
-
-  INLINE void enable_pointer_events();
-  INLINE void disable_pointer_events();
-
-  void enable_pointer_mode(double speed);
-  void disable_pointer_mode();
-
-  bool has_button_event() const;
-  ButtonEvent get_button_event();
-  bool has_pointer_event() const;
-  PT(PointerEventList) get_pointer_events();
-
 PUBLISHED:
 PUBLISHED:
   // The following interface is for the various kinds of
   // The following interface is for the various kinds of
   // GraphicsWindows to record the data incoming on the device.
   // GraphicsWindows to record the data incoming on the device.
-  INLINE void button_down(ButtonHandle button);
-  INLINE void button_resume_down(ButtonHandle button);
-  INLINE void button_up(ButtonHandle button);
-  INLINE void keystroke(int keycode);
-  INLINE void focus_lost();
-  INLINE void raw_button_down(ButtonHandle button);
-  INLINE void raw_button_up(ButtonHandle button);
-  INLINE void set_pointer_in_window(double x, double y);
-  INLINE void set_pointer_out_of_window();
-
-  void button_down(ButtonHandle button, double time);
-  void button_resume_down(ButtonHandle button, double time);
-  void button_up(ButtonHandle button, double time);
-  void keystroke(int keycode, double time);
+  void button_down(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time());
+  void button_resume_down(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time());
+  void button_up(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time());
+
+  void keystroke(int keycode, double time = ClockObject::get_global_clock()->get_frame_time());
   void candidate(const wstring &candidate_string, size_t highlight_start,
   void candidate(const wstring &candidate_string, size_t highlight_start,
                  size_t highlight_end, size_t cursor_pos);
                  size_t highlight_end, size_t cursor_pos);
-  void focus_lost(double time);
-  void raw_button_down(ButtonHandle button, double time);
-  void raw_button_up(ButtonHandle button, double time);
-
-  INLINE void set_pointer_in_window(double x, double y, double time);
-  INLINE void set_pointer_out_of_window(double time);
-  void set_pointer(bool inwin, double x, double y, double time);
 
 
-public:
-  // We need these methods to make VC++ happy when we try to
-  // instantiate a pvector<GraphicsWindowInputDevice>.  They don't do
-  // anything useful.
-  INLINE bool operator == (const GraphicsWindowInputDevice &other) const;
-  INLINE bool operator != (const GraphicsWindowInputDevice &other) const;
-  INLINE bool operator < (const GraphicsWindowInputDevice &other) const;
+  void focus_lost(double time = ClockObject::get_global_clock()->get_frame_time());
 
 
-private:
-  enum InputDeviceFlags {
-    IDF_has_pointer    = 0x01,
-    IDF_has_keyboard   = 0x02
-  };
-  typedef pdeque<ButtonEvent> ButtonEvents;
+  void raw_button_down(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time());
+  void raw_button_up(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time());
 
 
-  LightMutex _lock;
+  INLINE void set_pointer_in_window(double x, double y, double time = ClockObject::get_global_clock()->get_frame_time());
+  INLINE void set_pointer_out_of_window(double time = ClockObject::get_global_clock()->get_frame_time());
 
 
+private:
   GraphicsWindow *_host;
   GraphicsWindow *_host;
-
-  string _name;
-  int _flags;
   int _device_index;
   int _device_index;
-  int _event_sequence;
-
-  bool   _pointer_mode_enable;
-  double _pointer_speed;
-
-  bool _enable_pointer_events;
-  MouseData _mouse_data;
-  MouseData _true_mouse_data;
-  ButtonEvents _button_events;
-  PT(PointerEventList) _pointer_events;
 
 
   typedef pset<ButtonHandle> ButtonsHeld;
   typedef pset<ButtonHandle> ButtonsHeld;
   ButtonsHeld _buttons_held;
   ButtonsHeld _buttons_held;
-};
-
-#include "graphicsWindowInputDevice.I"
 
 
-#define EXPCL EXPCL_PANDA_DISPLAY
-#define EXPTP EXPTP_PANDA_DISPLAY
-#define TYPE GraphicsWindowInputDevice
-#define NAME vector_GraphicsWindowInputDevice
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    InputDevice::init_type();
+    register_type(_type_handle, "GraphicsWindowInputDevice",
+                  InputDevice::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
 
 
-#include "vector_src.h"
+private:
+  static TypeHandle _type_handle;
+};
 
 
-// Tell GCC that we'll take care of the instantiation explicitly here.
-#ifdef __GNUC__
-#pragma interface
-#endif
+#include "graphicsWindowInputDevice.I"
 
 
 #endif
 #endif

+ 13 - 16
panda/src/device/mouseAndKeyboard.cxx → panda/src/display/mouseAndKeyboard.cxx

@@ -41,7 +41,6 @@ MouseAndKeyboard(GraphicsWindow *window, int device, const string &name) :
   _pixel_xy = new EventStoreVec2(LPoint2(0.0f, 0.0f));
   _pixel_xy = new EventStoreVec2(LPoint2(0.0f, 0.0f));
   _pixel_size = new EventStoreVec2(LPoint2(0.0f, 0.0f));
   _pixel_size = new EventStoreVec2(LPoint2(0.0f, 0.0f));
   _xy = new EventStoreVec2(LPoint2(0.0f, 0.0f));
   _xy = new EventStoreVec2(LPoint2(0.0f, 0.0f));
-  _button_events = new ButtonEventList;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -93,20 +92,18 @@ get_source_device() const {
 void MouseAndKeyboard::
 void MouseAndKeyboard::
 do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &,
 do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &,
                  DataNodeTransmit &output) {
                  DataNodeTransmit &output) {
-  if (_window->has_button_event(_device)) {
-    // Fill up the button events.
-    _button_events->clear();
-    while (_window->has_button_event(_device)) {
-      ButtonEvent be = _window->get_button_event(_device);
-      _button_events->add_event(be);
-    }
-    output.set_data(_button_events_output, EventParameter(_button_events));
+
+  PT(InputDevice) device = _window->get_input_device(_device);
+
+  if (device->has_button_event()) {
+    PT(ButtonEventList) bel = device->get_button_events();
+    output.set_data(_button_events_output, EventParameter(bel));
   }
   }
-  if (_window->has_pointer_event(_device)) {
-    PT(PointerEventList) pel = _window->get_pointer_events(_device);
+  if (device->has_pointer_event()) {
+    PT(PointerEventList) pel = device->get_pointer_events();
     output.set_data(_pointer_events_output, EventParameter(pel));
     output.set_data(_pointer_events_output, EventParameter(pel));
   }
   }
-  
+
   // Get the window size.
   // Get the window size.
   WindowProperties properties = _window->get_properties();
   WindowProperties properties = _window->get_properties();
   if (properties.has_size()) {
   if (properties.has_size()) {
@@ -116,18 +113,18 @@ do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &,
     _pixel_size->set_value(LPoint2(w, h));
     _pixel_size->set_value(LPoint2(w, h));
     output.set_data(_pixel_size_output, EventParameter(_pixel_size));
     output.set_data(_pixel_size_output, EventParameter(_pixel_size));
 
 
-    if (_window->has_pointer(_device)) {
-      const MouseData &mdata = _window->get_pointer(_device);
+    if (device->has_pointer()) {
+      const MouseData &mdata = device->get_pointer();
 
 
       if (mdata._in_window) {
       if (mdata._in_window) {
         // Get mouse motion in pixels.
         // Get mouse motion in pixels.
         _pixel_xy->set_value(LPoint2(mdata._xpos, mdata._ypos));
         _pixel_xy->set_value(LPoint2(mdata._xpos, mdata._ypos));
         output.set_data(_pixel_xy_output, EventParameter(_pixel_xy));
         output.set_data(_pixel_xy_output, EventParameter(_pixel_xy));
-        
+
         // Normalize pixel motion to range [-1,1].
         // Normalize pixel motion to range [-1,1].
         PN_stdfloat xf = (PN_stdfloat)(2 * mdata._xpos) / (PN_stdfloat)w - 1.0f;
         PN_stdfloat xf = (PN_stdfloat)(2 * mdata._xpos) / (PN_stdfloat)w - 1.0f;
         PN_stdfloat yf = 1.0f - (PN_stdfloat)(2 * mdata._ypos) / (PN_stdfloat)h;
         PN_stdfloat yf = 1.0f - (PN_stdfloat)(2 * mdata._ypos) / (PN_stdfloat)h;
-        
+
         _xy->set_value(LPoint2(xf, yf));
         _xy->set_value(LPoint2(xf, yf));
         output.set_data(_xy_output, EventParameter(_xy));
         output.set_data(_xy_output, EventParameter(_xy));
       }
       }

+ 1 - 2
panda/src/device/mouseAndKeyboard.h → panda/src/display/mouseAndKeyboard.h

@@ -51,7 +51,7 @@ PUBLISHED:
 
 
   PT(GraphicsWindow) get_source_window() const;
   PT(GraphicsWindow) get_source_window() const;
   int                get_source_device() const;
   int                get_source_device() const;
-  
+
 protected:
 protected:
   // Inherited from DataNode
   // Inherited from DataNode
   virtual void do_transmit_data(DataGraphTraverser *trav,
   virtual void do_transmit_data(DataGraphTraverser *trav,
@@ -69,7 +69,6 @@ private:
   PT(EventStoreVec2) _pixel_xy;
   PT(EventStoreVec2) _pixel_xy;
   PT(EventStoreVec2) _pixel_size;
   PT(EventStoreVec2) _pixel_size;
   PT(EventStoreVec2) _xy;
   PT(EventStoreVec2) _xy;
-  PT(ButtonEventList) _button_events;
 
 
   PT(GraphicsWindow) _window;
   PT(GraphicsWindow) _window;
   int _device;
   int _device;

+ 1 - 0
panda/src/display/p3display_composite2.cxx

@@ -5,6 +5,7 @@
 #include "graphicsWindowProc.cxx"
 #include "graphicsWindowProc.cxx"
 #include "graphicsWindowProcCallbackData.cxx"
 #include "graphicsWindowProcCallbackData.cxx"
 #include "graphicsWindowInputDevice.cxx"
 #include "graphicsWindowInputDevice.cxx"
+#include "mouseAndKeyboard.cxx"
 #include "nativeWindowHandle.cxx"
 #include "nativeWindowHandle.cxx"
 #include "parasiteBuffer.cxx"
 #include "parasiteBuffer.cxx"
 #include "standardMunger.cxx"
 #include "standardMunger.cxx"

+ 2 - 0
panda/src/putil/config_util.cxx

@@ -32,6 +32,7 @@
 #include "datagram.h"
 #include "datagram.h"
 #include "doubleBitMask.h"
 #include "doubleBitMask.h"
 #include "factoryParam.h"
 #include "factoryParam.h"
+#include "gamepadButton.h"
 #include "namable.h"
 #include "namable.h"
 #include "nodeCachedReferenceCount.h"
 #include "nodeCachedReferenceCount.h"
 #include "paramValue.h"
 #include "paramValue.h"
@@ -225,6 +226,7 @@ init_libputil() {
   WritableConfigurable::init_type();
   WritableConfigurable::init_type();
   WritableParam::init_type();
   WritableParam::init_type();
 
 
+  GamepadButton::init_gamepad_buttons();
   KeyboardButton::init_keyboard_buttons();
   KeyboardButton::init_keyboard_buttons();
   MouseButton::init_mouse_buttons();
   MouseButton::init_mouse_buttons();
 
 

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

@@ -0,0 +1,75 @@
+// Filename: gamepadButton.cxx
+// Created by:  rdb (21Aug15)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "gamepadButton.h"
+#include "buttonRegistry.h"
+
+#define DEFINE_GAMEPAD_BUTTON_HANDLE(KeyName)     \
+                  static ButtonHandle _##KeyName; \
+                  ButtonHandle GamepadButton::KeyName() { return _##KeyName; }
+
+DEFINE_GAMEPAD_BUTTON_HANDLE(lstick)
+DEFINE_GAMEPAD_BUTTON_HANDLE(rstick)
+DEFINE_GAMEPAD_BUTTON_HANDLE(lshoulder)
+DEFINE_GAMEPAD_BUTTON_HANDLE(rshoulder)
+DEFINE_GAMEPAD_BUTTON_HANDLE(ltrigger)
+DEFINE_GAMEPAD_BUTTON_HANDLE(rtrigger)
+
+DEFINE_GAMEPAD_BUTTON_HANDLE(dpad_left)
+DEFINE_GAMEPAD_BUTTON_HANDLE(dpad_right)
+DEFINE_GAMEPAD_BUTTON_HANDLE(dpad_up)
+DEFINE_GAMEPAD_BUTTON_HANDLE(dpad_down)
+
+DEFINE_GAMEPAD_BUTTON_HANDLE(back)
+DEFINE_GAMEPAD_BUTTON_HANDLE(guide)
+DEFINE_GAMEPAD_BUTTON_HANDLE(start)
+
+DEFINE_GAMEPAD_BUTTON_HANDLE(action_a)
+DEFINE_GAMEPAD_BUTTON_HANDLE(action_b)
+DEFINE_GAMEPAD_BUTTON_HANDLE(action_c)
+DEFINE_GAMEPAD_BUTTON_HANDLE(action_x)
+DEFINE_GAMEPAD_BUTTON_HANDLE(action_y)
+DEFINE_GAMEPAD_BUTTON_HANDLE(action_z)
+
+////////////////////////////////////////////////////////////////////
+//     Function: GamepadButton::init_gamepad_buttons
+//       Access: Public, Static
+//  Description: This is intended to be called only once, by the
+//               static initialization performed in config_util.cxx.
+////////////////////////////////////////////////////////////////////
+void GamepadButton::
+init_gamepad_buttons() {
+  ButtonRegistry::ptr()->register_button(_lstick, "lstick");
+  ButtonRegistry::ptr()->register_button(_rstick, "rstick");
+  ButtonRegistry::ptr()->register_button(_lshoulder, "lshoulder");
+  ButtonRegistry::ptr()->register_button(_rshoulder, "rshoulder");
+  ButtonRegistry::ptr()->register_button(_ltrigger, "ltrigger");
+  ButtonRegistry::ptr()->register_button(_rtrigger, "rtrigger");
+
+  ButtonRegistry::ptr()->register_button(_dpad_left, "dpad_left");
+  ButtonRegistry::ptr()->register_button(_dpad_right, "dpad_right");
+  ButtonRegistry::ptr()->register_button(_dpad_up, "dpad_up");
+  ButtonRegistry::ptr()->register_button(_dpad_down, "dpad_down");
+
+  ButtonRegistry::ptr()->register_button(_back, "back");
+  ButtonRegistry::ptr()->register_button(_guide, "guide");
+  ButtonRegistry::ptr()->register_button(_start, "start");
+
+  ButtonRegistry::ptr()->register_button(_action_a, "action_a");
+  ButtonRegistry::ptr()->register_button(_action_b, "action_b");
+  ButtonRegistry::ptr()->register_button(_action_c, "action_c");
+  ButtonRegistry::ptr()->register_button(_action_x, "action_x");
+  ButtonRegistry::ptr()->register_button(_action_y, "action_y");
+  ButtonRegistry::ptr()->register_button(_action_z, "action_z");
+}

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

@@ -0,0 +1,57 @@
+// Filename: gamepadButton.h
+// Created by:  rdb (21Aug15)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef GAMEPADBUTTON_H
+#define GAMEPADBUTTON_H
+
+#include "pandabase.h"
+
+#include "buttonHandle.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : GamepadButton
+// Description : This class is just used as a convenient namespace for
+//               grouping all of these handy functions that return
+//               buttons which map to gamepad buttons.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA_PUTIL GamepadButton {
+PUBLISHED:
+  static ButtonHandle lstick();
+  static ButtonHandle rstick();
+  static ButtonHandle lshoulder();
+  static ButtonHandle rshoulder();
+  static ButtonHandle ltrigger();
+  static ButtonHandle rtrigger();
+
+  static ButtonHandle dpad_left();
+  static ButtonHandle dpad_right();
+  static ButtonHandle dpad_up();
+  static ButtonHandle dpad_down();
+
+  static ButtonHandle back();
+  static ButtonHandle guide();
+  static ButtonHandle start();
+
+  static ButtonHandle action_a();
+  static ButtonHandle action_b();
+  static ButtonHandle action_c();
+  static ButtonHandle action_x();
+  static ButtonHandle action_y();
+  static ButtonHandle action_z();
+
+public:
+  static void init_gamepad_buttons();
+};
+
+#endif

+ 0 - 1
panda/src/putil/p3putil_composite1.cxx

@@ -28,4 +28,3 @@
 #include "factoryBase.cxx"
 #include "factoryBase.cxx"
 #include "factoryParam.cxx"
 #include "factoryParam.cxx"
 #include "factoryParams.cxx"
 #include "factoryParams.cxx"
-#include "globalPointerRegistry.cxx"

+ 2 - 0
panda/src/putil/p3putil_composite2.cxx

@@ -1,3 +1,5 @@
+#include "gamepadButton.cxx"
+#include "globalPointerRegistry.cxx"
 #include "ioPtaDatagramFloat.cxx"
 #include "ioPtaDatagramFloat.cxx"
 #include "ioPtaDatagramInt.cxx"
 #include "ioPtaDatagramInt.cxx"
 #include "ioPtaDatagramShort.cxx"
 #include "ioPtaDatagramShort.cxx"

+ 16 - 16
panda/src/tinydisplay/tinyOsxGraphicsWindow.mm

@@ -419,7 +419,7 @@ OSStatus TinyOsxGraphicsWindow::handleTextInput (EventHandlerCallRef myHandler,
     }
     }
 
 
     for (unsigned int x = 0; x < actualSize/sizeof(UniChar); ++x) {
     for (unsigned int x = 0; x < actualSize/sizeof(UniChar); ++x) {
-      _input_devices[0].keystroke(text[x]);
+      _input_devices[0]->keystroke(text[x]);
     }
     }
     DisposePtr((char *)text);
     DisposePtr((char *)text);
   }
   }
@@ -492,10 +492,10 @@ TinyOsxGraphicsWindow::TinyOsxGraphicsWindow(GraphicsEngine *engine, GraphicsPip
   _current_icon(NULL),
   _current_icon(NULL),
   _ID(id_seed++),
   _ID(id_seed++),
   _originalMode(NULL) {
   _originalMode(NULL) {
- GraphicsWindowInputDevice device =
+  PT(InputDevice) device =
     GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard/mouse");
     GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard/mouse");
   _input_devices.push_back(device);
   _input_devices.push_back(device);
-  _input_devices[0].set_pointer_in_window(0, 0);
+  device->set_pointer_in_window(0, 0);
   _last_key_modifiers = 0;
   _last_key_modifiers = 0;
   _last_buttons = 0;
   _last_buttons = 0;
 
 
@@ -579,7 +579,7 @@ bool TinyOsxGraphicsWindow::set_icon_filename(const Filename &icon_filename) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void TinyOsxGraphicsWindow::
 void TinyOsxGraphicsWindow::
 set_pointer_in_window(int x, int y) {
 set_pointer_in_window(int x, int y) {
-  _input_devices[0].set_pointer_in_window(x, y);
+  _input_devices[0]->set_pointer_in_window(x, y);
 
 
   if (_cursor_hidden != _display_hide_cursor) {
   if (_cursor_hidden != _display_hide_cursor) {
     if (_cursor_hidden) {
     if (_cursor_hidden) {
@@ -600,7 +600,7 @@ set_pointer_in_window(int x, int y) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void TinyOsxGraphicsWindow::
 void TinyOsxGraphicsWindow::
 set_pointer_out_of_window() {
 set_pointer_out_of_window() {
-  _input_devices[0].set_pointer_out_of_window();
+  _input_devices[0]->set_pointer_out_of_window();
 
 
   if (_display_hide_cursor) {
   if (_display_hide_cursor) {
     CGDisplayShowCursor(kCGDirectMainDisplay);
     CGDisplayShowCursor(kCGDirectMainDisplay);
@@ -1333,13 +1333,13 @@ void TinyOsxGraphicsWindow::SystemPointToLocalPoint(Point &qdGlobalPoint) {
 	_wheel_delta += this_wheel_delta;
 	_wheel_delta += this_wheel_delta;
 	SInt32 wheel_scale = osx_mouse_wheel_scale;
 	SInt32 wheel_scale = osx_mouse_wheel_scale;
 	while (_wheel_delta > wheel_scale) {
 	while (_wheel_delta > wheel_scale) {
-	  _input_devices[0].button_down(MouseButton::wheel_up());
-	  _input_devices[0].button_up(MouseButton::wheel_up());
+	  _input_devices[0]->button_down(MouseButton::wheel_up());
+	  _input_devices[0]->button_up(MouseButton::wheel_up());
 	  _wheel_delta -= wheel_scale;
 	  _wheel_delta -= wheel_scale;
 	}
 	}
 	while (_wheel_delta < -wheel_scale) {
 	while (_wheel_delta < -wheel_scale) {
-	  _input_devices[0].button_down(MouseButton::wheel_down());
-	  _input_devices[0].button_up(MouseButton::wheel_down());
+	  _input_devices[0]->button_down(MouseButton::wheel_down());
+	  _input_devices[0]->button_up(MouseButton::wheel_down());
 	  _wheel_delta += wheel_scale;
 	  _wheel_delta += wheel_scale;
 	}
 	}
       }
       }
@@ -1519,25 +1519,25 @@ HandleButtonDelta(UInt32 new_buttons) {
 
 
   if (changed & 0x01) {
   if (changed & 0x01) {
     if (new_buttons & 0x01) {
     if (new_buttons & 0x01) {
-      _input_devices[0].button_down(MouseButton::one());
+      _input_devices[0]->button_down(MouseButton::one());
     } else {
     } else {
-      _input_devices[0].button_up(MouseButton::one());
+      _input_devices[0]->button_up(MouseButton::one());
     }
     }
   }
   }
 
 
   if (changed & 0x04) {
   if (changed & 0x04) {
     if (new_buttons & 0x04) {
     if (new_buttons & 0x04) {
-      _input_devices[0].button_down(MouseButton::two());
+      _input_devices[0]->button_down(MouseButton::two());
     } else {
     } else {
-      _input_devices[0].button_up(MouseButton::two());
+      _input_devices[0]->button_up(MouseButton::two());
     }
     }
   }
   }
 
 
   if (changed & 0x02) {
   if (changed & 0x02) {
     if (new_buttons & 0x02) {
     if (new_buttons & 0x02) {
-      _input_devices[0].button_down(MouseButton::three());
+      _input_devices[0]->button_down(MouseButton::three());
     } else {
     } else {
-      _input_devices[0].button_up(MouseButton::three());
+      _input_devices[0]->button_up(MouseButton::three());
     }
     }
   }
   }
 
 
@@ -1745,7 +1745,7 @@ void TinyOsxGraphicsWindow::set_properties_now(WindowProperties &properties) {
   if (properties.has_cursor_hidden()) {
   if (properties.has_cursor_hidden()) {
     _properties.set_cursor_hidden(properties.get_cursor_hidden());
     _properties.set_cursor_hidden(properties.get_cursor_hidden());
     _cursor_hidden = properties.get_cursor_hidden();
     _cursor_hidden = properties.get_cursor_hidden();
-    if (_cursor_hidden && _input_devices[0].has_pointer()) {
+    if (_cursor_hidden && _input_devices[0]->has_pointer()) {
       if (!_display_hide_cursor) {
       if (!_display_hide_cursor) {
         CGDisplayHideCursor(kCGDirectMainDisplay);
         CGDisplayHideCursor(kCGDirectMainDisplay);
         _display_hide_cursor = true;
         _display_hide_cursor = true;

+ 9 - 11
panda/src/tinydisplay/tinySDLGraphicsWindow.cxx

@@ -46,9 +46,7 @@ TinySDLGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
   _pitch = 0;
   _pitch = 0;
   update_pixel_factor();
   update_pixel_factor();
 
 
-  GraphicsWindowInputDevice device =
-    GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard_mouse");
-  add_input_device(device);
+  add_input_device(GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard_mouse"));
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -184,35 +182,35 @@ process_events() {
     switch(evt.type) {
     switch(evt.type) {
     case SDL_KEYDOWN:
     case SDL_KEYDOWN:
       if (evt.key.keysym.unicode) {
       if (evt.key.keysym.unicode) {
-        _input_devices[0].keystroke(evt.key.keysym.unicode);
+        _input_devices[0]->keystroke(evt.key.keysym.unicode);
       }
       }
       button = get_keyboard_button(evt.key.keysym.sym);
       button = get_keyboard_button(evt.key.keysym.sym);
       if (button != ButtonHandle::none()) {
       if (button != ButtonHandle::none()) {
-        _input_devices[0].button_down(button);
+        _input_devices[0]->button_down(button);
       }
       }
       break;
       break;
 
 
     case SDL_KEYUP:
     case SDL_KEYUP:
       button = get_keyboard_button(evt.key.keysym.sym);
       button = get_keyboard_button(evt.key.keysym.sym);
       if (button != ButtonHandle::none()) {
       if (button != ButtonHandle::none()) {
-        _input_devices[0].button_up(button);
+        _input_devices[0]->button_up(button);
       }
       }
       break;
       break;
 
 
     case SDL_MOUSEBUTTONDOWN:
     case SDL_MOUSEBUTTONDOWN:
       button = get_mouse_button(evt.button.button);
       button = get_mouse_button(evt.button.button);
-      _input_devices[0].set_pointer_in_window(evt.button.x, evt.button.y);
-      _input_devices[0].button_down(button);
+      _input_devices[0]->set_pointer_in_window(evt.button.x, evt.button.y);
+      _input_devices[0]->button_down(button);
       break;
       break;
 
 
     case SDL_MOUSEBUTTONUP:
     case SDL_MOUSEBUTTONUP:
       button = get_mouse_button(evt.button.button);
       button = get_mouse_button(evt.button.button);
-      _input_devices[0].set_pointer_in_window(evt.button.x, evt.button.y);
-      _input_devices[0].button_up(button);
+      _input_devices[0]->set_pointer_in_window(evt.button.x, evt.button.y);
+      _input_devices[0]->button_up(button);
       break;
       break;
 
 
     case SDL_MOUSEMOTION:
     case SDL_MOUSEMOTION:
-      _input_devices[0].set_pointer_in_window(evt.motion.x, evt.motion.y);
+      _input_devices[0]->set_pointer_in_window(evt.motion.x, evt.motion.y);
       break;
       break;
      
      
     case SDL_VIDEORESIZE:
     case SDL_VIDEORESIZE:

+ 9 - 11
panda/src/tinydisplay/tinyXGraphicsWindow.cxx

@@ -215,9 +215,7 @@ process_events() {
   if (_xwindow == (X11_Window)0) {
   if (_xwindow == (X11_Window)0) {
     return;
     return;
   }
   }
-  
-  poll_raw_mice();
-  
+
   XEvent event;
   XEvent event;
   XKeyEvent keyrelease_event;
   XKeyEvent keyrelease_event;
   bool got_keyrelease_event = false;
   bool got_keyrelease_event = false;
@@ -294,18 +292,18 @@ process_events() {
     case ButtonPress:
     case ButtonPress:
       // This refers to the mouse buttons.
       // This refers to the mouse buttons.
       button = get_mouse_button(event.xbutton);
       button = get_mouse_button(event.xbutton);
-      _input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y);
-      _input_devices[0].button_down(button);
+      _input->set_pointer_in_window(event.xbutton.x, event.xbutton.y);
+      _input->button_down(button);
       break;
       break;
       
       
     case ButtonRelease:
     case ButtonRelease:
       button = get_mouse_button(event.xbutton);
       button = get_mouse_button(event.xbutton);
-      _input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y);
-      _input_devices[0].button_up(button);
+      _input->set_pointer_in_window(event.xbutton.x, event.xbutton.y);
+      _input->button_up(button);
       break;
       break;
 
 
     case MotionNotify:
     case MotionNotify:
-      _input_devices[0].set_pointer_in_window(event.xmotion.x, event.xmotion.y);
+      _input->set_pointer_in_window(event.xmotion.x, event.xmotion.y);
       break;
       break;
 
 
     case KeyPress:
     case KeyPress:
@@ -322,11 +320,11 @@ process_events() {
       break;
       break;
 
 
     case EnterNotify:
     case EnterNotify:
-      _input_devices[0].set_pointer_in_window(event.xcrossing.x, event.xcrossing.y);
+      _input->set_pointer_in_window(event.xcrossing.x, event.xcrossing.y);
       break;
       break;
 
 
     case LeaveNotify:
     case LeaveNotify:
-      _input_devices[0].set_pointer_out_of_window();
+      _input->set_pointer_out_of_window();
       break;
       break;
 
 
     case FocusIn:
     case FocusIn:
@@ -335,7 +333,7 @@ process_events() {
       break;
       break;
 
 
     case FocusOut:
     case FocusOut:
-      _input_devices[0].focus_lost();
+      _input->focus_lost();
       properties.set_foreground(false);
       properties.set_foreground(false);
       system_changed_properties(properties);
       system_changed_properties(properties);
       break;
       break;

+ 0 - 2
panda/src/vrpn/vrpnAnalog.cxx

@@ -115,7 +115,6 @@ vrpn_analog_callback(void *userdata, const vrpn_ANALOGCB 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) {
     VrpnAnalogDevice *device = (*di);
     VrpnAnalogDevice *device = (*di);
-    device->acquire();
     for (int i = 0; i < info.num_channel; i++) {
     for (int i = 0; i < info.num_channel; i++) {
       if (vrpn_cat.is_debug()) {
       if (vrpn_cat.is_debug()) {
         if (device->get_control_state(i) != info.channel[i]) {
         if (device->get_control_state(i) != info.channel[i]) {
@@ -125,6 +124,5 @@ vrpn_analog_callback(void *userdata, const vrpn_ANALOGCB info) {
       }
       }
       device->set_control_state(i, info.channel[i]);
       device->set_control_state(i, info.channel[i]);
     }
     }
-    device->unlock();
   }
   }
 }
 }

+ 0 - 2
panda/src/vrpn/vrpnButton.cxx

@@ -119,8 +119,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->acquire();
     device->set_button_state(info.button, info.state != 0);
     device->set_button_state(info.button, info.state != 0);
-    device->unlock();
   }
   }
 }
 }

+ 0 - 2
panda/src/vrpn/vrpnDial.cxx

@@ -120,8 +120,6 @@ vrpn_dial_callback(void *userdata, const vrpn_DIALCB 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) {
     VrpnDialDevice *device = (*di);
     VrpnDialDevice *device = (*di);
-    device->acquire();
     device->push_dial(info.dial, info.change);
     device->push_dial(info.dial, info.change);
-    device->unlock();
   }
   }
 }
 }

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

@@ -123,11 +123,10 @@ vrpn_position_callback(void *userdata, const vrpn_TRACKERCB info) {
     VrpnTrackerDevice *device = (*di);
     VrpnTrackerDevice *device = (*di);
     if (device->get_sensor() == info.sensor &&
     if (device->get_sensor() == info.sensor &&
         device->get_data_type() == VrpnTrackerDevice::DT_position) {
         device->get_data_type() == VrpnTrackerDevice::DT_position) {
-      device->acquire();
-      device->_data.set_time(VrpnClient::convert_to_secs(info.msg_time));
-      device->_data.set_pos(LPoint3(info.pos[0], info.pos[1], info.pos[2]));
-      device->_data.set_orient(LOrientation(info.quat[3], info.quat[0], info.quat[1], info.quat[2]));
-      device->unlock();
+      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));
     }
     }
   }
   }
 }
 }
@@ -152,13 +151,10 @@ vrpn_velocity_callback(void *userdata, const vrpn_TRACKERVELCB info) {
     VrpnTrackerDevice *device = (*di);
     VrpnTrackerDevice *device = (*di);
     if (device->get_sensor() == info.sensor &&
     if (device->get_sensor() == info.sensor &&
         device->get_data_type() == VrpnTrackerDevice::DT_velocity) {
         device->get_data_type() == VrpnTrackerDevice::DT_velocity) {
-      device->acquire();
-      device->_data.set_time(VrpnClient::convert_to_secs(info.msg_time));
-      device->_data.set_pos(LPoint3(info.vel[0], info.vel[1], info.vel[2]));
-      device->_data.set_orient(LOrientation(info.vel_quat[3], info.vel_quat[0],
-                                             info.vel_quat[1], info.vel_quat[2]));
-      device->_data.set_dt(info.vel_quat_dt);
-      device->unlock();
+      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));
     }
     }
   }
   }
 }
 }
@@ -183,13 +179,10 @@ vrpn_acceleration_callback(void *userdata, const vrpn_TRACKERACCCB info) {
     VrpnTrackerDevice *device = (*di);
     VrpnTrackerDevice *device = (*di);
     if (device->get_sensor() == info.sensor &&
     if (device->get_sensor() == info.sensor &&
         device->get_data_type() == VrpnTrackerDevice::DT_acceleration) {
         device->get_data_type() == VrpnTrackerDevice::DT_acceleration) {
-      device->acquire();
-      device->_data.set_time(VrpnClient::convert_to_secs(info.msg_time));
-      device->_data.set_pos(LPoint3(info.acc[0], info.acc[1], info.acc[2]));
-      device->_data.set_orient(LOrientation(info.acc_quat[3], info.acc_quat[0],
-                                             info.acc_quat[1], info.acc_quat[2]));
-      device->_data.set_dt(info.acc_quat_dt);
-      device->unlock();
+      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));
     }
     }
   }
   }
 }
 }

+ 3 - 3
panda/src/windisplay/winGraphicsWindow.cxx

@@ -2786,9 +2786,9 @@ handle_raw_input(HRAWINPUT hraw) {
       if (raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) {
       if (raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) {
         _input_devices[i].set_pointer_in_window(adjx, adjy);
         _input_devices[i].set_pointer_in_window(adjx, adjy);
       } else {
       } else {
-        int oldx = _input_devices[i].get_raw_pointer().get_x();
-        int oldy = _input_devices[i].get_raw_pointer().get_y();
-        _input_devices[i].set_pointer_in_window(oldx + adjx, oldy + adjy);
+        //int oldx = _input_devices[i].get_raw_pointer().get_x();
+        //int oldy = _input_devices[i].get_raw_pointer().get_y();
+        //_input_devices[i].set_pointer_in_window(oldx + adjx, oldy + adjy);
       }
       }
 
 
       if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) {
       if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) {

+ 78 - 269
panda/src/x11display/x11GraphicsWindow.cxx

@@ -28,14 +28,10 @@
 #include "nativeWindowHandle.h"
 #include "nativeWindowHandle.h"
 #include "virtualFileSystem.h"
 #include "virtualFileSystem.h"
 #include "get_x11.h"
 #include "get_x11.h"
+#include "evdevInputDevice.h"
 
 
-#include <errno.h>
-#include <fcntl.h>
 #include <sys/time.h>
 #include <sys/time.h>
-
-#ifdef PHAVE_LINUX_INPUT_H
-#include <linux/input.h>
-#endif
+#include <fcntl.h>
 
 
 #ifdef HAVE_XCURSOR
 #ifdef HAVE_XCURSOR
 static int xcursor_read(XcursorFile *file, unsigned char *buf, int len) {
 static int xcursor_read(XcursorFile *file, unsigned char *buf, int len) {
@@ -69,8 +65,6 @@ static int xcursor_seek(XcursorFile *file, long offset, int whence) {
 
 
 TypeHandle x11GraphicsWindow::_type_handle;
 TypeHandle x11GraphicsWindow::_type_handle;
 
 
-#define test_bit(bit, array) ((array)[(bit)/8] & (1<<((bit)&7)))
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: x11GraphicsWindow::Constructor
 //     Function: x11GraphicsWindow::Constructor
 //       Access: Public
 //       Access: Public
@@ -107,9 +101,9 @@ x11GraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
   _override_redirect = False;
   _override_redirect = False;
   _wm_delete_window = x11_pipe->_wm_delete_window;
   _wm_delete_window = x11_pipe->_wm_delete_window;
 
 
-  GraphicsWindowInputDevice device =
-    GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard_mouse");
+  PT(GraphicsWindowInputDevice) device = GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard_mouse");
   add_input_device(device);
   add_input_device(device);
+  _input = device;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -143,26 +137,26 @@ move_pointer(int device, int x, int y) {
   if (device == 0) {
   if (device == 0) {
     // Move the system mouse pointer.
     // Move the system mouse pointer.
     if (!_properties.get_foreground() ||
     if (!_properties.get_foreground() ||
-        !_input_devices[0].get_pointer().get_in_window()) {
+        !_input->get_pointer().get_in_window()) {
       // If the window doesn't have input focus, or the mouse isn't
       // If the window doesn't have input focus, or the mouse isn't
       // currently within the window, forget it.
       // currently within the window, forget it.
       return false;
       return false;
     }
     }
 
 
-    const MouseData &md = _input_devices[0].get_pointer();
+    const MouseData &md = _input->get_pointer();
     if (!md.get_in_window() || md.get_x() != x || md.get_y() != y) {
     if (!md.get_in_window() || md.get_x() != x || md.get_y() != y) {
       if (!_dga_mouse_enabled) {
       if (!_dga_mouse_enabled) {
         XWarpPointer(_display, None, _xwindow, 0, 0, 0, 0, x, y);
         XWarpPointer(_display, None, _xwindow, 0, 0, 0, 0, x, y);
       }
       }
-      _input_devices[0].set_pointer_in_window(x, y);
+      _input->set_pointer_in_window(x, y);
     }
     }
     return true;
     return true;
   } else {
   } else {
     // Move a raw mouse.
     // Move a raw mouse.
-    if ((device < 1)||(device >= _input_devices.size())) {
+    if (device < 1 || device >= _input_devices.size()) {
       return false;
       return false;
     }
     }
-    _input_devices[device].set_pointer_in_window(x, y);
+    //_input_devices[device]->set_pointer_in_window(x, y);
     return true;
     return true;
   }
   }
 }
 }
@@ -249,8 +243,6 @@ process_events() {
     return;
     return;
   }
   }
 
 
-  poll_raw_mice();
-
   XEvent event;
   XEvent event;
   XKeyEvent keyrelease_event;
   XKeyEvent keyrelease_event;
   bool got_keyrelease_event = false;
   bool got_keyrelease_event = false;
@@ -311,25 +303,25 @@ process_events() {
       // This refers to the mouse buttons.
       // This refers to the mouse buttons.
       button = get_mouse_button(event.xbutton);
       button = get_mouse_button(event.xbutton);
       if (!_dga_mouse_enabled) {
       if (!_dga_mouse_enabled) {
-        _input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y);
+        _input->set_pointer_in_window(event.xbutton.x, event.xbutton.y);
       }
       }
-      _input_devices[0].button_down(button);
+      _input->button_down(button);
       break;
       break;
 
 
     case ButtonRelease:
     case ButtonRelease:
       button = get_mouse_button(event.xbutton);
       button = get_mouse_button(event.xbutton);
       if (!_dga_mouse_enabled) {
       if (!_dga_mouse_enabled) {
-        _input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y);
+        _input->set_pointer_in_window(event.xbutton.x, event.xbutton.y);
       }
       }
-      _input_devices[0].button_up(button);
+      _input->button_up(button);
       break;
       break;
 
 
     case MotionNotify:
     case MotionNotify:
       if (_dga_mouse_enabled) {
       if (_dga_mouse_enabled) {
-        const MouseData &md = _input_devices[0].get_raw_pointer();
-        _input_devices[0].set_pointer_in_window(md.get_x() + event.xmotion.x_root, md.get_y() + event.xmotion.y_root);
+        const MouseData &md = _input->get_pointer();
+        _input->set_pointer_in_window(md.get_x() + event.xmotion.x_root, md.get_y() + event.xmotion.y_root);
       } else {
       } else {
-        _input_devices[0].set_pointer_in_window(event.xmotion.x, event.xmotion.y);
+        _input->set_pointer_in_window(event.xmotion.x, event.xmotion.y);
       }
       }
       break;
       break;
 
 
@@ -348,15 +340,15 @@ process_events() {
 
 
     case EnterNotify:
     case EnterNotify:
       if (_dga_mouse_enabled) {
       if (_dga_mouse_enabled) {
-        const MouseData &md = _input_devices[0].get_raw_pointer();
-        _input_devices[0].set_pointer_in_window(md.get_x(), md.get_y());
+        const MouseData &md = _input->get_pointer();
+        _input->set_pointer_in_window(md.get_x(), md.get_y());
       } else {
       } else {
-        _input_devices[0].set_pointer_in_window(event.xcrossing.x, event.xcrossing.y);
+        _input->set_pointer_in_window(event.xcrossing.x, event.xcrossing.y);
       }
       }
       break;
       break;
 
 
     case LeaveNotify:
     case LeaveNotify:
-      _input_devices[0].set_pointer_out_of_window();
+      _input->set_pointer_out_of_window();
       break;
       break;
 
 
     case FocusIn:
     case FocusIn:
@@ -365,7 +357,7 @@ process_events() {
       break;
       break;
 
 
     case FocusOut:
     case FocusOut:
-      _input_devices[0].focus_lost();
+      _input->focus_lost();
       properties.set_foreground(false);
       properties.set_foreground(false);
       changed_properties = true;
       changed_properties = true;
       break;
       break;
@@ -751,7 +743,7 @@ set_properties_now(WindowProperties &properties) {
             XQueryPointer(_display, _xwindow, &event.xbutton.root,
             XQueryPointer(_display, _xwindow, &event.xbutton.root,
               &event.xbutton.window, &event.xbutton.x_root, &event.xbutton.y_root,
               &event.xbutton.window, &event.xbutton.x_root, &event.xbutton.y_root,
               &event.xbutton.x, &event.xbutton.y, &event.xbutton.state);
               &event.xbutton.x, &event.xbutton.y, &event.xbutton.state);
-            _input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y);
+            _input->set_pointer_in_window(event.xbutton.x, event.xbutton.y);
           }
           }
         } else {
         } else {
           x11display_cat.info() << "XF86DGA extension not available\n";
           x11display_cat.info() << "XF86DGA extension not available\n";
@@ -1295,66 +1287,43 @@ open_raw_mice() {
   bool any_mice = false;
   bool any_mice = false;
 
 
   for (int i=0; i<64; i++) {
   for (int i=0; i<64; i++) {
-    uint8_t evtypes[EV_MAX/8 + 1];
     ostringstream fnb;
     ostringstream fnb;
     fnb << "/dev/input/event" << i;
     fnb << "/dev/input/event" << i;
     string fn = fnb.str();
     string fn = fnb.str();
     int fd = open(fn.c_str(), O_RDONLY | O_NONBLOCK, 0);
     int fd = open(fn.c_str(), O_RDONLY | O_NONBLOCK, 0);
     if (fd >= 0) {
     if (fd >= 0) {
-      any_present = true;
-      char name[256];
-      char phys[256];
-      char uniq[256];
-      if ((ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0)||
-          (ioctl(fd, EVIOCGPHYS(sizeof(phys)), phys) < 0)||
-          (ioctl(fd, EVIOCGPHYS(sizeof(uniq)), uniq) < 0)||
-          (ioctl(fd, EVIOCGBIT(0, EV_MAX), &evtypes) < 0)) {
-        close(fd);
-        x11display_cat.error() <<
-          "Opening raw mice: ioctl failed on " << fn << "\n";
-      } else {
-        if (test_bit(EV_REL, evtypes) || test_bit(EV_ABS, evtypes)) {
-          for (char *p=name; *p; p++) {
-            if (((*p<'a')||(*p>'z')) && ((*p<'A')||(*p>'Z')) && ((*p<'0')||(*p>'9'))) {
-              *p = '_';
-            }
-          }
-          for (char *p=uniq; *p; p++) {
-            if (((*p<'a')||(*p>'z')) && ((*p<'A')||(*p>'Z')) && ((*p<'0')||(*p>'9'))) {
-              *p = '_';
-            }
-          }
-          string full_id = ((string)name) + "." + uniq;
-          MouseDeviceInfo inf;
-          inf._fd = fd;
-          inf._input_device_index = _input_devices.size();
-          inf._io_buffer = "";
-          _mouse_device_info.push_back(inf);
-          GraphicsWindowInputDevice device =
-            GraphicsWindowInputDevice::pointer_only(this, full_id);
-          add_input_device(device);
-          x11display_cat.info() << "Raw mouse " <<
-            inf._input_device_index << " detected: " << full_id << "\n";
-          any_mice = true;
-        } else {
-          close(fd);
-        }
+      EvdevInputDevice *device = new EvdevInputDevice(fd);
+      nassertd(device != NULL) continue;
+
+      if (device->has_pointer()) {
+        add_input_device(device);
+
+        x11display_cat.info()
+          << "Raw mouse " << _input_devices.size()
+          << " detected: " << device->get_name() << "\n";
+
+        any_mice = true;
+        any_present = true;
       }
       }
     } else {
     } else {
-      if ((errno == ENOENT)||(errno == ENOTDIR)) {
+      if (errno == ENOENT || errno == ENOTDIR) {
         break;
         break;
       } else {
       } else {
         any_present = true;
         any_present = true;
-        x11display_cat.error() <<
-          "Opening raw mice: " << strerror(errno) << " " << fn << "\n";
+        x11display_cat.error()
+          << "Opening raw mice: " << strerror(errno) << " " << fn << "\n";
       }
       }
     }
     }
   }
   }
 
 
-  if (!any_present) {
+  if (any_mice) {
+    _properties.set_raw_mice(true);
+
+  } else if (!any_present) {
     x11display_cat.error() <<
     x11display_cat.error() <<
       "Opening raw mice: files not found: /dev/input/event*\n";
       "Opening raw mice: files not found: /dev/input/event*\n";
-  } else if (!any_mice) {
+
+  } else {
     x11display_cat.error() <<
     x11display_cat.error() <<
       "Opening raw mice: no mouse devices detected in /dev/input/event*\n";
       "Opening raw mice: no mouse devices detected in /dev/input/event*\n";
   }
   }
@@ -1364,69 +1333,6 @@ open_raw_mice() {
 #endif
 #endif
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: x11GraphicsWindow::poll_raw_mice
-//       Access: Private
-//  Description: Reads events from the raw mouse device files.
-////////////////////////////////////////////////////////////////////
-void x11GraphicsWindow::
-poll_raw_mice() {
-#ifdef PHAVE_LINUX_INPUT_H
-  for (int di = 0; di < _mouse_device_info.size(); ++di) {
-    MouseDeviceInfo &inf = _mouse_device_info[di];
-
-    // Read all bytes into buffer.
-    if (inf._fd >= 0) {
-      while (1) {
-        char tbuf[1024];
-        int nread = read(inf._fd, tbuf, sizeof(tbuf));
-        if (nread > 0) {
-          inf._io_buffer += string(tbuf, nread);
-        } else {
-          if ((nread < 0) && ((errno == EWOULDBLOCK) || (errno==EAGAIN))) {
-            break;
-          }
-          close(inf._fd);
-          inf._fd = -1;
-          break;
-        }
-      }
-    }
-
-    // Process events.
-    int nevents = inf._io_buffer.size() / sizeof(struct input_event);
-    if (nevents == 0) {
-      continue;
-    }
-    const input_event *events = (const input_event *)(inf._io_buffer.c_str());
-    GraphicsWindowInputDevice &dev = _input_devices[inf._input_device_index];
-    int x = dev.get_raw_pointer().get_x();
-    int y = dev.get_raw_pointer().get_y();
-    for (int i = 0; i < nevents; i++) {
-      if (events[i].type == EV_REL) {
-        if (events[i].code == REL_X) x += events[i].value;
-        if (events[i].code == REL_Y) y += events[i].value;
-      } else if (events[i].type == EV_ABS) {
-        if (events[i].code == ABS_X) x = events[i].value;
-        if (events[i].code == ABS_Y) y = events[i].value;
-      } else if (events[i].type == EV_KEY) {
-        if ((events[i].code >= BTN_MOUSE) && (events[i].code < BTN_MOUSE + 8)) {
-          int btn = events[i].code - BTN_MOUSE;
-          dev.set_pointer_in_window(x, y);
-          if (events[i].value) {
-            dev.button_down(MouseButton::button(btn));
-          } else {
-            dev.button_up(MouseButton::button(btn));
-          }
-        }
-      }
-    }
-    inf._io_buffer.erase(0, nevents * sizeof(struct input_event));
-    dev.set_pointer_in_window(x, y);
-  }
-#endif
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: x11GraphicsWindow::handle_keystroke
 //     Function: x11GraphicsWindow::handle_keystroke
 //       Access: Private
 //       Access: Private
@@ -1436,7 +1342,7 @@ poll_raw_mice() {
 void x11GraphicsWindow::
 void x11GraphicsWindow::
 handle_keystroke(XKeyEvent &event) {
 handle_keystroke(XKeyEvent &event) {
   if (!_dga_mouse_enabled) {
   if (!_dga_mouse_enabled) {
-    _input_devices[0].set_pointer_in_window(event.x, event.y);
+    _input->set_pointer_in_window(event.x, event.y);
   }
   }
 
 
   if (_ic) {
   if (_ic) {
@@ -1454,14 +1360,14 @@ handle_keystroke(XKeyEvent &event) {
     // Now each of the returned wide characters represents a
     // Now each of the returned wide characters represents a
     // keystroke.
     // keystroke.
     for (int i = 0; i < len; i++) {
     for (int i = 0; i < len; i++) {
-      _input_devices[0].keystroke(buffer[i]);
+      _input->keystroke(buffer[i]);
     }
     }
 
 
   } else {
   } else {
     // Without an input context, just get the ascii keypress.
     // Without an input context, just get the ascii keypress.
     ButtonHandle button = get_button(event, true);
     ButtonHandle button = get_button(event, true);
     if (button.has_ascii_equivalent()) {
     if (button.has_ascii_equivalent()) {
-      _input_devices[0].keystroke(button.get_ascii_equivalent());
+      _input->keystroke(button.get_ascii_equivalent());
     }
     }
   }
   }
 }
 }
@@ -1475,30 +1381,32 @@ handle_keystroke(XKeyEvent &event) {
 void x11GraphicsWindow::
 void x11GraphicsWindow::
 handle_keypress(XKeyEvent &event) {
 handle_keypress(XKeyEvent &event) {
   if (!_dga_mouse_enabled) {
   if (!_dga_mouse_enabled) {
-    _input_devices[0].set_pointer_in_window(event.x, event.y);
+    _input->set_pointer_in_window(event.x, event.y);
   }
   }
 
 
   // Now get the raw unshifted button.
   // Now get the raw unshifted button.
   ButtonHandle button = get_button(event, false);
   ButtonHandle button = get_button(event, false);
   if (button != ButtonHandle::none()) {
   if (button != ButtonHandle::none()) {
     if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) {
     if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) {
-      _input_devices[0].button_down(KeyboardButton::control());
+      _input->button_down(KeyboardButton::control());
     }
     }
     if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) {
     if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) {
-      _input_devices[0].button_down(KeyboardButton::shift());
+      _input->button_down(KeyboardButton::shift());
     }
     }
     if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) {
     if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) {
-      _input_devices[0].button_down(KeyboardButton::alt());
+      _input->button_down(KeyboardButton::alt());
     }
     }
     if (button == KeyboardButton::lmeta() || button == KeyboardButton::rmeta()) {
     if (button == KeyboardButton::lmeta() || button == KeyboardButton::rmeta()) {
-      _input_devices[0].button_down(KeyboardButton::meta());
+      _input->button_down(KeyboardButton::meta());
     }
     }
-    _input_devices[0].button_down(button);
+    _input->button_down(button);
   }
   }
 
 
-  ButtonHandle raw_button = map_raw_button(event.keycode);
-  if (raw_button != ButtonHandle::none()) {
-    _input_devices[0].raw_button_down(raw_button);
+  if (event.keycode >= 9 && event.keycode <= 135) {
+    ButtonHandle raw_button = map_raw_button(event.keycode);
+    if (raw_button != ButtonHandle::none()) {
+      _input->raw_button_down(raw_button);
+    }
   }
   }
 }
 }
 
 
@@ -1511,30 +1419,32 @@ handle_keypress(XKeyEvent &event) {
 void x11GraphicsWindow::
 void x11GraphicsWindow::
 handle_keyrelease(XKeyEvent &event) {
 handle_keyrelease(XKeyEvent &event) {
   if (!_dga_mouse_enabled) {
   if (!_dga_mouse_enabled) {
-    _input_devices[0].set_pointer_in_window(event.x, event.y);
+    _input->set_pointer_in_window(event.x, event.y);
   }
   }
 
 
   // Now get the raw unshifted button.
   // Now get the raw unshifted button.
   ButtonHandle button = get_button(event, false);
   ButtonHandle button = get_button(event, false);
   if (button != ButtonHandle::none()) {
   if (button != ButtonHandle::none()) {
     if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) {
     if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) {
-      _input_devices[0].button_up(KeyboardButton::control());
+      _input->button_up(KeyboardButton::control());
     }
     }
     if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) {
     if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) {
-      _input_devices[0].button_up(KeyboardButton::shift());
+      _input->button_up(KeyboardButton::shift());
     }
     }
     if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) {
     if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) {
-      _input_devices[0].button_up(KeyboardButton::alt());
+      _input->button_up(KeyboardButton::alt());
     }
     }
     if (button == KeyboardButton::lmeta() || button == KeyboardButton::rmeta()) {
     if (button == KeyboardButton::lmeta() || button == KeyboardButton::rmeta()) {
-      _input_devices[0].button_up(KeyboardButton::meta());
+      _input->button_up(KeyboardButton::meta());
     }
     }
-    _input_devices[0].button_up(button);
+    _input->button_up(button);
   }
   }
 
 
-  ButtonHandle raw_button = map_raw_button(event.keycode);
-  if (raw_button != ButtonHandle::none()) {
-    _input_devices[0].raw_button_up(raw_button);
+  if (event.keycode >= 9 && event.keycode <= 135) {
+    ButtonHandle raw_button = map_raw_button(event.keycode);
+    if (raw_button != ButtonHandle::none()) {
+      _input->raw_button_up(raw_button);
+    }
   }
   }
 }
 }
 
 
@@ -1617,7 +1527,7 @@ get_button(XKeyEvent &key_event, bool allow_shift) {
     // can do this in just the ASCII set, because we handle
     // can do this in just the ASCII set, because we handle
     // international keyboards elsewhere (via an input context).
     // international keyboards elsewhere (via an input context).
     if ((key_event.state & (ShiftMask | LockMask)) != 0) {
     if ((key_event.state & (ShiftMask | LockMask)) != 0) {
-      if (key >= XK_a and key <= XK_z) {
+      if (key >= XK_a && key <= XK_z) {
         key += (XK_A - XK_a);
         key += (XK_A - XK_a);
       }
       }
     }
     }
@@ -1962,117 +1872,16 @@ map_button(KeySym key) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 ButtonHandle x11GraphicsWindow::
 ButtonHandle x11GraphicsWindow::
 map_raw_button(KeyCode key) const {
 map_raw_button(KeyCode key) const {
-  switch (key) {
-  case 9:  return KeyboardButton::escape();
-  case 10: return KeyboardButton::ascii_key('1');
-  case 11: return KeyboardButton::ascii_key('2');
-  case 12: return KeyboardButton::ascii_key('3');
-  case 13: return KeyboardButton::ascii_key('4');
-  case 14: return KeyboardButton::ascii_key('5');
-  case 15: return KeyboardButton::ascii_key('6');
-  case 16: return KeyboardButton::ascii_key('7');
-  case 17: return KeyboardButton::ascii_key('8');
-  case 18: return KeyboardButton::ascii_key('9');
-  case 19: return KeyboardButton::ascii_key('0');
-  case 20: return KeyboardButton::ascii_key('-');
-  case 21: return KeyboardButton::ascii_key('=');
-  case 22: return KeyboardButton::backspace();
-  case 23: return KeyboardButton::tab();
-  case 24: return KeyboardButton::ascii_key('q');
-  case 25: return KeyboardButton::ascii_key('w');
-  case 26: return KeyboardButton::ascii_key('e');
-  case 27: return KeyboardButton::ascii_key('r');
-  case 28: return KeyboardButton::ascii_key('t');
-  case 29: return KeyboardButton::ascii_key('y');
-  case 30: return KeyboardButton::ascii_key('u');
-  case 31: return KeyboardButton::ascii_key('i');
-  case 32: return KeyboardButton::ascii_key('o');
-  case 33: return KeyboardButton::ascii_key('p');
-  case 34: return KeyboardButton::ascii_key('[');
-  case 35: return KeyboardButton::ascii_key(']');
-  case 36: return KeyboardButton::enter();
-  case 37: return KeyboardButton::lcontrol();
-  case 38: return KeyboardButton::ascii_key('a');
-  case 39: return KeyboardButton::ascii_key('s');
-  case 40: return KeyboardButton::ascii_key('d');
-  case 41: return KeyboardButton::ascii_key('f');
-  case 42: return KeyboardButton::ascii_key('g');
-  case 43: return KeyboardButton::ascii_key('h');
-  case 44: return KeyboardButton::ascii_key('j');
-  case 45: return KeyboardButton::ascii_key('k');
-  case 46: return KeyboardButton::ascii_key('l');
-  case 47: return KeyboardButton::ascii_key(';');
-  case 48: return KeyboardButton::ascii_key('\'');
-  case 49: return KeyboardButton::ascii_key('`');
-  case 50: return KeyboardButton::lshift();
-  case 51: return KeyboardButton::ascii_key('\\');
-  case 52: return KeyboardButton::ascii_key('z');
-  case 53: return KeyboardButton::ascii_key('x');
-  case 54: return KeyboardButton::ascii_key('c');
-  case 55: return KeyboardButton::ascii_key('v');
-  case 56: return KeyboardButton::ascii_key('b');
-  case 57: return KeyboardButton::ascii_key('n');
-  case 58: return KeyboardButton::ascii_key('m');
-  case 59: return KeyboardButton::ascii_key(',');
-  case 60: return KeyboardButton::ascii_key('.');
-  case 61: return KeyboardButton::ascii_key('/');
-  case 62: return KeyboardButton::rshift();
-  case 63: return KeyboardButton::ascii_key('*');
-  case 64: return KeyboardButton::lalt();
-  case 65: return KeyboardButton::space();
-  case 66: return KeyboardButton::caps_lock();
-  case 67: return KeyboardButton::f1();
-  case 68: return KeyboardButton::f2();
-  case 69: return KeyboardButton::f3();
-  case 70: return KeyboardButton::f4();
-  case 71: return KeyboardButton::f5();
-  case 72: return KeyboardButton::f6();
-  case 73: return KeyboardButton::f7();
-  case 74: return KeyboardButton::f8();
-  case 75: return KeyboardButton::f9();
-  case 76: return KeyboardButton::f10();
-  case 77: return KeyboardButton::num_lock();
-  case 78: return KeyboardButton::scroll_lock();
-  case 79: return KeyboardButton::ascii_key('7');
-  case 80: return KeyboardButton::ascii_key('8');
-  case 81: return KeyboardButton::ascii_key('9');
-  case 82: return KeyboardButton::ascii_key('-');
-  case 83: return KeyboardButton::ascii_key('4');
-  case 84: return KeyboardButton::ascii_key('5');
-  case 85: return KeyboardButton::ascii_key('6');
-  case 86: return KeyboardButton::ascii_key('+');
-  case 87: return KeyboardButton::ascii_key('1');
-  case 88: return KeyboardButton::ascii_key('2');
-  case 89: return KeyboardButton::ascii_key('3');
-  case 90: return KeyboardButton::ascii_key('0');
-  case 91: return KeyboardButton::ascii_key('.');
-
-  case 95: return KeyboardButton::f11();
-  case 96: return KeyboardButton::f12();
-
-  case 104: return KeyboardButton::enter();
-  case 105: return KeyboardButton::rcontrol();
-  case 106: return KeyboardButton::ascii_key('/');
-  case 107: return KeyboardButton::print_screen();
-  case 108: return KeyboardButton::ralt();
-
-  case 110: return KeyboardButton::home();
-  case 111: return KeyboardButton::up();
-  case 112: return KeyboardButton::page_up();
-  case 113: return KeyboardButton::left();
-  case 114: return KeyboardButton::right();
-  case 115: return KeyboardButton::end();
-  case 116: return KeyboardButton::down();
-  case 117: return KeyboardButton::page_down();
-  case 118: return KeyboardButton::insert();
-  case 119: return KeyboardButton::del();
-
-  case 127: return KeyboardButton::pause();
-
-  case 133: return KeyboardButton::lmeta();
-  case 134: return KeyboardButton::rmeta();
-  case 135: return KeyboardButton::menu();
+#ifdef PHAVE_LINUX_INPUT_H
+  // Most X11 servers are configured to use the evdev driver, which
+  // adds 8 to the underlying evdev keycodes (not sure why).
+  // In any case, this means we can use the same mapping as our raw
+  // input code, which uses evdev directly.
+  int index = key - 8;
+  if (index >= 0) {
+    return EvdevInputDevice::map_button(index);
   }
   }
+#endif
   return ButtonHandle::none();
   return ButtonHandle::none();
 }
 }
 
 

+ 1 - 1
panda/src/x11display/x11GraphicsWindow.h

@@ -74,7 +74,6 @@ protected:
   static Bool check_event(X11_Display *display, XEvent *event, char *arg);
   static Bool check_event(X11_Display *display, XEvent *event, char *arg);
 
 
   void open_raw_mice();
   void open_raw_mice();
-  void poll_raw_mice();
 
 
 private:
 private:
   X11_Cursor get_cursor(const Filename &filename);
   X11_Cursor get_cursor(const Filename &filename);
@@ -89,6 +88,7 @@ protected:
   Colormap _colormap;
   Colormap _colormap;
   XIC _ic;
   XIC _ic;
   XVisualInfo *_visual_info;
   XVisualInfo *_visual_info;
+  GraphicsWindowInputDevice *_input;
 
 
   bool _have_xrandr;
   bool _have_xrandr;
 #ifdef HAVE_XRANDR
 #ifdef HAVE_XRANDR