Browse Source

Prepare input API for multipointer support

rdb 7 years ago
parent
commit
585ba2d647

+ 7 - 8
panda/src/device/evdevInputDevice.cxx

@@ -557,6 +557,7 @@ init_device() {
 
 
   if (test_bit(EV_REL, evtypes)) {
   if (test_bit(EV_REL, evtypes)) {
     enable_feature(Feature::pointer);
     enable_feature(Feature::pointer);
+    add_pointer(PointerType::unknown, 0);
   }
   }
 
 
   if (test_bit(EV_FF, evtypes)) {
   if (test_bit(EV_FF, evtypes)) {
@@ -669,9 +670,8 @@ process_events() {
 
 
   n_read /= sizeof(struct input_event);
   n_read /= sizeof(struct input_event);
 
 
-  int x = _pointer_data.get_x();
-  int y = _pointer_data.get_y();
-  bool have_pointer = false;
+  int rel_x = 0;
+  int rel_y = 0;
   double time = ClockObject::get_global_clock()->get_frame_time();
   double time = ClockObject::get_global_clock()->get_frame_time();
   int index;
   int index;
 
 
@@ -689,9 +689,8 @@ process_events() {
       break;
       break;
 
 
     case EV_REL:
     case EV_REL:
-      if (code == REL_X) x += events[i].value;
-      if (code == REL_Y) y += events[i].value;
-      have_pointer = true;
+      if (code == REL_X) rel_x += events[i].value;
+      if (code == REL_Y) rel_y += events[i].value;
       break;
       break;
 
 
     case EV_ABS:
     case EV_ABS:
@@ -728,8 +727,8 @@ process_events() {
     }
     }
   }
   }
 
 
-  if (have_pointer) {
-    set_pointer(true, x, y, time);
+  if (rel_x != 0 || rel_y != 0) {
+    pointer_moved(0, rel_x, rel_y, time);
   }
   }
 
 
   return true;
   return true;

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

@@ -19,6 +19,7 @@
 INLINE InputDevice::
 INLINE InputDevice::
 InputDevice() {
 InputDevice() {
   _button_events = new ButtonEventList;
   _button_events = new ButtonEventList;
+  _pointer_events = new PointerEventList;
 }
 }
 
 
 /**
 /**
@@ -142,16 +143,6 @@ has_battery() const {
   return has_feature(Feature::battery);
   return has_feature(Feature::battery);
 }
 }
 
 
-/**
- * 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;
-}
-
 /**
 /**
  * Returns the TrackerData associated with the input device's tracker.  This
  * Returns the TrackerData associated with the input device's tracker.  This
  * only makes sense if has_tracker() also returns true.
  * only makes sense if has_tracker() also returns true.

+ 85 - 37
panda/src/device/inputDevice.cxx

@@ -29,6 +29,7 @@ InputDevice(const std::string &name, DeviceClass dev_class) :
   _is_connected(true)
   _is_connected(true)
 {
 {
   _button_events = new ButtonEventList;
   _button_events = new ButtonEventList;
+  _pointer_events = new PointerEventList;
 }
 }
 
 
 /**
 /**
@@ -80,7 +81,7 @@ get_button_events() {
 bool InputDevice::
 bool InputDevice::
 has_pointer_event() const {
 has_pointer_event() const {
   LightMutexHolder holder(_lock);
   LightMutexHolder holder(_lock);
-  return (_pointer_events != 0);
+  return _pointer_events != nullptr && !_pointer_events->empty();
 }
 }
 
 
 /**
 /**
@@ -90,8 +91,8 @@ has_pointer_event() const {
 PT(PointerEventList) InputDevice::
 PT(PointerEventList) InputDevice::
 get_pointer_events() {
 get_pointer_events() {
   LightMutexHolder holder(_lock);
   LightMutexHolder holder(_lock);
-  PT(PointerEventList) result = _pointer_events;
-  _pointer_events.clear();
+  PT(PointerEventList) result = new PointerEventList;
+  swap(_pointer_events, result);
   return result;
   return result;
 }
 }
 
 
@@ -149,69 +150,116 @@ add_axis(Axis axis, int minimum, int maximum) {
 }
 }
 
 
 /**
 /**
- * Records that a mouse movement has taken place.
+ * Records that a new pointer was found.
+ */
+int InputDevice::
+add_pointer(PointerType type, int id, bool primary) {
+  nassertr(_lock.debug_is_locked(), -1);
+
+  PointerData data;
+  data._id = id;
+  data._type = type;
+
+  int index = (int)_pointers.size();
+  if (_num_pointers == _pointers.size()) {
+    _pointers.push_back(data);
+  } else {
+    _pointers[index] = data;
+  }
+  ++_num_pointers;
+
+  return index;
+}
+
+/**
+ * Removes a previously added pointer.  If the current pressure is not zero,
+ * it will generate an event doing so.
  */
  */
 void InputDevice::
 void InputDevice::
-set_pointer(bool inwin, double x, double y, double time) {
+remove_pointer(int id) {
   nassertv(_lock.debug_is_locked());
   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();
+  size_t i;
+  for (i = 0; i < _pointers.size(); ++i) {
+    if (_pointers[i]._id == id) {
+      break;
     }
     }
-    _pointer_events->add_event(_pointer_data._in_window,
-                               _pointer_data._xpos,
-                               _pointer_data._ypos,
-                               seq, time);
+  }
+
+  if (i < _pointers.size()) {
+    if (_pointers[i]._pressure != 0.0) {
+      _pointers[i]._pressure = 0.0;
+
+      if (_enable_pointer_events) {
+        int seq = _event_sequence++;
+        double time = ClockObject::get_global_clock()->get_frame_time();
+        _pointer_events->add_event(_pointers[i], seq, time);
+      }
+    }
+
+    // Replace it with the last one.
+    if (i != _pointers.size() - 1) {
+      _pointers[i] = _pointers.back();
+    }
+    --_num_pointers;
   }
   }
 }
 }
 
 
 /**
 /**
- * Records that the mouse pointer has left the window.
+ * Records that pointer data for a pointer has changed.  This can also be used
+ * to add a new pointer.
  */
  */
 void InputDevice::
 void InputDevice::
-set_pointer_out_of_window(double time) {
+update_pointer(PointerData data, double time) {
   nassertv(_lock.debug_is_locked());
   nassertv(_lock.debug_is_locked());
-  _pointer_data._in_window = false;
+
+  PointerData *ptr = nullptr;
+  for (size_t i = 0; i < _pointers.size(); ++i) {
+    if (_pointers[i]._id == data._id) {
+      ptr = &_pointers[i];
+      *ptr = data;
+      break;
+    }
+  }
+  if (ptr == nullptr) {
+    _pointers.push_back(data);
+    ptr = &_pointers.back();
+  }
 
 
   if (_enable_pointer_events) {
   if (_enable_pointer_events) {
     int seq = _event_sequence++;
     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);
+    _pointer_events->add_event(*ptr, seq, time);
   }
   }
 }
 }
 
 
 /**
 /**
- * Records that a relative mouse movement has taken place.
+ * Records that a relative pointer movement has taken place.
  */
  */
 void InputDevice::
 void InputDevice::
-pointer_moved(double x, double y, double time) {
+pointer_moved(int id, double x, double y, double time) {
   nassertv(_lock.debug_is_locked());
   nassertv(_lock.debug_is_locked());
-  _pointer_data._xpos += x;
-  _pointer_data._ypos += y;
+
+  PointerData *ptr = nullptr;
+  for (size_t i = 0; i < _pointers.size(); ++i) {
+    if (_pointers[i]._id == id) {
+      ptr = &_pointers[i];
+      _pointers[i]._xpos = x;
+      _pointers[i]._ypos = y;
+      break;
+    }
+  }
+  nassertv_always(ptr != nullptr);
 
 
   if (device_cat.is_spam() && (x != 0 || y != 0)) {
   if (device_cat.is_spam() && (x != 0 || y != 0)) {
     device_cat.spam()
     device_cat.spam()
-      << "Pointer moved by " << x << " x " << y << "\n";
+      << "Pointer " << id << " moved by " << x << " x " << y << "\n";
   }
   }
 
 
   if (_enable_pointer_events) {
   if (_enable_pointer_events) {
     int seq = _event_sequence++;
     int seq = _event_sequence++;
-    if (_pointer_events.is_null()) {
-      _pointer_events = new PointerEventList();
-    }
-    _pointer_events->add_event(_pointer_data._in_window,
-                               _pointer_data._xpos,
-                               _pointer_data._ypos,
+    _pointer_events->add_event(ptr->_in_window,
+                               ptr->_xpos,
+                               ptr->_ypos,
                                x, y, seq, time);
                                x, y, seq, time);
   }
   }
 }
 }

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

@@ -201,7 +201,6 @@ public:
   INLINE bool has_vibration() const;
   INLINE bool has_vibration() const;
   INLINE bool has_battery() const;
   INLINE bool has_battery() const;
 
 
-  INLINE PointerData get_pointer() const;
   INLINE TrackerData get_tracker() const;
   INLINE TrackerData get_tracker() const;
   INLINE BatteryData get_battery() const;
   INLINE BatteryData get_battery() const;
 
 
@@ -244,7 +243,6 @@ PUBLISHED:
   INLINE bool has_feature(Feature feature) const;
   INLINE bool has_feature(Feature feature) const;
 
 
   // Getters for the various types of device data.
   // Getters for the various types of device data.
-  MAKE_PROPERTY2(pointer, has_pointer, get_pointer);
   MAKE_PROPERTY2(tracker, has_tracker, get_tracker);
   MAKE_PROPERTY2(tracker, has_tracker, get_tracker);
   MAKE_PROPERTY2(battery, has_battery, get_battery);
   MAKE_PROPERTY2(battery, has_battery, get_battery);
 
 
@@ -285,10 +283,10 @@ protected:
   int add_axis(Axis axis, int minimum, int maximum, bool centered);
   int add_axis(Axis axis, int minimum, int maximum, bool centered);
   int add_axis(Axis axis, int minimum, int maximum);
   int add_axis(Axis axis, int minimum, int maximum);
 
 
-  void set_pointer(bool inwin, double x, double y, double time);
-  void set_pointer_out_of_window(double time);
-
-  void pointer_moved(double x, double y, double time);
+  int add_pointer(PointerType type, int id, bool primary = false);
+  void remove_pointer(int id);
+  void update_pointer(PointerData data, double time);
+  void pointer_moved(int id, double x, double y, double time);
   void button_changed(int index, bool down);
   void button_changed(int index, bool down);
   void axis_changed(int index, int value);
   void axis_changed(int index, int value);
   void set_axis_value(int index, double state);
   void set_axis_value(int index, double state);
@@ -323,6 +321,10 @@ protected:
   PT(ButtonEventList) _button_events;
   PT(ButtonEventList) _button_events;
   PT(PointerEventList) _pointer_events;
   PT(PointerEventList) _pointer_events;
 
 
+  size_t _num_pointers = 0;
+  typedef pvector<PointerData> Pointers;
+  Pointers _pointers;
+
 PUBLISHED:
 PUBLISHED:
   typedef pvector<ButtonState> Buttons;
   typedef pvector<ButtonState> Buttons;
   typedef pvector<AxisState> Axes;
   typedef pvector<AxisState> Axes;

+ 1 - 1
panda/src/display/graphicsWindow.cxx

@@ -363,7 +363,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 = ((const GraphicsWindowInputDevice *)_input_devices[device].p())->get_pointer();
   }
   }
   return result;
   return result;
 }
 }

+ 23 - 9
panda/src/display/graphicsWindowInputDevice.I

@@ -12,23 +12,27 @@
  */
  */
 
 
 /**
 /**
- * To be called by a particular kind of GraphicsWindow to indicate that the
- * pointer is within the window, at the given pixel coordinates.
+ * Returns the PointerData associated with the input device's pointer.  This
+ * only makes sense if has_pointer() also returns true.
  */
  */
