From 4026cd5c261517fa3c467751de07824e75e4f0bf Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Tue, 24 Oct 2023 23:07:37 +0200 Subject: [PATCH] Add timestamp to events, and buttons to wheel events (#397) * add buttons to glfw wheel events (and make buttons and modifiers order consistent). * Add buttons to wheel event for qt * Add time_stamp to events (if they don't have it already) * explain todo a bit better --------- Co-authored-by: Korijn van Golen --- wgpu/gui/base.py | 14 +++++++++----- wgpu/gui/glfw.py | 21 +++++++++++++++------ wgpu/gui/qt.py | 10 ++++++++-- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/wgpu/gui/base.py b/wgpu/gui/base.py index 8d5d5cc4..2618fc0f 100644 --- a/wgpu/gui/base.py +++ b/wgpu/gui/base.py @@ -237,7 +237,9 @@ def _get_event_wait_time(self): target_time = self._last_event_time + 1.0 / rate return max(0, target_time - now) - def _handle_event_rate_limited(self, ev, call_later_func, match_keys, accum_keys): + def _handle_event_rate_limited( + self, event, call_later_func, match_keys, accum_keys + ): """Alternative `to handle_event()` for events that must be rate-limted. If any of the `match_keys` keys of the new event differ from the currently pending event, the old event is dispatched now. The `accum_keys` keys of @@ -252,23 +254,25 @@ def _handle_event_rate_limited(self, ev, call_later_func, match_keys, accum_keys Subclasses that use this method must use ``_handle_event_and_flush()`` where they would otherwise call ``handle_event()``, to preserve event order. """ - event_type = ev["event_type"] + event_type = event["event_type"] + event.setdefault("time_stamp", time.perf_counter()) # We may need to emit the old event. Otherwise, we need to update the new one. old = self._pending_events.get(event_type, None) if old: - if any(ev[key] != old[key] for key in match_keys): + if any(event[key] != old[key] for key in match_keys): self.handle_event(old) else: for key in accum_keys: - ev[key] = old[key] + ev[key] + event[key] = old[key] + event[key] # Make sure that we have scheduled a moment to handle events if not self._pending_events: call_later_func(self._get_event_wait_time(), self._handle_pending_events) # Store the event object - self._pending_events[event_type] = ev + self._pending_events[event_type] = event def _handle_event_and_flush(self, event): """Call handle_event after flushing any pending (rate-limited) events.""" + event.setdefault("time_stamp", time.perf_counter()) self._handle_pending_events() self.handle_event(event) diff --git a/wgpu/gui/glfw.py b/wgpu/gui/glfw.py index 614713f3..d68eaf60 100644 --- a/wgpu/gui/glfw.py +++ b/wgpu/gui/glfw.py @@ -152,8 +152,8 @@ def __init__(self, *, size=None, title=None, **kwargs): glfw.set_window_iconify_callback(self._window, weakbind(self._on_iconify)) # User input - self._key_modifiers = set() - self._pointer_buttons = set() + self._key_modifiers = [] + self._pointer_buttons = [] self._pointer_pos = 0, 0 self._double_click_state = {"clicks": 0} glfw.set_mouse_button_callback(self._window, weakbind(self._on_mouse_button)) @@ -323,10 +323,14 @@ def _on_mouse_button(self, window, but, action, mods): if action == glfw.PRESS: event_type = "pointer_down" - self._pointer_buttons.add(button) + buttons = set(self._pointer_buttons) + buttons.add(button) + self._pointer_buttons = list(sorted(buttons)) elif action == glfw.RELEASE: event_type = "pointer_up" - self._pointer_buttons.discard(button) + buttons = set(self._pointer_buttons) + buttons.discard(button) + self._pointer_buttons = list(sorted(buttons)) else: return @@ -426,6 +430,7 @@ def _on_scroll(self, window, dx, dy): "dy": -100.0 * dy, "x": self._pointer_pos[0], "y": self._pointer_pos[1], + "buttons": list(self._pointer_buttons), "modifiers": list(self._key_modifiers), } match_keys = {"modifiers"} @@ -438,11 +443,15 @@ def _on_key(self, window, key, scancode, action, mods): if action == glfw.PRESS: event_type = "key_down" if modifier: - self._key_modifiers.add(modifier) + modifiers = set(self._key_modifiers) + modifiers.add(modifier) + self._key_modifiers = list(sorted(modifiers)) elif action == glfw.RELEASE: event_type = "key_up" if modifier: - self._key_modifiers.discard(modifier) + modifiers = set(self._key_modifiers) + modifiers.discard(modifier) + self._key_modifiers = list(sorted(modifiers)) else: # glfw.REPEAT return diff --git a/wgpu/gui/qt.py b/wgpu/gui/qt.py index d429e803..2fa763fe 100644 --- a/wgpu/gui/qt.py +++ b/wgpu/gui/qt.py @@ -253,8 +253,8 @@ def _mouse_event(self, event_type, event, touches=True): if touches: ev.update( { - "ntouches": 0, # TODO - "touches": {}, # TODO + "ntouches": 0, + "touches": {}, # TODO: Qt touch events } ) @@ -285,6 +285,11 @@ def wheelEvent(self, event): # noqa: N802 for mod in MODIFIERS_MAP.keys() if mod & event.modifiers() ] + buttons = [ + BUTTON_MAP[button] + for button in BUTTON_MAP.keys() + if button & event.buttons() + ] ev = { "event_type": "wheel", @@ -292,6 +297,7 @@ def wheelEvent(self, event): # noqa: N802 "dy": -event.angleDelta().y(), "x": event.position().x(), "y": event.position().y(), + "buttons": buttons, "modifiers": modifiers, } match_keys = {"modifiers"}