Browse Source

multitouch: Begin properly emulating the mouse with touch if the option is turned on. Refactor PointerEvents to have them carry only PointerData and a timestamp (for now).

Donny Lawrence 6 years ago
parent
commit
7b90e43da5

+ 2 - 2
direct/src/gui/DirectButton.py

@@ -101,11 +101,11 @@ class DirectButton(DirectFrame):
 
         # Tapping with the finger
         if DGG.TOUCH in self['commandButtons']:
-            self.guiItem.addClickButton(MouseButton.tap())
+            self.guiItem.addClickButton(MouseButton.touch())
             self.bind(DGG.TOUCHCLICK, self.commandFunc)
         else:
             self.unbind(DGG.TOUCHCLICK)
-            self.guiItem.removeClickButton(MouseButton.tap())
+            self.guiItem.removeClickButton(MouseButton.touch())
 
     def commandFunc(self, event):
         if self['command']:

+ 3 - 6
panda/src/device/inputDevice.cxx

@@ -188,9 +188,8 @@ remove_pointer(int id) {
   if (pointer.get_pressure() != 0.0) {
     pointer.set_pressure(0.0);
     if (_enable_pointer_events) {
-      int seq = _event_sequence++;
       double time = ClockObject::get_global_clock()->get_frame_time();
-      _pointer_events->add_event(pointer, seq, time);
+      _pointer_events->add_event(pointer, time);
     }
   }
 }
@@ -203,8 +202,7 @@ pointer_moved_absolute(int id, double x, double y, double pressure, double time)
   pointer.update(x, y, pressure);
 
   if (_enable_pointer_events) {
-    int seq = _event_sequence++;
-    _pointer_events->add_event(pointer, seq, time);
+    _pointer_events->add_event(pointer, time);
   }
 }
 
@@ -224,8 +222,7 @@ pointer_moved(int id, double x, double y, double time) {
   pointer.rel_move(x, y);
 
   if (_enable_pointer_events) {
-    int seq = _event_sequence++;
-    _pointer_events->add_event(pointer, seq, time);
+    _pointer_events->add_event(pointer, time);
   }
 }
 

+ 3 - 0
panda/src/display/config_display.cxx

@@ -478,6 +478,9 @@ ConfigVariableBool sync_video
           "cheesy estimate of scene complexity.  Some drivers may ignore "
           "this request."));
 
+ConfigVariableBool touch_emulates_mouse
+("touch-emulates-mouse", true);
+
 /**
  * Initializes the library.  This must be called at least once before any of
  * the functions or classes in this library can be used.  Normally it will be

+ 2 - 0
panda/src/display/config_display.h

@@ -109,6 +109,8 @@ extern EXPCL_PANDA_DISPLAY ConfigVariableDouble pixel_zoom;
 extern EXPCL_PANDA_DISPLAY ConfigVariableColor background_color;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool sync_video;
 
+extern EXPCL_PANDA_DISPLAY ConfigVariableBool touch_emulates_mouse;
+
 extern EXPCL_PANDA_DISPLAY void init_libdisplay();
 
 #endif /* CONFIG_DISPLAY_H */

+ 2 - 16
panda/src/display/graphicsWindowInputDevice.cxx

@@ -172,15 +172,6 @@ set_pointer_in_window(double x, double y, double time) {
 
   pointer.update(x, y, 1.0);
   pointer.set_in_window(true);
-
-
-  // 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);
 }
 
 /**
@@ -199,17 +190,12 @@ set_pointer_out_of_window(double time) {
   pointer.set_pressure(0.0);
   pointer.set_in_window(false);
 
-  // _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(pointer.get_in_window(),
-                               pointer.get_x(),
-                               pointer.get_y(),
-                               seq, time);
+
+    _pointer_events->add_event(pointer);
   }
 }

+ 38 - 15
panda/src/display/mouseAndKeyboard.cxx

@@ -68,14 +68,33 @@ do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &,
 
   GraphicsWindowInputDevice *device = (GraphicsWindowInputDevice *)_device.p();
 
+  if (device->has_pointer_event()) {
+    PT(PointerEventList) all_events = device->get_pointer_events();
+    PT(PointerEventList) output_events;
+
+    if (touch_emulates_mouse) {
+      output_events = new PointerEventList;
+      for (int i = 0; i < all_events->get_num_events(); i++) {
+        const PointerEvent &event = all_events->get_event(i);
+        if (event._data.get_type() == PointerType::mouse || event._data.get_primary()) {
+          if (event._data.get_pressure() > 0) {
+            device->button_down(MouseButton::one());
+          } else {
+            device->button_up(MouseButton::one());
+          }
+          output_events->add_event(event);
+        }
+      }
+    } else {
+      output_events = all_events;
+    }
+
+    output.set_data(_pointer_events_output, EventParameter(output_events));
+  }
   if (device->has_button_event()) {
     PT(ButtonEventList) bel = device->get_button_events();
     output.set_data(_button_events_output, EventParameter(bel));
   }
-  if (device->has_pointer_event()) {
-    PT(PointerEventList) pel = device->get_pointer_events();
-    output.set_data(_pointer_events_output, EventParameter(pel));
-  }
 
   // Get the window size.
   WindowProperties properties = _window->get_properties();
@@ -89,17 +108,21 @@ do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &,
     if (device->has_pointer()) {
       PointerData mdata = device->get_pointer();
 
-      if (mdata.get_in_window()) {
-        // Get mouse motion in pixels.
-        _pixel_xy->set_value(LPoint2(mdata.get_x(), mdata.get_y()));
-        output.set_data(_pixel_xy_output, EventParameter(_pixel_xy));
-
-        // Normalize pixel motion to range [-1,1].
-        PN_stdfloat xf = (PN_stdfloat)(2 * mdata.get_x()) / (PN_stdfloat)w - 1.0f;
-        PN_stdfloat yf = 1.0f - (PN_stdfloat)(2 * mdata.get_y()) / (PN_stdfloat)h;
-
-        _xy->set_value(LPoint2(xf, yf));
-        output.set_data(_xy_output, EventParameter(_xy));
+      // We're only going to use the pixel_xy and xy wires if the pointer is
+      // a mouse or is emulating a mouse.
+      if (mdata.get_type() == PointerType::mouse || touch_emulates_mouse) {
+        if (mdata.get_in_window()) {
+          // Get mouse motion in pixels.
+          _pixel_xy->set_value(LPoint2(mdata.get_x(), mdata.get_y()));
+          output.set_data(_pixel_xy_output, EventParameter(_pixel_xy));
+
+          // Normalize pixel motion to range [-1,1].
+          PN_stdfloat xf = (PN_stdfloat)(2 * mdata.get_x()) / (PN_stdfloat)w - 1.0f;
+          PN_stdfloat yf = 1.0f - (PN_stdfloat)(2 * mdata.get_y()) / (PN_stdfloat)h;
+
+          _xy->set_value(LPoint2(xf, yf));
+          output.set_data(_xy_output, EventParameter(_xy));
+        }
       }
     }
   }

+ 6 - 17
panda/src/eagldisplay/eaglGraphicsWindow.mm

@@ -267,18 +267,12 @@ touches_began(NSSet<UITouch *> *touch_set) {
 
     CGPoint point = [touch locationInView:_view];
     NSLog(@"%d, %d", point.x, point.y);
+    float scale = _view.layer.contentsScale;
 
     PointerData &data = _input->add_pointer(PointerType::finger, [next_id intValue], _primary_touch == nil);
-    data.update(point.x, point.y, 1.0);
-
-    // PointerData data;
-    // data._id = [next_id intValue];
-    // data._type = PointerType::finger;
-    // data._xpos = point.x;
-    // data._ypos = point.y;
-    // data._pressure = 1.0;
-    // _input->update_pointer(data);
-    if (_primary_touch != nil) {
+    data.update(point.x * scale, point.y * scale, 1.0);
+
+    if (_primary_touch == nil) {
       _primary_touch = touch;
     }
 
@@ -292,14 +286,9 @@ touches_moved(NSSet<UITouch *> *touch_set) {
     NSNumber *touch_id = (NSNumber *)objc_getAssociatedObject(touch, &touch_id_key);
 
     CGPoint point = [touch locationInView:_view];
+    float scale = _view.layer.contentsScale;
 
-    // PointerData data;
-    // data._id = [touch_id intValue];
-    // data._xpos = point.x;
-    // data._ypos = point.y;
-    // data._pressure = 1.0;
-    _input->get_pointer([touch_id intValue]).update(point.x, point.y, 1.0);
-    //printf("Touch %d moved\n", [touch_id intValue]);
+    _input->pointer_moved_absolute([touch_id intValue], point.x * scale, point.y * scale, 1.0);
   }];
 }
 

+ 53 - 53
panda/src/event/pointerEvent.I

@@ -11,58 +11,58 @@
  * @date 2007-09-20
  */
 