-INLINE void GraphicsWindowInputDevice::
-set_pointer_in_window(double x, double y, double time) {
+INLINE PointerData GraphicsWindowInputDevice::
+get_pointer() const {
   LightMutexHolder holder(_lock);
   LightMutexHolder holder(_lock);
-  InputDevice::set_pointer(true, x, y, time);
+  if (!_pointers.empty()) {
+    return _pointers[0];
+  } else {
+    return PointerData();
+  }
 }
 }
 
 
 /**
 /**
  * To be called by a particular kind of GraphicsWindow to indicate that the
  * To be called by a particular kind of GraphicsWindow to indicate that the
- * pointer is no longer within the window.
+ * pointer data has changed.
  */
  */
 INLINE void GraphicsWindowInputDevice::
 INLINE void GraphicsWindowInputDevice::
-set_pointer_out_of_window(double time) {
+update_pointer(PointerData data, double time) {
   LightMutexHolder holder(_lock);
   LightMutexHolder holder(_lock);
-  InputDevice::set_pointer_out_of_window(time);
+  InputDevice::update_pointer(std::move(data), time);
 }
 }
 
 
 /**
 /**
@@ -38,5 +42,15 @@ set_pointer_out_of_window(double time) {
 INLINE void GraphicsWindowInputDevice::
 INLINE void GraphicsWindowInputDevice::
 pointer_moved(double x, double y, double time) {
 pointer_moved(double x, double y, double time) {
   LightMutexHolder holder(_lock);
   LightMutexHolder holder(_lock);
-  InputDevice::pointer_moved(x, y, time);
+  InputDevice::pointer_moved(0, x, y, time);
+}
+
+/**
+ * To be called by a particular kind of GraphicsWindow to indicate that the
+ * pointer no longer exists.
+ */
+INLINE void GraphicsWindowInputDevice::
+remove_pointer(int id) {
+  LightMutexHolder holder(_lock);
+  InputDevice::remove_pointer(id);
 }
 }

+ 43 - 0
panda/src/display/graphicsWindowInputDevice.cxx

