Files
voculinux/tests/test_shortcut_capture.py
T
4d8c58f536 feat(shortcuts): allow bare function keys for push-to-talk (#815)
* feat(shortcuts): allow bare function keys for push-to-talk

Accept F1–F24 shortcuts without a modifier so dictation can use a
dedicated key (e.g. F10) instead of Shift/Ctrl/Alt combos that fire
while typing. Settings shortcut capture records bare function keys too.

* fix(shortcuts): evdev availability for bare function keys

Check EV_KEY capabilities for bare F1-F24 shortcuts instead of an empty
modifier name. Add availability regression tests and type hints on new tests.

* refactor(shortcuts): fold bare F-keys into ShortcutSpec

Teach primary_modifier to return the bare key so parse_shortcut and the
backend stop special-casing empty modifiers. Capture now asks the parser
instead of re-encoding the F-key allow-list, and evdev shares one
capability probe for modifiers and main keys.

---------

Co-authored-by: Jatin K Malik <jatinkrmalik@gmail.com>
2026-09-12 12:39:25 -07:00

59 lines
1.7 KiB
Python

"""Tests for the shortcut-capture keyname mapping in the settings dialog.
Covers the pure `_gdk_keyname_to_token` helper that turns a GDK key-symbol name
(from the "Record shortcut" capture) into a canonical main-key token. The GTK
dialog itself can't be instantiated under the mocked-GTK test harness, but this
module-level helper is pure and directly testable.
"""
import pytest
from vocalinux.ui.settings_dialog import _gdk_keyname_to_token, _shortcut_from_capture
@pytest.mark.parametrize(
"name,expected",
[
("r", "r"),
("A", "a"), # capture may report a shifted/upper name
("5", "5"),
("F5", "f5"),
("f12", "f12"),
("space", "space"),
("Return", "enter"),
("Escape", "esc"),
("Page_Up", "pageup"),
("comma", "comma"),
("bracketleft", "leftbracket"),
],
)
def test_maps_known_keys(name: str, expected: str) -> None:
assert _gdk_keyname_to_token(name) == expected
@pytest.mark.parametrize("name", ["Control_L", "Alt_R", "Shift_L", "Super_L", "", None, "F25"])
def test_rejects_modifiers_and_unknown(name: str | None) -> None:
# Modifiers, empty/None, and out-of-range function keys are not main keys.
assert _gdk_keyname_to_token(name) is None
@pytest.mark.parametrize(
"modifiers,token,expected",
[
(["alt"], "r", "alt+r"),
(["ctrl", "alt"], "f5", "ctrl+alt+f5"),
([], "f10", "f10"),
([], "f24", "f24"),
([], "r", None),
([], "space", None),
([], None, None),
(["shift"], "f10", "shift+f10"),
],
)
def test_shortcut_from_capture(
modifiers: list[str],
token: str | None,
expected: str | None,
) -> None:
assert _shortcut_from_capture(modifiers, token) == expected