-/**
- * The equality operator does not consider time significant.
- */
-INLINE bool PointerEvent::
-operator == (const PointerEvent &other) const {
-  return (_in_window == other._in_window &&
-          _xpos == other._xpos &&
-          _ypos == other._ypos &&
-          _dx == other._dx &&
-          _dy == other._dy &&
-          _sequence == other._sequence &&
-          _length == other._length &&
-          _direction == other._direction &&
-          _rotation == other._rotation);
-}
+// /**
+//  * The equality operator does not consider time significant.
+//  */
+// INLINE bool PointerEvent::
+// operator == (const PointerEvent &other) const {
+//   return (_in_window == other._in_window &&
+//           _xpos == other._xpos &&
+//           _ypos == other._ypos &&
+//           _dx == other._dx &&
+//           _dy == other._dy &&
+//           _sequence == other._sequence &&
+//           _length == other._length &&
+//           _direction == other._direction &&
+//           _rotation == other._rotation);
+// }
 
-/**
- *
- */
-INLINE bool PointerEvent::
-operator != (const PointerEvent &other) const {
-  return !operator == (other);
-}
+// /**
+//  *
+//  */
+// INLINE bool PointerEvent::
+// operator != (const PointerEvent &other) const {
+//   return !operator == (other);
+// }
 
-/**
- *
- */
-INLINE bool PointerEvent::
-operator < (const PointerEvent &other) const {
-  if (_sequence != other._sequence) {
-    return _sequence < other._sequence;
-  }
-  if (_xpos != other._xpos) {
-    return _xpos < other._xpos;
-  }
-  if (_ypos != other._ypos) {
-    return _ypos < other._ypos;
-  }
-  if (_dx != other._dx) {
-    return _dx < other._dx;
-  }
-  if (_dy != other._dy) {
-    return _dy < other._dy;
-  }
-  if (_length != other._length) {
-    return _length < other._length;
-  }
-  if (_direction != other._direction) {
-    return _direction < other._direction;
-  }
-  if (_rotation != other._rotation) {
-    return _rotation < other._rotation;
-  }
-  return _in_window < other._in_window;
-}
+// /**
+//  *
+//  */
+// INLINE bool PointerEvent::
+// operator < (const PointerEvent &other) const {
+//   if (_sequence != other._sequence) {
+//     return _sequence < other._sequence;
+//   }
+//   if (_xpos != other._xpos) {
+//     return _xpos < other._xpos;
+//   }
+//   if (_ypos != other._ypos) {
+//     return _ypos < other._ypos;
+//   }
+//   if (_dx != other._dx) {
+//     return _dx < other._dx;
+//   }
+//   if (_dy != other._dy) {
+//     return _dy < other._dy;
+//   }
+//   if (_length != other._length) {
+//     return _length < other._length;
+//   }
+//   if (_direction != other._direction) {
+//     return _direction < other._direction;
+//   }
+//   if (_rotation != other._rotation) {
+//     return _rotation < other._rotation;
+//   }
+//   return _in_window < other._in_window;
+// }

+ 10 - 20
panda/src/event/pointerEvent.cxx

@@ -12,30 +12,20 @@
  */
 
 #include "pointerEvent.h"
-#include "datagram.h"
-#include "datagramIterator.h"
 
-/**
- *
- */
-void PointerEvent::
-output(std::ostream &out) const {
-  out << (_in_window ? "In@" : "Out@")
-      << _xpos << "," << _ypos << " ";
-}
+PointerEvent::
+PointerEvent(PointerData data, double time) :
+  _data(data),
+  _time(time)
+{
 
-/**
- * Writes the event into a datagram.
- */
-void PointerEvent::
-write_datagram(Datagram &dg) const {
-  nassert_raise("This function not implemented yet.");
 }
 
 /**
- * Restores the event from the datagram.
+ *
  */
 void PointerEvent::
-read_datagram(DatagramIterator &scan) {
-  nassert_raise("This function not implemented yet.");
-}
+output(std::ostream &out) const {
+  out << (_data.get_in_window() ? "In@" : "Out@")
+      << _data.get_x() << "," << _data.get_y() << " ";
+}

+ 5 - 22
panda/src/event/pointerEvent.h

@@ -17,38 +17,21 @@
 #include "pandabase.h"
 #include "pointerData.h"
 
-class Datagram;
-class DatagramIterator;
-
 /**
  * Records a pointer movement event.
  */
 class EXPCL_PANDA_EVENT PointerEvent {
 public:
-  PointerEvent() = default;
+  PointerEvent(PointerData data, double time = ClockObject::get_global_clock()->get_frame_time());
 
-  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;
+  // INLINE bool operator != (const PointerEvent &other) const;
+  // INLINE bool operator < (const PointerEvent &other) const;
 
   void output(std::ostream &out) const;
 
-  void write_datagram(Datagram &dg) const;
-  void read_datagram(DatagramIterator &scan);
-
 public:
-  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;
+  PointerData _data;
   double _time = 0.0;
 };
 

+ 58 - 58
panda/src/event/pointerEventList.I

@@ -65,7 +65,7 @@ get_event(size_t n) const {
 INLINE bool PointerEventList::
 get_in_window(size_t n) const {
   nassertr(n < _events.size(), 0);
-  return _events[n]._in_window;
+  return _events[n]._data.get_in_window();
 }
 
 /**
@@ -74,7 +74,7 @@ get_in_window(size_t n) const {
 INLINE int PointerEventList::
 get_xpos(size_t n) const {
   nassertr(n < _events.size(), 0);
-  return _events[n]._xpos;
+  return _events[n]._data.get_x();
 }
 
 /**
@@ -83,62 +83,62 @@ get_xpos(size_t n) const {
 INLINE int PointerEventList::
 get_ypos(size_t n) const {
   nassertr(n < _events.size(), 0);
-  return _events[n]._ypos;
-}
-
-/**
- * Get the x-delta of the nth event.
- */
-INLINE double PointerEventList::
-get_dx(size_t n) const {
-  nassertr(n < _events.size(), 0);
-  return _events[n]._dx;
-}
-
-/**
- * Get the y-delta of the nth event.
- */
-INLINE double PointerEventList::
-get_dy(size_t n) const {
-  nassertr(n < _events.size(), 0);
-  return _events[n]._dy;
-}
-
-/**
- * Get the length of the nth event.
- */
-INLINE double PointerEventList::
-get_length(size_t n) const {
-  nassertr(n < _events.size(), 0);
-  return _events[n]._length;
-}
-
-/**
- * Get the direction of the nth event.
- */
-INLINE double PointerEventList::
-get_direction(size_t n) const {
-  nassertr(n < _events.size(), 0);
-  return _events[n]._direction;
-}
-
-/**
- * Get the rotation of the nth event.
- */
-INLINE double PointerEventList::
-get_rotation(size_t n) const {
-  nassertr(n < _events.size(), 0);
-  return _events[n]._rotation;
-}
-
-/**
- * Get the sequence number of the nth event.
- */
-INLINE int PointerEventList::
-get_sequence(size_t n) const {
-  nassertr(n < _events.size(), 0);
-  return _events[n]._sequence;
-}
+  return _events[n]._data.get_y();
+}
+
+// /**
+//  * Get the x-delta of the nth event.
+//  */
+// INLINE double PointerEventList::
+// get_dx(size_t n) const {
+//   nassertr(n < _events.size(), 0);
+//   return _events[n]._dx;
+// }
+
+// /**
+//  * Get the y-delta of the nth event.
+//  */
+// INLINE double PointerEventList::
+// get_dy(size_t n) const {
+//   nassertr(n < _events.size(), 0);
+//   return _events[n]._dy;
+// }
+
+// /**
+//  * Get the length of the nth event.
+//  */
+// INLINE double PointerEventList::
+// get_length(size_t n) const {
+//   nassertr(n < _events.size(), 0);
+//   return _events[n]._length;
+// }
+
+// /**
+//  * Get the direction of the nth event.
+//  */
+// INLINE double PointerEventList::
+// get_direction(size_t n) const {
+//   nassertr(n < _events.size(), 0);
+//   return _events[n]._direction;
+// }
+
+// /**
+//  * Get the rotation of the nth event.
+//  */
+// INLINE double PointerEventList::
+// get_rotation(size_t n) const {
+//   nassertr(n < _events.size(), 0);
+//   return _events[n]._rotation;
+// }
+
+// /**
+//  * Get the sequence number of the nth event.
+//  */
+// INLINE int PointerEventList::
+// get_sequence(size_t n) const {
+//   nassertr(n < _events.size(), 0);
+//   return _events[n]._sequence;
+// }
 
 /**
  * Get the timestamp of the nth event.

+ 105 - 100
panda/src/event/pointerEventList.cxx

@@ -76,104 +76,109 @@ write(std::ostream &out, int indent_level) const {
   }
 }
 
+void PointerEventList::
+add_event(const PointerEvent &event) {
+  _events.push_back(event);
+}
+
 /**
  * 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);
+add_event(const PointerData &data, double time) {
+  // PointerEvent pe;
+  // pe._in_window = data.get_in_window();
+  // pe._type = data.get_type();
+  // pe._id = data.get_id();
+  // pe._xpos = data.get_x();
+  // pe._ypos = data.get_y();
+  // pe._pressure = data.get_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(PointerEvent(data, time));
 }
 
 /**
  * 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.
  */
-void PointerEventList::
-add_event(bool in_win, int xpos, int ypos, int seq, double time) {
-  PointerEvent pe;
-  pe._in_window = in_win;
-  pe._xpos = xpos;
-  pe._ypos = ypos;
-  pe._sequence = seq;
-  pe._time = time;
-  if (_events.size() > 0) {
-    pe._dx = xpos - _events.back()._xpos;
-    pe._dy = 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);
-}
+// void PointerEventList::
+// add_event(bool in_win, int xpos, int ypos, int seq, double time) {
+//   PointerEvent pe;
+//   pe._in_window = in_win;
+//   pe._xpos = xpos;
+//   pe._ypos = ypos;
+//   pe._sequence = seq;
+//   pe._time = time;
+//   // if (_events.size() > 0) {
+//   //   pe._dx = xpos - _events.back()._xpos;
+//   //   pe._dy = 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 based on the given mouse movement.
  */
-void PointerEventList::
-add_event(bool in_win, int xpos, int ypos, double xdelta, double ydelta, int seq, double time) {
-  PointerEvent pe;
-  pe._in_window = in_win;
-  pe._xpos = xpos;
-  pe._ypos = ypos;
-  pe._dx = xdelta;
-  pe._dy = ydelta;
-  pe._sequence = seq;
-  pe._time = time;
-  pe._length = csqrt(xdelta*xdelta + ydelta*ydelta);
-  if (pe._length > 0.0) {
-    pe._direction = normalize_angle(rad_2_deg(catan2(-ydelta,xdelta)));
-  } else if (!_events.empty()) {
-    pe._direction = _events.back()._direction;
-  } else {
-    pe._direction = 0.0;
-  }
-  if (!_events.empty()) {
-    pe._rotation = delta_angle(_events.back()._direction, pe._direction);
-  } else {
-    pe._rotation = 0.0;
-  }
-  _events.push_back(pe);
-}
+// void PointerEventList::
+// add_event(bool in_win, int xpos, int ypos, double xdelta, double ydelta, int seq, double time) {
+//   PointerEvent pe;
+//   pe._in_window = in_win;
+//   pe._xpos = xpos;
+//   pe._ypos = ypos;
+//   pe._dx = xdelta;
+//   pe._dy = ydelta;
+//   pe._sequence = seq;
+//   pe._time = time;
+//   pe._length = csqrt(xdelta*xdelta + ydelta*ydelta);
+//   if (pe._length > 0.0) {
+//     pe._direction = normalize_angle(rad_2_deg(catan2(-ydelta,xdelta)));
+//   } else if (!_events.empty()) {
+//     pe._direction = _events.back()._direction;
+//   } else {
+//     pe._direction = 0.0;
+//   }
+//   if (!_events.empty()) {
+//     pe._rotation = delta_angle(_events.back()._direction, pe._direction);
+//   } else {
+//     pe._rotation = 0.0;
+//   }
+//   _events.push_back(pe);
+// }
 
 /**
  * Returns true if the trail loops around the specified point.
@@ -185,13 +190,13 @@ encircles(int x, int y) const {
     return false;
   }
   int last = tot_events-1;
-  double dx = _events[last]._xpos - x;
-  double dy = _events[last]._ypos - y;
+  double dx = _events[last]._data.get_x() - x;
+  double dy = _events[last]._data.get_y() - y;
   double lastang = rad_2_deg(catan2(dy, dx));
   double total = 0.0;
   for (int i=last; (i>=0) && (total < 360.0) && (total > -360.0); i--) {
-    dx = _events[i]._xpos - x;
-    dy = _events[i]._ypos - y;
+    dx = _events[i]._data.get_x() - x;
+    dy = _events[i]._data.get_y() - y;
     if ((dx==0.0)&&(dy==0.0)) {
       continue;
     }
@@ -212,18 +217,18 @@ encircles(int x, int y) const {
  * relatively straight line, a large number means that the trail is zig-
  * zagging or spinning.  The result is in degrees.
  */
-double PointerEventList::
-total_turns(double sec) const {
-  double old = ClockObject::get_global_clock()->get_frame_time() - sec;
-  int pos = _events.size()-1;
-  double tot = 0.0;
-  while ((pos >= 0)&&(_events[pos]._time >= old)) {
-    double rot = _events[pos]._rotation;
-    if (rot < 0.0) rot = -rot;
-    tot += rot;
-  }
-  return tot;
-}
+// double PointerEventList::
+// total_turns(double sec) const {
+//   double old = ClockObject::get_global_clock()->get_frame_time() - sec;
+//   int pos = _events.size()-1;
+//   double tot = 0.0;
+//   while ((pos >= 0)&&(_events[pos]._time >= old)) {
+//     double rot = _events[pos]._rotation;
+//     if (rot < 0.0) rot = -rot;
+//     tot += rot;
+//   }
+//   return tot;
+// }
 
 /**
  * This function is not implemented yet.  It is a work in progress.  The

+ 13 - 11
panda/src/event/pointerEventList.h

@@ -38,23 +38,25 @@ PUBLISHED:
   INLINE bool   get_in_window(size_t n) const;
   INLINE int    get_xpos(size_t n) const;
   INLINE int    get_ypos(size_t n) const;
-  INLINE double get_dx(size_t n) const;
-  INLINE double get_dy(size_t n) const;
-  INLINE int    get_sequence(size_t n) const;
-  INLINE double get_length(size_t n) const;
-  INLINE double get_direction(size_t n) const;
-  INLINE double get_rotation(size_t n) const;
+  // INLINE double get_dx(size_t n) const;
+  // INLINE double get_dy(size_t n) const;
+  // INLINE int    get_sequence(size_t n) const;
+  // INLINE double get_length(size_t n) const;
+  // INLINE double get_direction(size_t n) const;
+  // INLINE double get_rotation(size_t n) const;
   INLINE double get_time(size_t n) const;
 
   INLINE void   clear();
   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, double xdelta, double ydelta,
-                 int seq, double time);
+
+  void add_event(const PointerEvent &event);
+  void add_event(const PointerData &data, 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,
+  //                int seq, double time);
 
   bool   encircles(int x, int y) const;
-  double total_turns(double sec) const;
+  // double total_turns(double sec) const;
   double match_pattern(const std::string &pattern, double rot, double seglen);
 
 public:

+ 1 - 2
panda/src/putil/pointerData.h

@@ -36,7 +36,6 @@ END_PUBLISH
  * as the mouse in the GraphicsWindow.
  */
 class EXPCL_PANDA_PUTIL PointerData {
-  friend class PointerEvent;
 
 public:
   PointerData() = default;
@@ -69,7 +68,7 @@ PUBLISHED:
 
 protected:
   bool _primary = false;
-  bool _in_window = false;
+  bool _in_window = true;
   double _xpos = 0.0;
   double _ypos = 0.0;
   double _pressure = 0.0;

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

@@ -152,7 +152,7 @@ is_button_down(ButtonHandle button) const {
  */
 INLINE bool MouseWatcher::
 is_pointer_down(int id) const {
-  return _active_pointers.find(id) != _active_pointers.end();
+  return _active_regions.find(id) != _active_regions.end();
 }
 
 /**

+ 39 - 44
panda/src/tform/mouseWatcher.cxx

@@ -39,6 +39,8 @@ using std::string;
 
 TypeHandle MouseWatcher::_type_handle;
 
+extern ConfigVariableBool touch_emulates_mouse;
+
 /**
  *
  */
@@ -120,9 +122,9 @@ remove_region(MouseWatcherRegion *region) {
     _preferred_button_down_region = nullptr;
   }
 
-  for (auto it = _active_pointers.begin(); it != _active_pointers.end(); ++it) {
-    if (it->second._region == region) {
-      it->second._region = nullptr;
+  for (auto it = _active_regions.begin(); it != _active_regions.end(); ++it) {
+    if (it->second == region) {
+      it->second = nullptr;
     }
   }
 
@@ -912,24 +914,23 @@ throw_event_pattern(const string &pattern, const MouseWatcherRegion *region,
  * Records the indicated pointer as having made contact.
  */
 void MouseWatcher::
-pointer_down(PointerType type, int id, const LPoint2 &pos, double pressure) {
+pointer_down(const PointerData &ptr, const LPoint2 &region_pos) {
   nassertv(_lock.debug_is_locked());
 
   MouseWatcherParameter param;
   param.set_modifier_buttons(_mods);
-  param.set_mouse(pos);
+  param.set_mouse(region_pos);
   param.set_outside(false);
-  param._pressure = pressure;
-  param._pointer_id = id;
+  param._pressure = ptr.get_pressure();
+  param._pointer_id = ptr.get_id();
 
   Regions regions;
-  get_over_regions(regions, pos);
+  get_over_regions(regions, region_pos);
   MouseWatcherRegion *region = get_preferred_region(regions);
 
-  double now = ClockObject::get_global_clock()->get_frame_time();
-  _active_pointers[id] = {region, type, pressure, now};
+  _active_regions[ptr.get_id()] = region;
 
-  if (region != nullptr && type != PointerType::mouse) {
+  if (region != nullptr && ptr.get_type() != PointerType::mouse) {
     param.set_button(MouseButton::touch());
     region->press(param);
   }
@@ -939,20 +940,18 @@ pointer_down(PointerType type, int id, const LPoint2 &pos, double pressure) {
  * Records the indicated pointer as having moved.
  */
 void MouseWatcher::
-pointer_move(int id, const LPoint2 &pos, double pressure) {
+pointer_move(const PointerData &ptr, const LPoint2 &region_pos) {
   nassertv(_lock.debug_is_locked());
 
-  ActivePointer &pointer = _active_pointers[id];
-
   MouseWatcherParameter param;
   param.set_modifier_buttons(_mods);
-  param.set_mouse(pos);
-  param._pressure = pressure;
-  param._pointer_id = id;
+  param.set_mouse(region_pos);
+  param._pressure = ptr.get_pressure();
+  param._pointer_id = ptr.get_id();
 
-  pointer._max_pressure = std::max(pointer._max_pressure, pressure);
+  // pointer._max_pressure = std::max(pointer._max_pressure, pressure);
 
-  MouseWatcherRegion *region = pointer._region;
+  MouseWatcherRegion *region = _active_regions[ptr.get_id()];
   if (region != nullptr) {
     region->move(param);
   }
@@ -962,20 +961,20 @@ pointer_move(int id, const LPoint2 &pos, double pressure) {
  * Records the indicated pointer as no longer making contact.
  */
 void MouseWatcher::
-pointer_up(int id, const LPoint2 &pos) {
+pointer_up(const PointerData &ptr, const LPoint2 &region_pos) {
   nassertv(_lock.debug_is_locked());
 
-  MouseWatcherRegion *region = _active_pointers[id]._region;
-  if (region != nullptr && _active_pointers[id]._type != PointerType::mouse) {
+  MouseWatcherRegion *region = _active_regions[ptr.get_id()];
+  if (region != nullptr && ptr.get_type() != PointerType::mouse) {
     // Generate a release event.
     MouseWatcherParameter param;
     param.set_modifier_buttons(_mods);
-    param.set_mouse(pos);
+    param.set_mouse(region_pos);
     param.set_button(MouseButton::touch());
 
     // Are we still within the same region?
-    PN_stdfloat mx = (pos[0] + 1.0f) * 0.5f * (_frame[1] - _frame[0]) + _frame[0];
-    PN_stdfloat my = (pos[1] + 1.0f) * 0.5f * (_frame[3] - _frame[2]) + _frame[2];
+    PN_stdfloat mx = (region_pos[0] + 1.0f) * 0.5f * (_frame[1] - _frame[0]) + _frame[0];
+    PN_stdfloat my = (region_pos[1] + 1.0f) * 0.5f * (_frame[3] - _frame[2]) + _frame[2];
 
     const LVecBase4 &frame = region->get_frame();
     if (region->get_active() &&
@@ -987,7 +986,7 @@ pointer_up(int id, const LPoint2 &pos) {
       param.set_outside(true);
     }
 
-    param._pointer_id = id;
+    param._pointer_id = ptr.get_id();
     region->release(param);
   }
 }
@@ -1414,45 +1413,41 @@ do_transmit_data(DataGraphTraverser *trav, const DataNodeTransmit &input,
     }
   }
 
-  // Code for recording the mouse trail.
-  _num_trail_recent = 0;
   if (input.has_data(_pointer_events_input)) {
     const PointerEventList *this_pointer_events;
     DCAST_INTO_V(this_pointer_events, input.get_data(_pointer_events_input).get_ptr());
 
     for (size_t i = 0; i < this_pointer_events->get_num_events(); ++i) {
       const PointerEvent &event = this_pointer_events->get_event(i);
-      auto it = _active_pointers.find(event._id);
+      auto it = _active_regions.find(event._data.get_id());
 
       // Determine the position in the -1..1 range.
       LVecBase2 size = _pixel_size->get_value();
-      LPoint2 pos((PN_stdfloat)(2 * event._xpos) / size[0] - 1.0f,
-                  1.0f - (PN_stdfloat)(2 * event._ypos) / size[1]);
+      LPoint2 pos((PN_stdfloat)(2 * event._data.get_x()) / size[0] - 1.0f,
+                  1.0f - (PN_stdfloat)(2 * event._data.get_y()) / size[1]);
 
-      if (event._pressure > 0.0) {
-        if (it == _active_pointers.end()) {
-          pointer_down(event._type, event._id, pos, event._pressure);
+      if (event._data.get_pressure() > 0.0) {
+        if (it == _active_regions.end()) {
+          pointer_down(event._data, pos);
         } else {
-          pointer_move(event._id, pos, event._pressure);
+          pointer_move(event._data, pos);
         }
-      } else if (it != _active_pointers.end()) {
-        pointer_up(event._id, pos);
-        _active_pointers.erase(it);
+      } else if (it != _active_regions.end()) {
+        pointer_up(event._data, pos);
+        _active_regions.erase(it);
       }
     }
 
+     // Code for recording the mouse trail.
+    _num_trail_recent = 0;
     if (_trail_log_duration > 0.0) {
       _num_trail_recent = this_pointer_events->get_num_events();
       for (size_t i = 0; i < _num_trail_recent; i++) {
-        bool in_win = this_pointer_events->get_in_window(i);
-        int xpos = this_pointer_events->get_xpos(i);
-        int ypos = this_pointer_events->get_ypos(i);
-        int sequence = this_pointer_events->get_sequence(i);
-        double time = this_pointer_events->get_time(i);
-        _trail_log->add_event(in_win, xpos, ypos, sequence, time);
+        _trail_log->add_event(this_pointer_events->get_event(i));
       }
     }
   }
+
   if (_trail_log->get_num_events() > 0) {
     discard_excess_trail_log();
     update_trail_node();

+ 14 - 11
panda/src/tform/mouseWatcher.h

@@ -178,9 +178,9 @@ protected:
                            const MouseWatcherRegion *region,
                            const ButtonHandle &button);
 
-  void pointer_down(PointerType type, int id, const LPoint2 &pos, double pressure);
-  void pointer_move(int id, const LPoint2 &pos, double pressure);
-  void pointer_up(int id, const LPoint2 &pos);
+  void pointer_down(const PointerData &ptr, const LPoint2 &pos);
+  void pointer_move(const PointerData &ptr, const LPoint2 &pos);
+  void pointer_up(const PointerData &ptr, const LPoint2 &pos);
 
   void move();
   void press(ButtonHandle button, bool keyrepeat);
@@ -224,14 +224,17 @@ private:
 
   // Keeps track of which pointers are down and which regions they went down
   // in.
-  struct ActivePointer {
-    PT(MouseWatcherRegion) _region;
-    PointerType _type;
-    double _max_pressure;
-    double _time;
-  };
-  pmap<int, ActivePointer> _active_pointers;
-  int _primary_pointer = -1;
+  // struct ActivePointer {
+  //   PT(MouseWatcherRegion) _region;
+  //   PointerType _type;
+  //   double _max_pressure;
+  //   double _time;
+  // };
+  // pmap<int, ActivePointer> _active_pointers;
+  // int _primary_pointer = -1;
+
+  // Associate pointers with the mouse-watcher regions they're over.
+  pmap<int, PT(MouseWatcherRegion)> _active_regions;
 
   LVecBase4 _frame;