@@ -34,6 +34,7 @@ GraphicsWindowInputDevice(GraphicsWindow *host, const string &name, bool pointer
 {
 {
   if (pointer) {
   if (pointer) {
     enable_feature(Feature::pointer);
     enable_feature(Feature::pointer);
+    add_pointer(PointerType::mouse, 0);
   }
   }
   if (keyboard) {
   if (keyboard) {
     enable_feature(Feature::keyboard);
     enable_feature(Feature::keyboard);
@@ -156,3 +157,45 @@ raw_button_up(ButtonHandle button, double time) {
   LightMutexHolder holder(_lock);
   LightMutexHolder holder(_lock);
   _button_events->add_event(ButtonEvent(button, ButtonEvent::T_raw_up, time));
   _button_events->add_event(ButtonEvent(button, ButtonEvent::T_raw_up, time));
 }
 }
+
+/**
+ * To be called by a particular kind of GraphicsWindow to indicate that the
+ * pointer is within the window, at the given pixel coordinates.
+ */
+void GraphicsWindowInputDevice::
+set_pointer_in_window(double x, double y, double time) {
+  LightMutexHolder holder(_lock);
+  PointerData data = _pointers[0];
+  data._id = 0;
+  data._type = PointerType::mouse;
+  data._xpos = x;
+  data._ypos = y;
+  data._in_window = true;
+  InputDevice::update_pointer(data, time);
+}
+
+/**
+ * To be called by a particular kind of GraphicsWindow to indicate that the
+ * pointer is no longer within the window.
+ */
+void GraphicsWindowInputDevice::
+set_pointer_out_of_window(double time) {
+  LightMutexHolder holder(_lock);
+  if (_pointers.empty()) {
+    return;
+  }
+
+  _pointers[0]._in_window = false;
+  _pointers[0]._pressure = 0.0;
+
+  if (_enable_pointer_events) {
+    int seq = _event_sequence++;
+    if (_pointer_events.is_null()) {
+      _pointer_events = new PointerEventList();
+    }
+    _pointer_events->add_event(_pointers[0]._in_window,
+                               _pointers[0]._xpos,
+                               _pointers[0]._ypos,
+                               seq, time);
+  }
+}

+ 5 - 2
panda/src/display/graphicsWindowInputDevice.h

@@ -53,9 +53,12 @@ PUBLISHED:
   void raw_button_down(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time());
   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());
   void raw_button_up(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time());
 
 
-  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());
+  INLINE PointerData get_pointer() const;
+  void set_pointer_in_window(double x, double y, double time = ClockObject::get_global_clock()->get_frame_time());
+  void set_pointer_out_of_window(double time = ClockObject::get_global_clock()->get_frame_time());
+  INLINE void update_pointer(PointerData data, double time = ClockObject::get_global_clock()->get_frame_time());
   INLINE void pointer_moved(double x, double y, double time = ClockObject::get_global_clock()->get_frame_time());
   INLINE void pointer_moved(double x, double y, double time = ClockObject::get_global_clock()->get_frame_time());
+  INLINE void remove_pointer(int id);
 
 
 private:
 private:
   typedef pset<ButtonHandle> ButtonsHeld;
   typedef pset<ButtonHandle> ButtonsHeld;

+ 6 - 18
panda/src/display/mouseAndKeyboard.cxx

@@ -27,7 +27,7 @@ MouseAndKeyboard::
 MouseAndKeyboard(GraphicsWindow *window, int device, const std::string &name) :
 MouseAndKeyboard(GraphicsWindow *window, int device, const std::string &name) :
   DataNode(name),
   DataNode(name),
   _window(window),
   _window(window),
-  _device(device)
+  _device(window->get_input_device(device))
 {
 {
   _pixel_xy_output = define_output("pixel_xy", EventStoreVec2::get_class_type());
   _pixel_xy_output = define_output("pixel_xy", EventStoreVec2::get_class_type());
   _pixel_size_output = define_output("pixel_size", EventStoreVec2::get_class_type());
   _pixel_size_output = define_output("pixel_size", EventStoreVec2::get_class_type());
@@ -38,6 +38,8 @@ MouseAndKeyboard(GraphicsWindow *window, int device, const std::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));
+
+  _device->enable_pointer_events();
 }
 }
 
 
 /**
 /**
@@ -47,23 +49,9 @@ MouseAndKeyboard(GraphicsWindow *window, int device, const std::string &name) :
 void MouseAndKeyboard::
 void MouseAndKeyboard::
 set_source(GraphicsWindow *window, int device) {
 set_source(GraphicsWindow *window, int device) {
   _window = window;
   _window = window;
-  _device = device;
-}
-
-/**
- * Returns the associated source window.
- */
-PT(GraphicsWindow) MouseAndKeyboard::
-get_source_window() const {
-  return _window;
-}
+  _device = window->get_input_device(device);
 
 
-/**
- * Returns the associated source device.
- */
-int MouseAndKeyboard::
-get_source_device() const {
-  return _device;
+  //_device->enable_pointer_events();
 }
 }
 
 
 /**
 /**
@@ -78,7 +66,7 @@ void MouseAndKeyboard::
 do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &,
 do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &,
                  DataNodeTransmit &output) {
                  DataNodeTransmit &output) {
 
 
-  PT(InputDevice) device = _window->get_input_device(_device);
+  GraphicsWindowInputDevice *device = (GraphicsWindowInputDevice *)_device.p();
 
 
   if (device->has_button_event()) {
   if (device->has_button_event()) {
     PT(ButtonEventList) bel = device->get_button_events();
     PT(ButtonEventList) bel = device->get_button_events();

+ 1 - 4
panda/src/display/mouseAndKeyboard.h

@@ -43,9 +43,6 @@ PUBLISHED:
   explicit MouseAndKeyboard(GraphicsWindow *window, int device, const std::string &name);
   explicit MouseAndKeyboard(GraphicsWindow *window, int device, const std::string &name);
   void set_source(GraphicsWindow *window, int device);
   void set_source(GraphicsWindow *window, int device);
 
 
-  PT(GraphicsWindow) get_source_window() 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,
@@ -65,7 +62,7 @@ private:
   PT(EventStoreVec2) _xy;
   PT(EventStoreVec2) _xy;
 
 
   PT(GraphicsWindow) _window;
   PT(GraphicsWindow) _window;
-  int _device;
+  PT(InputDevice) _device;
 
 
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {

+ 0 - 18
panda/src/event/pointerEvent.I

@@ -11,24 +11,6 @@
  * @date 2007-09-20
  * @date 2007-09-20
  */
  */
 
 
