diff --git a/piker/ui/_interaction.py b/piker/ui/_interaction.py index 9e4ce0e4..fd8c8e13 100644 --- a/piker/ui/_interaction.py +++ b/piker/ui/_interaction.py @@ -226,6 +226,16 @@ async def handle_viewmode_kb_inputs( if mods == Qt.KeyboardModifier.ControlModifier: ctrl = True + # Real key chords deliver modifier-only events before the + # bound key. Nothing below handles those as actions. + if key in { + Qt.Key.Key_Alt, + Qt.Key.Key_Control, + Qt.Key.Key_Meta, + Qt.Key.Key_Shift, + }: + continue + # UI REPL-shell, with ctrl-p (for "pause") if ( ctrl diff --git a/tests/test_gap_overlays.py b/tests/test_gap_overlays.py index 629fec89..2b1eea50 100644 --- a/tests/test_gap_overlays.py +++ b/tests/test_gap_overlays.py @@ -10,7 +10,6 @@ from types import SimpleNamespace import msgspec import numpy as np -from PyQt6.QtGui import QKeyEvent from PyQt6.QtWidgets import QGraphicsScene import pyqtgraph as pg import pytest @@ -36,7 +35,6 @@ from piker.ui._interaction import ( ) from piker.ui.qt import ( QApplication, - QEvent, QPointF, QRectF, Qt, @@ -630,14 +628,16 @@ def test_ctrl_g_event_renders_real_history_overlay( ) -> None: ''' - Route a real Qt Ctrl-G event into a rendered history gap layer. + Route real QtBot Ctrl-G input into a rendered history gap layer. Calling the toggle helper directly does not prove that Qt event filtering, `KeyboardMsg` conversion or the asynchronous view-mode handler recognizes the configured binding. Install the production - `EventRelay` on a real widget, send one offscreen `QKeyEvent`, + `EventRelay` on a shown and focused widget, press Ctrl-G through + `QtBot.keyPress()` so Qt emits its modifier-only event before G, and wait until the handler blocks again. The resulting manager - and scene state prove the complete local keyboard path ran. + and scene state prove the complete local keyboard path ran + without crashing or directly dispatching a synthetic event. ''' ds: SimpleNamespace @@ -670,6 +670,13 @@ def test_ctrl_g_event_renders_real_history_overlay( cursor=SimpleNamespace(in_query_mode=False), ) source.setMouseMode = lambda mode: None + source.setFocusPolicy(Qt.FocusPolicy.StrongFocus) + with qtbot.waitExposed(source): + source.show() + source.raise_() + source.activateWindow() + source.setFocus() + qtbot.waitUntil(lambda: source.hasFocus()) async def drive_key_event() -> None: ''' @@ -680,13 +687,13 @@ def test_ctrl_g_event_renders_real_history_overlay( source, dss={FQME: ds}, ): - key_event: QKeyEvent = QKeyEvent( - QEvent.Type.KeyPress, + qtbot.keyPress( + source, Qt.Key.Key_G, - Qt.KeyboardModifier.ControlModifier, - 'g', + modifier=( + Qt.KeyboardModifier.ControlModifier + ), ) - assert QApplication.sendEvent(source, key_event) await wait_all_tasks_blocked() try: