251 lines
7.0 KiB
Python
251 lines
7.0 KiB
Python
import importlib.machinery
|
|
import importlib.util
|
|
from pathlib import Path
|
|
from unittest.mock import Mock
|
|
|
|
import pytest
|
|
|
|
from fenrirscreenreader.inputDriver.x11Driver import X
|
|
from fenrirscreenreader.inputDriver.x11Driver import XK
|
|
from fenrirscreenreader.inputDriver.x11Driver import driver as X11Driver
|
|
|
|
|
|
def load_fenrir_entrypoint():
|
|
fenrir_path = Path(__file__).parents[2] / "src" / "fenrir"
|
|
loader = importlib.machinery.SourceFileLoader(
|
|
"fenrir_entrypoint_x11", str(fenrir_path)
|
|
)
|
|
spec = importlib.util.spec_from_loader(loader.name, loader)
|
|
module = importlib.util.module_from_spec(spec)
|
|
loader.exec_module(module)
|
|
return module
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_x11_mode_runs_in_foreground():
|
|
fenrir = load_fenrir_entrypoint()
|
|
args = fenrir.create_argument_parser().parse_args(["-x"])
|
|
|
|
assert fenrir.should_run_foreground(args) is True
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_removed_emulated_pty_flag_is_rejected():
|
|
fenrir = load_fenrir_entrypoint()
|
|
with pytest.raises(SystemExit):
|
|
fenrir.create_argument_parser().parse_args(["-e"])
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_removed_emulated_evdev_flag_is_rejected():
|
|
fenrir = load_fenrir_entrypoint()
|
|
with pytest.raises(SystemExit):
|
|
fenrir.create_argument_parser().parse_args(["-E"])
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_x11_cli_accepts_window_id():
|
|
fenrir = load_fenrir_entrypoint()
|
|
args = fenrir.create_argument_parser().parse_args(
|
|
["-x", "--x11-window-id", "0x123"]
|
|
)
|
|
|
|
assert args.x11_window_id == "0x123"
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_x11_window_id_requires_x11_mode():
|
|
fenrir = load_fenrir_entrypoint()
|
|
args = fenrir.create_argument_parser().parse_args(
|
|
["--x11-window-id", "0x123"]
|
|
)
|
|
|
|
is_valid, error = fenrir.validate_arguments(args)
|
|
|
|
assert is_valid is False
|
|
assert "--x11-window-id requires --x11" == error
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_x11_key_name_mapping_for_keypad_and_capslock():
|
|
x11 = X11Driver()
|
|
|
|
assert x11.keysym_name_to_key_name("KP_0") == "KEY_KP0"
|
|
assert x11.keysym_name_to_key_name("KP_Insert") == "KEY_KP0"
|
|
assert x11.keysym_name_to_key_name("Caps_Lock") == "KEY_CAPSLOCK"
|
|
assert x11.keysym_name_to_key_name("Super_L") == "KEY_LEFTMETA"
|
|
assert x11.keysym_name_to_key_name("Multi_key") == "KEY_COMPOSE"
|
|
assert x11.keysym_name_to_key_name("Next") == "KEY_PAGEDOWN"
|
|
assert x11.keysym_name_to_key_name("Prior") == "KEY_PAGEUP"
|
|
assert x11.keysym_name_to_key_name("a") == "KEY_A"
|
|
assert x11.keysym_name_to_key_name("F10") == "KEY_F10"
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_x11_keycode_mapping_prefers_keypad_aliases():
|
|
x11 = X11Driver()
|
|
x11.display = Mock()
|
|
keysyms = {
|
|
0: XK.string_to_keysym("Up"),
|
|
1: XK.string_to_keysym("KP_8"),
|
|
2: 0,
|
|
3: 0,
|
|
4: 0,
|
|
5: 0,
|
|
6: 0,
|
|
7: 0,
|
|
}
|
|
x11.display.keycode_to_keysym.side_effect = lambda keycode, column: keysyms[column]
|
|
|
|
assert x11.keycode_to_key_name(80) == "KEY_KP8"
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_x11_keycode_mapping_preserves_plain_insert():
|
|
x11 = X11Driver()
|
|
x11.display = Mock()
|
|
keysyms = {
|
|
0: XK.string_to_keysym("Insert"),
|
|
1: 0,
|
|
2: 0,
|
|
3: 0,
|
|
4: 0,
|
|
5: 0,
|
|
6: 0,
|
|
7: 0,
|
|
}
|
|
x11.display.keycode_to_keysym.side_effect = lambda keycode, column: keysyms[column]
|
|
|
|
assert x11.keycode_to_key_name(118) == "KEY_INSERT"
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_x11_keycode_mapping_detects_keypad_insert():
|
|
x11 = X11Driver()
|
|
x11.display = Mock()
|
|
keysyms = {
|
|
0: XK.string_to_keysym("Insert"),
|
|
1: XK.string_to_keysym("KP_Insert"),
|
|
2: 0,
|
|
3: 0,
|
|
4: 0,
|
|
5: 0,
|
|
6: 0,
|
|
7: 0,
|
|
}
|
|
x11.display.keycode_to_keysym.side_effect = lambda keycode, column: keysyms[column]
|
|
|
|
assert x11.keycode_to_key_name(90) == "KEY_KP0"
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_x11_key_name_to_keysym_names_includes_numlock_aliases():
|
|
x11 = X11Driver()
|
|
|
|
assert x11.key_name_to_keysym_names("KEY_KP0") == ["KP_0", "KP_Insert"]
|
|
assert "KP_Delete" in x11.key_name_to_keysym_names("KEY_KPDOT")
|
|
assert "Caps_Lock" in x11.key_name_to_keysym_names("KEY_CAPSLOCK")
|
|
assert "Super_L" in x11.key_name_to_keysym_names("KEY_META")
|
|
assert "Meta_R" in x11.key_name_to_keysym_names("KEY_META")
|
|
assert x11.key_name_to_keysym_names("KEY_COMPOSE") == ["Multi_key"]
|
|
assert "Next" in x11.key_name_to_keysym_names("KEY_PAGEDOWN")
|
|
assert "Prior" in x11.key_name_to_keysym_names("KEY_PAGEUP")
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_x11_should_emit_unbound_mapped_keys_for_speech_interrupt():
|
|
x11 = X11Driver()
|
|
x11.interesting_keys = set()
|
|
|
|
assert x11.should_emit_key("KEY_ESC") is True
|
|
assert x11.should_emit_key("KEY_ENTER") is True
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_x11_build_passive_grabs_for_fenrir_keys_and_shortcuts():
|
|
x11 = X11Driver()
|
|
input_manager = Mock(convert_event_name=lambda key: key)
|
|
x11.env = {
|
|
"input": {
|
|
"fenrir_key": ["KEY_KP0", "KEY_CAPSLOCK"],
|
|
"script_key": [],
|
|
},
|
|
"rawBindings": {
|
|
"fenrir_combo": [1, ["KEY_FENRIR", "KEY_KP8"]],
|
|
"bare_keypad": [1, ["KEY_KP5"]],
|
|
"ctrl_keypad": [1, ["KEY_CTRL", "KEY_KP2"]],
|
|
},
|
|
"runtime": {"InputManager": input_manager},
|
|
}
|
|
|
|
grabs = x11.build_passive_grabs()
|
|
|
|
assert ("KEY_KP0", 0) in grabs
|
|
assert ("KEY_CAPSLOCK", 0) in grabs
|
|
assert ("KEY_KP5", 0) in grabs
|
|
assert ("KEY_KP2", X.ControlMask) in grabs
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_x11_parse_window_id_accepts_decimal_and_hex():
|
|
x11 = X11Driver()
|
|
|
|
assert x11.parse_window_id("123") == 123
|
|
assert x11.parse_window_id("0x123") == 0x123
|
|
assert x11.parse_window_id("") is None
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_x11_write_event_buffer_clears_buffer():
|
|
x11 = X11Driver()
|
|
x11._initialized = True
|
|
x11.env = {"input": {"event_buffer": ["KEY_KP0"]}}
|
|
|
|
x11.write_event_buffer()
|
|
|
|
assert x11.env["input"]["event_buffer"] == []
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_x11_find_num_lock_mask_uses_modifier_mapping():
|
|
x11 = X11Driver()
|
|
x11.display = Mock()
|
|
x11.display.keysym_to_keycode.return_value = 77
|
|
x11.display.get_modifier_mapping.return_value = [
|
|
[],
|
|
[],
|
|
[],
|
|
[],
|
|
[77],
|
|
[],
|
|
[],
|
|
[],
|
|
]
|
|
|
|
assert x11.find_num_lock_mask() == X.Mod2Mask
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_x11_handle_key_event_keeps_event_buffer_for_input_manager():
|
|
x11 = X11Driver()
|
|
x11.active = True
|
|
x11.interesting_keys = {"KEY_KP0"}
|
|
x11.env = {
|
|
"input": {
|
|
"curr_input": [],
|
|
"event_buffer": [],
|
|
},
|
|
"runtime": {
|
|
"InputManager": Mock(convert_event_name=lambda key: key),
|
|
"DebugManager": Mock(),
|
|
},
|
|
}
|
|
event_queue = Mock()
|
|
event = Mock(type=X.KeyPress, detail=90, state=0)
|
|
x11.keycode_to_key_name = Mock(return_value="KEY_KP0")
|
|
|
|
x11.handle_x_event(event, event_queue)
|
|
|
|
assert x11.env["input"]["event_buffer"][0]["event_name"] == "KEY_KP0"
|
|
event_queue.put.assert_called_once()
|