-/**
- *
- */
-INLINE PointerEvent::
-PointerEvent() :
-  _in_window(false),
-  _xpos(0),
-  _ypos(0),
-  _dx(0),
-  _dy(0),
-  _length(0.0),
-  _direction(0.0),
-  _rotation(0.0),
-  _sequence(0),
-  _time(0.0)
-{
-}
-
 /**
 /**
  * The equality operator does not consider time significant.
  * The equality operator does not consider time significant.
  */
  */

+ 15 - 12
panda/src/event/pointerEvent.h

@@ -15,7 +15,7 @@
 #define POINTEREVENT_H
 #define POINTEREVENT_H
 
 
 #include "pandabase.h"
 #include "pandabase.h"
-#include "mouseData.h"
+#include "pointerData.h"
 
 
 class Datagram;
 class Datagram;
 class DatagramIterator;
 class DatagramIterator;
@@ -25,7 +25,7 @@ class DatagramIterator;
  */
  */
 class EXPCL_PANDA_EVENT PointerEvent {
 class EXPCL_PANDA_EVENT PointerEvent {
 public:
 public:
-  INLINE PointerEvent();
+  PointerEvent() = default;
 
 
   INLINE bool operator == (const PointerEvent &other) const;
   INLINE bool operator == (const PointerEvent &other) const;
   INLINE bool operator != (const PointerEvent &other) const;
   INLINE bool operator != (const PointerEvent &other) const;
@@ -37,16 +37,19 @@ public:
   void read_datagram(DatagramIterator &scan);
   void read_datagram(DatagramIterator &scan);
 
 
 public:
 public:
-  bool      _in_window;
-  int       _xpos;
-  int       _ypos;
-  double    _dx;
-  double    _dy;
-  double    _length;
-  double    _direction;
-  double    _rotation;
-  int       _sequence;
-  double    _time;
+  bool _in_window = false;
+  int _id = 0;
+  PointerType _type = PointerType::unknown;
+  double _xpos = 0.0;
+  double _ypos = 0.0;
+  double _dx = 0.0;
+  double _dy = 0.0;
+  double _length = 0.0;
+  double _direction = 0.0;
+  double _pressure = 0.0;
+  double _rotation = 0.0;
+  int _sequence = 0;
+  double _time = 0.0;
 };
 };
 
 
 INLINE std::ostream &operator << (std::ostream &out, const PointerEvent &pe) {
 INLINE std::ostream &operator << (std::ostream &out, const PointerEvent &pe) {

+ 16 - 0
panda/src/event/pointerEventList.I

@@ -43,6 +43,22 @@ get_num_events() const {
   return _events.size();
   return _events.size();
 }
 }
 
 
+/**
+ * Returns true if the list is empty.
+ */
+INLINE bool PointerEventList::
+empty() const {
+  return _events.empty();
+}
+
+/**
+ * Returns the nth event in the list.
+ */
+INLINE const PointerEvent &PointerEventList::
+get_event(size_t n) const {
+  return _events[n];
+}
+
 /**
 /**
  * Get the in-window flag of the nth event.
  * Get the in-window flag of the nth event.
  */
  */

+ 36 - 0
panda/src/event/pointerEventList.cxx

@@ -76,6 +76,42 @@ write(std::ostream &out, int indent_level) const {
   }
   }
 }
 }
 
 
