33#include <NDEVR/WidgetOptions.h>
34#include <NDEVR/WindowInstance.h>
35#include <NDEVR/Thread.h>
36#include <NDEVR/TimeSpan.h>
38#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
40#define points touchPoints
42#if NDEVR_SUPPORTS_THREADING
43#define RUN_MOUSE_MANAGER_THREADED 1
45#define RUN_MOUSE_MANAGER_THREADED 0
50 class NDEVRMouseManager
51#if NDEVR_SUPPORTS_THREADING
58 , m_use_mouse_clicks(
true)
59 , m_last_touch_scale_factor(Constant<fltp08>::NaN)
60 , m_last_mouse_press_time(0)
62#if NDEVR_SUPPORTS_THREADING
63 setThreadName(
"Mouse Manager");
66 static NDEVRMouseManager& defaultInstance()
68 static NDEVRMouseManager manager;
69 if (!manager.m_is_init)
71#if RUN_MOUSE_MANAGER_THREADED
74 manager.m_is_init =
true;
78 void setUseMouseClicks(
bool use_mouse_clicks)
80 m_use_mouse_clicks = use_mouse_clicks;
82 void processMouseEvent()
84 if (!m_last_mouse_events.isEmpty())
86 while (!m_last_mouse_events.isEmpty())
90#if RUN_MOUSE_MANAGER_THREADED
91 std::unique_lock<std::mutex> crit_lock(m_critical_section);
93 event = m_last_mouse_events[0];
94 m_last_mouse_events.removeIndex(0);
96 if(event.window_instance)
97 event.window_instance->createEvent(event);
99#if RUN_MOUSE_MANAGER_THREADED
100 ThreadFunctions::RequestSleep(TimeSpan(0.01));
104 void eraseOldestEvent()
106#if RUN_MOUSE_MANAGER_THREADED
107 std::unique_lock<std::mutex> crit_lock(m_critical_section);
109 if (!m_last_mouse_events.isEmpty())
110 m_last_mouse_events.removeIndex(0);
112 MouseEvent oldestEvent()
const
114#if RUN_MOUSE_MANAGER_THREADED
115 std::unique_lock<std::mutex> crit_lock(m_critical_section);
117 return m_last_mouse_events.get(0);
119 void clearEvents(
const WindowInstance* instance)
121#if RUN_MOUSE_MANAGER_THREADED
122 std::unique_lock<std::mutex> crit_lock(m_critical_section);
124 for (uint04 i = m_last_mouse_events.size() - 1; !isNaN(i); --i)
126 if (m_last_mouse_events[i].window_instance == instance)
127 m_last_mouse_events.removeIndex(i);
131#if RUN_MOUSE_MANAGER_THREADED
132 void stopThread()
override
135 std::unique_lock<std::mutex> crit_lock(m_critical_section);
136 m_last_mouse_events.clear();
137 m_is_running =
false;
138 ConcurrentOperation::notifyAll(&m_critical_section);
140 Thread::stopThread();
144#if RUN_MOUSE_MANAGER_THREADED
145 virtual void run()
override
150 std::unique_lock<std::mutex> crit_lock(m_critical_section);
151 while(m_is_running && m_last_mouse_events.size() == 0)
152 ConcurrentOperation::wait(&m_critical_section, 100000000, crit_lock);
156 void addTouchEvent(Buffer<Vector<2, fltp04>> location, Vector<2, uint04> size,
bool touch_pressed, WindowInstance* instance =
nullptr)
158 if (location.size() == 0)
160 MouseEvent mouse_event(instance);
161 mouse_event.click_type = MouseEvent::e_left_button;
162 mouse_event.event_type = MouseEvent::e_mouse_exited;
163 addMouseEvent(mouse_event);
165 if (location.size() == 1)
167 MouseEvent mouse_event(instance);
168 mouse_event.click_type = MouseEvent::e_left_button;
169 mouse_event.event_location = location[A];
170 mouse_event.event_type = MouseEvent::e_mouse_dragged;
171 addMouseEvent(mouse_event);
173 if (location.size() == 2)
175 fltp04 scale_factor = distance<fltp04>(location[A], location[B]);
183 m_last_touch_press_point[0] = location[A];
184 m_last_touch_press_point[1] = location[B];
185 m_last_touch_scale_factor = scale_factor;
196 if (isNaN(m_last_touch_press_point))
198 m_last_touch_press_point[0] = location[A];
199 m_last_touch_press_point[1] = location[B];
200 m_last_touch_scale_factor = scale_factor;
204 MouseEvent mouse_event(instance);
205 mouse_event.event_location = (location[A] + location[B]) / 2.0f;
206 mouse_event.number_of_clicks = 1;
214 mouse_event.event_type = MouseEvent::e_touch_zoomed;
215 mouse_event.distance_scrolled[X] = 0.0f;
216 mouse_event.distance_scrolled[Y] = 2000.0 * (scale_factor - m_last_touch_scale_factor) / size.magnitude<fltp08>();
217 mouse_event.click_type = MouseEvent::e_center_button;
218 m_last_touch_scale_factor = scale_factor;
219 addMouseEvent(mouse_event);
227 void clearTouchEvent(WindowInstance* instance)
229 m_last_touch_scale_factor = Constant<fltp08>::NaN;
230 if (!isNaN(m_last_touch_press_point[0]))
232 MouseEvent mouse_event(instance);
233 mouse_event.event_location = (m_last_touch_press_point[0], m_last_touch_press_point[1]) / 2.0f;
234 mouse_event.number_of_clicks = 1;
235 mouse_event.click_type = MouseEvent::e_right_button;
236 mouse_event.event_type = MouseEvent::e_mouse_released;
238 m_last_touch_press_point[0] = Constant<fltp04>::NaN;
239 m_last_touch_press_point[1] = Constant<fltp04>::NaN;
240 addMouseEvent(mouse_event);
243 bool addMouseEvent(QEvent* event, Vector<2, uint04> size, WindowInstance* instance =
nullptr)
245 QEvent::Type q_event =
event->type();
248 case QEvent::TouchEnd:
249 clearTouchEvent(instance);
251 case QEvent::TouchBegin:
252 case QEvent::TouchUpdate:
254 QTouchEvent* touchEvent =
static_cast<QTouchEvent*
>(event);
255 QList<QTouchEvent::TouchPoint> touch_points = touchEvent->points();
256 if (touch_points.count() == 2)
259 const QTouchEvent::TouchPoint& touchPoint0 = touch_points.first();
260 const QTouchEvent::TouchPoint& touchPoint1 = touch_points.last();
261 Vector<2, fltp04> p0(touchPoint0.position().x(), touchPoint0.position().y());
262 Vector<2, fltp04> p1(touchPoint1.position().x(), touchPoint1.position().y());
263 addTouchEvent({ p0, p1 }, size, touchEvent->touchPointStates() & Qt::TouchPointPressed, instance);
269 MouseEvent mouse_event(instance);
270 m_last_touch_scale_factor = Constant<fltp08>::NaN;
271 mouse_event.event_type = MouseEvent::e_mouse_exited;
272 addMouseEvent(mouse_event);
273 clearTouchEvent(instance);
275 case QEvent::MouseButtonPress:
276 case QEvent::MouseButtonRelease:
277 clearTouchEvent(instance);
279 case QEvent::MouseMove:
280 if (!isNaN(m_last_touch_scale_factor))
283 case QEvent::MouseTrackingChange:
284 case QEvent::MouseButtonDblClick:
288 m_last_touch_scale_factor = Constant<fltp08>::NaN;
289 const QMouseEvent* qt_mouse_event =
dynamic_cast<QMouseEvent*
>(event);
290 if (qt_mouse_event ==
nullptr)
293 MouseEvent mouse_event(instance);
294 mouse_event.event_location[X] = cast<fltp04>(qt_mouse_event->pos().x());
295 mouse_event.event_location[Y] = cast<fltp04>(qt_mouse_event->pos().y());
296 switch (qt_mouse_event->button())
299 if (WidgetOptions::IsTouchOptimized() && m_last_mouse_press_time != 0 && qt_mouse_event->timestamp() - m_last_mouse_press_time > 500)
300 mouse_event.click_type = MouseEvent::e_right_button;
302 case Qt::LeftButton: mouse_event.click_type = MouseEvent::e_left_button;
break;
303 case Qt::RightButton: mouse_event.click_type = MouseEvent::e_right_button;
break;
304 case Qt::MiddleButton: mouse_event.click_type = MouseEvent::e_center_button;
break;
307 mouse_event.number_of_clicks = 1;
308 mouse_event.key_modifier = 0;
309 Qt::KeyboardModifiers mods = qt_mouse_event->modifiers();
310 if (mods & Qt::KeyboardModifier::ShiftModifier)
311 mouse_event.key_modifier |= KeyEvent::SHIFT;
312 if (mods & Qt::KeyboardModifier::ControlModifier)
313 mouse_event.key_modifier |= KeyEvent::CTRL;
314 if (mods & Qt::KeyboardModifier::AltModifier)
315 mouse_event.key_modifier |= KeyEvent::ALT;
316 switch (event->type())
318 case QEvent::MouseButtonPress:
320 mouse_event.event_type = MouseEvent::e_mouse_pressed;
322 m_last_mouse_press_time = qt_mouse_event->timestamp();
323 m_last_mouse_press_point = mouse_event.event_location;
325 case QEvent::MouseButtonRelease:
327 mouse_event.event_type = MouseEvent::e_mouse_released;
328 if (m_use_mouse_clicks && qt_mouse_event->timestamp() - m_last_mouse_press_time < 200)
329 mouse_event.event_type = MouseEvent::e_mouse_clicked;
330 m_last_mouse_press_time = 0;
331 m_last_mouse_press_point = Constant<Vector<2, fltp04>>::NaN;
333 case QEvent::MouseButtonDblClick:
335 m_last_mouse_press_time = 0;
336 mouse_event.event_type = MouseEvent::e_mouse_clicked;
337 mouse_event.number_of_clicks = 2;
339 case QEvent::MouseTrackingChange:
340 mouse_event.event_type = MouseEvent::e_mouse_scrolled;
342 case QEvent::DragMove:
343 case QEvent::MouseMove:
345 Qt::MouseButtons qt_buttons = qt_mouse_event->buttons();
348 case Qt::LeftButton: mouse_event.click_type = MouseEvent::e_left_button;
break;
349 case Qt::RightButton: mouse_event.click_type = MouseEvent::e_right_button;
break;
350 case Qt::MiddleButton: mouse_event.click_type = MouseEvent::e_center_button;
break;
351 default: mouse_event.event_type = MouseEvent::e_mouse_moved;
353 if (mouse_event.click_type != MouseEvent::none)
355 if (distance(m_last_mouse_press_point / size.as<2, fltp04>(), mouse_event.event_location / size.as<2, fltp04>()) > 0.03)
356 m_last_mouse_press_time = 0;
357 mouse_event.event_type = MouseEvent::e_mouse_dragged;
361 mouse_event.event_type = MouseEvent::e_mouse_moved;
367 addMouseEvent(mouse_event);
372 QWheelEvent* wheel_event =
dynamic_cast<QWheelEvent*
>(event);
373 MouseEvent mouse_event(instance);
374 mouse_event.event_type = MouseEvent::e_mouse_scrolled;
375 mouse_event.distance_scrolled[X] = wheel_event->angleDelta().x();
376 mouse_event.distance_scrolled[Y] = wheel_event->angleDelta().y();
377 if (wheel_event->inverted())
378 mouse_event.distance_scrolled = -mouse_event.distance_scrolled;
379 mouse_event.event_location[X] = cast<fltp04>(wheel_event->position().x());
380 mouse_event.event_location[Y] = cast<fltp04>(wheel_event->position().y());
381 mouse_event.number_of_clicks = 1;
382 mouse_event.click_type = MouseEvent::e_center_button;
383 addMouseEvent(mouse_event);
392 void addMouseEvent(MouseEvent& mouse_event)
394#if RUN_MOUSE_MANAGER_THREADED
395 std::unique_lock<std::mutex> crit_lock(m_critical_section);
397 switch (mouse_event.event_type)
399 case MouseEvent::e_mouse_scrolled:
400 if (m_last_mouse_events.isEmpty() || m_last_mouse_events.last().event_type != MouseEvent::e_mouse_scrolled)
401 m_last_mouse_events.add(mouse_event);
403 m_last_mouse_events.last().distance_scrolled += mouse_event.distance_scrolled;
405 case MouseEvent::e_touch_zoomed:
406 if (m_last_mouse_events.isEmpty() || m_last_mouse_events.last().event_type != MouseEvent::e_touch_zoomed)
407 m_last_mouse_events.add(mouse_event);
409 m_last_mouse_events.last().distance_scrolled += mouse_event.distance_scrolled;
411 case MouseEvent::e_mouse_moved:
412 case MouseEvent::e_mouse_dragged:
413 if (m_last_mouse_events.isEmpty() || m_last_mouse_events.last().event_type != mouse_event.event_type)
414 m_last_mouse_events.add(mouse_event);
416 m_last_mouse_events.last().event_location = mouse_event.event_location;
418 case MouseEvent::e_mouse_released:
419 m_last_mouse_events.add(mouse_event);
422 m_last_mouse_events.add(mouse_event);
425#if !RUN_MOUSE_MANAGER_THREADED
428 ConcurrentOperation::notifyAll(&m_critical_section);
431 const Buffer<MouseEvent>& mouseEvents()
const
433 return m_last_mouse_events;
435 static ApplicationOption<bool> seperate_mouse_thread;
438 bool m_use_mouse_clicks;
439#if RUN_MOUSE_MANAGER_THREADED
440 mutable std::mutex m_critical_section;
442 Buffer<MouseEvent> m_last_mouse_events;
443 Vector<2, fltp04> m_last_mouse_press_point;
446 Vector<2, Vector<2, fltp04>> m_last_touch_press_point = Constant<Vector<2, Vector<2, fltp04>>>::NaN;
448 fltp08 m_last_touch_scale_factor = Constant<fltp08>::NaN;
449 uint08 m_last_mouse_press_time;
452#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)