+/**
+ * Adds a new event from the given PointerData object.
+ */
+void PointerEventList::
+add_event(const PointerData &data, int seq, double time) {
+  PointerEvent pe;
+  pe._in_window = data._in_window;
+  pe._type = data._type;
+  pe._id = data._id;
+  pe._xpos = data._xpos;
+  pe._ypos = data._ypos;
+  pe._pressure = data._pressure;
+  pe._sequence = seq;
+  pe._time = time;
+  if (_events.size() > 0) {
+    pe._dx = data._xpos - _events.back()._xpos;
+    pe._dy = data._ypos - _events.back()._ypos;
+    double ddx = pe._dx;
+    double ddy = pe._dy;
+    pe._length = csqrt(ddx*ddx + ddy*ddy);
+    if (pe._length > 0.0) {
+      pe._direction = normalize_angle(rad_2_deg(catan2(-ddy,ddx)));
+    } else {
+      pe._direction = _events.back()._direction;
+    }
+    pe._rotation = delta_angle(_events.back()._direction, pe._direction);
+  } else {
+    pe._dx = 0;
+    pe._dy = 0;
+    pe._length = 0.0;
+    pe._direction = 0.0;
+    pe._rotation = 0.0;
+  }
+  _events.push_back(pe);
+}
+
 /**
 /**
  * Adds a new event to the end of the list.  Automatically calculates the dx,
  * Adds a new event to the end of the list.  Automatically calculates the dx,
  * dy, length, direction, and rotation for all but the first event.
  * dy, length, direction, and rotation for all but the first event.

+ 4 - 0
panda/src/event/pointerEventList.h

@@ -48,6 +48,7 @@ PUBLISHED:
 
 
   INLINE void   clear();
   INLINE void   clear();
   INLINE void   pop_front();
   INLINE void   pop_front();
+  void add_event(const PointerData &data, int seq, double time);
   void add_event(bool in_win, int xpos, int ypos, int seq, double time);
   void add_event(bool in_win, int xpos, int ypos, int seq, double time);
   void add_event(bool in_win, int xpos, int ypos, double xdelta, double ydelta,
   void add_event(bool in_win, int xpos, int ypos, double xdelta, double ydelta,
                  int seq, double time);
                  int seq, double time);
@@ -60,6 +61,9 @@ public:
   INLINE PointerEventList(const PointerEventList &copy);
   INLINE PointerEventList(const PointerEventList &copy);
   INLINE void operator = (const PointerEventList &copy);
   INLINE void operator = (const PointerEventList &copy);
 
 
+  INLINE bool empty() const;
+  INLINE const PointerEvent &get_event(size_t n) const;
+
   virtual void output(std::ostream &out) const;
   virtual void output(std::ostream &out) const;
   void write(std::ostream &out, int indent_level = 0) const;
   void write(std::ostream &out, int indent_level = 0) const;
 
 

+ 8 - 0
panda/src/putil/pointerData.I

@@ -47,6 +47,14 @@ get_id() const {
   return _id;
   return _id;
 }
 }
 
 
+/**
+ * Returns the type of pointing device.
+ */
+INLINE PointerType PointerData::
+get_type() const {
+  return _type;
+}
+
 /**
 /**
  * Returns the pressure of the pointer.  For mice, this will be 1.0 if any
  * Returns the pressure of the pointer.  For mice, this will be 1.0 if any
  * button is pressed, 0.0 otherwise.
  * button is pressed, 0.0 otherwise.

+ 16 - 0
panda/src/putil/pointerData.h

@@ -18,6 +18,19 @@
 
 
 #include "modifierButtons.h"
 #include "modifierButtons.h"
 
 
+BEGIN_PUBLISH
+/**
+ * Contains the types of pointer device.
+ */
+enum class PointerType {
+  unknown,
+  mouse,
+  finger,
+  stylus,
+  eraser,
+};
+END_PUBLISH
+
 /**
 /**
  * Holds the data that might be generated by a 2-d pointer input device, such
  * Holds the data that might be generated by a 2-d pointer input device, such
  * as the mouse in the GraphicsWindow.
  * as the mouse in the GraphicsWindow.
@@ -30,6 +43,7 @@ PUBLISHED:
 
 
 public:
 public:
   INLINE int get_id() const;
   INLINE int get_id() const;
+  INLINE PointerType get_type() const;
   INLINE double get_pressure() const;
   INLINE double get_pressure() const;
 
 
   void output(std::ostream &out) const;
   void output(std::ostream &out) const;
@@ -37,6 +51,7 @@ public:
 PUBLISHED:
 PUBLISHED:
   MAKE_PROPERTY(x, get_x);
   MAKE_PROPERTY(x, get_x);
   MAKE_PROPERTY(y, get_y);
   MAKE_PROPERTY(y, get_y);
+  MAKE_PROPERTY(type, get_type);
   MAKE_PROPERTY(id, get_id);
   MAKE_PROPERTY(id, get_id);
   MAKE_PROPERTY(in_window, get_in_window);
   MAKE_PROPERTY(in_window, get_in_window);
   MAKE_PROPERTY(pressure, get_pressure);
   MAKE_PROPERTY(pressure, get_pressure);
@@ -46,6 +61,7 @@ public:
   double _xpos = 0.0;
   double _xpos = 0.0;
   double _ypos = 0.0;
   double _ypos = 0.0;
   double _pressure = 0.0;
   double _pressure = 0.0;
+  PointerType _type = PointerType::unknown;
   int _id = 0;
   int _id = 0;
 };
 };
 
 

+ 1 - 1
panda/src/tform/mouseWatcher.I

@@ -542,7 +542,7 @@ get_trail_log() const {
  * frame.  The trail log is updated once per frame, during the process_events
  * frame.  The trail log is updated once per frame, during the process_events
  * operation.
  * operation.
  */
  */
-INLINE int MouseWatcher::
+INLINE size_t MouseWatcher::
 num_trail_recent() const {
 num_trail_recent() const {
   return _num_trail_recent;
   return _num_trail_recent;
 }
 }

+ 1 - 1
panda/src/tform/mouseWatcher.cxx

@@ -1326,7 +1326,7 @@ do_transmit_data(DataGraphTraverser *trav, const DataNodeTransmit &input,
     const PointerEventList *this_pointer_events;
     const PointerEventList *this_pointer_events;
     DCAST_INTO_V(this_pointer_events, input.get_data(_pointer_events_input).get_ptr());
     DCAST_INTO_V(this_pointer_events, input.get_data(_pointer_events_input).get_ptr());
     _num_trail_recent = this_pointer_events->get_num_events();
     _num_trail_recent = this_pointer_events->get_num_events();
-    for (int i = 0; i < _num_trail_recent; i++) {
+    for (size_t i = 0; i < _num_trail_recent; i++) {
       bool in_win = this_pointer_events->get_in_window(i);
       bool in_win = this_pointer_events->get_in_window(i);
       int xpos = this_pointer_events->get_xpos(i);
       int xpos = this_pointer_events->get_xpos(i);
       int ypos = this_pointer_events->get_ypos(i);
       int ypos = this_pointer_events->get_ypos(i);

+ 2 - 2
panda/src/tform/mouseWatcher.h

@@ -138,7 +138,7 @@ PUBLISHED:
   INLINE const std::string &get_inactivity_timeout_event() const;
   INLINE const std::string &get_inactivity_timeout_event() const;
 
 
   INLINE CPT(PointerEventList) get_trail_log() const;
   INLINE CPT(PointerEventList) get_trail_log() const;
-  INLINE int   num_trail_recent() const;
+  INLINE size_t num_trail_recent() const;
   void         set_trail_log_duration(double duration);
   void         set_trail_log_duration(double duration);
   PT(GeomNode) get_trail_node();
   PT(GeomNode) get_trail_node();
   void         clear_trail_node();
   void         clear_trail_node();
@@ -220,7 +220,7 @@ private:
   LVecBase4 _frame;
   LVecBase4 _frame;
 
 
   PT(PointerEventList) _trail_log;
   PT(PointerEventList) _trail_log;
-  int _num_trail_recent;
+  size_t _num_trail_recent;
   double _trail_log_duration;
   double _trail_log_duration;
   PT(GeomNode) _trail_node;
   PT(GeomNode) _trail_node;
 
 

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

@@ -130,7 +130,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 = ((const GraphicsWindowInputDevice *)_input_devices[device].p())->get_pointer();
 
 
     // We recheck this immediately to get the most up-to-date value.
     // We recheck this immediately to get the most up-to-date value.
     POINT cpos;
     POINT cpos;

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

@@ -150,7 +150,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 = ((const GraphicsWindowInputDevice *)_input_devices[device].p())->get_pointer();
 
 
     // We recheck this immediately to get the most up-to-date value, but we
     // We recheck this immediately to get the most up-to-date value, but we
     // won't bother waiting for the lock if we can't.
     // won't bother waiting for the lock if we can't.