Support modifier-first Fenrir shortcuts
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
|
||||
from fenrirscreenreader.core.eventData import FenrirEventType
|
||||
from fenrirscreenreader.core.fenrirManager import FenrirManager
|
||||
from fenrirscreenreader.core.inputManager import InputManager
|
||||
|
||||
|
||||
def create_handle_input_manager(no_key_pressed):
|
||||
manager = FenrirManager.__new__(FenrirManager)
|
||||
manager.modifierInput = False
|
||||
manager.modifier_prefix_input = True
|
||||
manager.singleKeyCommand = False
|
||||
manager.command = ""
|
||||
manager.detect_shortcut_command = Mock()
|
||||
manager.update_key_forward = Mock()
|
||||
|
||||
input_manager = Mock(
|
||||
convert_event_name=Mock(side_effect=lambda key_name: key_name),
|
||||
no_key_pressed=Mock(return_value=no_key_pressed),
|
||||
)
|
||||
manager.environment = {
|
||||
"input": {"key_forward": 0},
|
||||
"runtime": {
|
||||
"DebugManager": Mock(write_debug_out=Mock()),
|
||||
"InputManager": input_manager,
|
||||
"ScreenManager": Mock(is_ignored_screen=Mock(return_value=False)),
|
||||
"HelpManager": Mock(is_tutorial_mode=Mock(return_value=False)),
|
||||
"VmenuManager": Mock(get_active=Mock(return_value=False)),
|
||||
"DiffReviewManager": Mock(is_active=Mock(return_value=False)),
|
||||
"SpeechHistoryManager": Mock(is_active=Mock(return_value=False)),
|
||||
"CommandManager": Mock(execute_default_trigger=Mock()),
|
||||
},
|
||||
}
|
||||
return manager, input_manager
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_input_manager_recognizes_conventional_modifier_prefix():
|
||||
input_manager = InputManager()
|
||||
input_manager.env = {"input": {"curr_input": ["KEY_CTRL", "KEY_SHIFT"]}}
|
||||
|
||||
assert input_manager.curr_input_is_modifier_prefix() is True
|
||||
|
||||
input_manager.env["input"]["curr_input"].append("KEY_S")
|
||||
|
||||
assert input_manager.curr_input_is_modifier_prefix() is False
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_first_conventional_modifier_starts_deferred_prefix():
|
||||
manager = FenrirManager.__new__(FenrirManager)
|
||||
manager.modifierInput = False
|
||||
manager.modifier_prefix_input = False
|
||||
manager.singleKeyCommand = False
|
||||
manager.command = ""
|
||||
input_manager = Mock(
|
||||
is_key_press=Mock(return_value=True),
|
||||
curr_input_has_command_modifier=Mock(return_value=False),
|
||||
curr_input_is_modifier_prefix=Mock(return_value=True),
|
||||
get_curr_shortcut=Mock(return_value=str([1, ["KEY_CTRL"]])),
|
||||
get_command_for_shortcut=Mock(return_value=""),
|
||||
)
|
||||
manager.environment = {
|
||||
"input": {
|
||||
"key_forward": 0,
|
||||
"prev_input": [],
|
||||
"curr_input": ["KEY_CTRL"],
|
||||
},
|
||||
"runtime": {
|
||||
"InputManager": input_manager,
|
||||
"EventManager": Mock(put_to_event_queue=Mock()),
|
||||
"VmenuManager": Mock(get_active=Mock(return_value=False)),
|
||||
"DiffReviewManager": Mock(is_active=Mock(return_value=False)),
|
||||
"SpeechHistoryManager": Mock(is_active=Mock(return_value=False)),
|
||||
},
|
||||
}
|
||||
|
||||
manager.detect_shortcut_command()
|
||||
|
||||
assert manager.modifier_prefix_input is True
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_fenrir_shortcut_is_dispatched_when_ctrl_is_pressed_first():
|
||||
manager = FenrirManager.__new__(FenrirManager)
|
||||
manager.modifierInput = False
|
||||
manager.modifier_prefix_input = True
|
||||
manager.singleKeyCommand = False
|
||||
manager.command = ""
|
||||
|
||||
event_manager = Mock(put_to_event_queue=Mock())
|
||||
input_manager = Mock(
|
||||
is_key_press=Mock(return_value=False),
|
||||
no_key_pressed=Mock(return_value=False),
|
||||
curr_input_has_command_modifier=Mock(return_value=True),
|
||||
get_curr_shortcut=Mock(
|
||||
side_effect=[
|
||||
str([1, ["KEY_CTRL", "KEY_FENRIR"]]),
|
||||
str([1, ["KEY_CTRL", "KEY_FENRIR", "KEY_S"]]),
|
||||
]
|
||||
),
|
||||
get_command_for_shortcut=Mock(side_effect=["", "SAVE_SETTINGS"]),
|
||||
)
|
||||
manager.environment = {
|
||||
"input": {
|
||||
"key_forward": 0,
|
||||
"prev_input": ["KEY_CTRL"],
|
||||
"curr_input": ["KEY_CTRL", "KEY_FENRIR"],
|
||||
},
|
||||
"runtime": {
|
||||
"InputManager": input_manager,
|
||||
"EventManager": event_manager,
|
||||
"VmenuManager": Mock(get_active=Mock(return_value=False)),
|
||||
"DiffReviewManager": Mock(is_active=Mock(return_value=False)),
|
||||
"SpeechHistoryManager": Mock(is_active=Mock(return_value=False)),
|
||||
},
|
||||
}
|
||||
|
||||
manager.detect_shortcut_command()
|
||||
|
||||
assert manager.modifierInput is True
|
||||
assert manager.modifier_prefix_input is False
|
||||
event_manager.put_to_event_queue.assert_not_called()
|
||||
|
||||
manager.environment["input"]["prev_input"] = [
|
||||
"KEY_CTRL",
|
||||
"KEY_FENRIR",
|
||||
]
|
||||
manager.environment["input"]["curr_input"] = [
|
||||
"KEY_CTRL",
|
||||
"KEY_FENRIR",
|
||||
"KEY_S",
|
||||
]
|
||||
manager.detect_shortcut_command()
|
||||
|
||||
event_manager.put_to_event_queue.assert_called_once_with(
|
||||
FenrirEventType.execute_command, "SAVE_SETTINGS"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_action_key_disarms_modifier_prefix():
|
||||
manager = FenrirManager.__new__(FenrirManager)
|
||||
manager.modifierInput = False
|
||||
manager.modifier_prefix_input = True
|
||||
manager.singleKeyCommand = False
|
||||
manager.command = ""
|
||||
input_manager = Mock(
|
||||
is_key_press=Mock(return_value=False),
|
||||
no_key_pressed=Mock(return_value=False),
|
||||
curr_input_has_command_modifier=Mock(return_value=False),
|
||||
curr_input_is_modifier_prefix=Mock(return_value=False),
|
||||
get_curr_shortcut=Mock(return_value=str([1, ["KEY_C", "KEY_CTRL"]])),
|
||||
get_command_for_shortcut=Mock(return_value=""),
|
||||
)
|
||||
manager.environment = {
|
||||
"input": {
|
||||
"key_forward": 0,
|
||||
"prev_input": ["KEY_CTRL"],
|
||||
"curr_input": ["KEY_C", "KEY_CTRL"],
|
||||
},
|
||||
"runtime": {
|
||||
"InputManager": input_manager,
|
||||
"EventManager": Mock(put_to_event_queue=Mock()),
|
||||
"VmenuManager": Mock(get_active=Mock(return_value=False)),
|
||||
"DiffReviewManager": Mock(is_active=Mock(return_value=False)),
|
||||
"SpeechHistoryManager": Mock(is_active=Mock(return_value=False)),
|
||||
},
|
||||
}
|
||||
|
||||
manager.detect_shortcut_command()
|
||||
|
||||
assert manager.modifier_prefix_input is False
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_modifier_prefix_is_not_forwarded_before_chord_is_known():
|
||||
manager, input_manager = create_handle_input_manager(False)
|
||||
|
||||
manager.handle_input(
|
||||
{"data": {"event_name": "KEY_CTRL", "event_state": 1}}
|
||||
)
|
||||
|
||||
input_manager.write_event_buffer.assert_not_called()
|
||||
input_manager.clear_event_buffer.assert_not_called()
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_modifier_prefix_is_forwarded_when_released_unused():
|
||||
manager, input_manager = create_handle_input_manager(True)
|
||||
|
||||
manager.handle_input(
|
||||
{"data": {"event_name": "KEY_CTRL", "event_state": 0}}
|
||||
)
|
||||
|
||||
input_manager.write_event_buffer.assert_called_once_with()
|
||||
assert manager.modifier_prefix_input is False
|
||||
@@ -10,6 +10,7 @@ from fenrirscreenreader.core.fenrirManager import FenrirManager
|
||||
def test_speech_history_plain_key_modal_command_is_dispatched():
|
||||
manager = FenrirManager.__new__(FenrirManager)
|
||||
manager.modifierInput = False
|
||||
manager.modifier_prefix_input = False
|
||||
manager.singleKeyCommand = False
|
||||
manager.command = ""
|
||||
|
||||
@@ -50,6 +51,7 @@ def test_speech_history_plain_key_modal_command_is_dispatched():
|
||||
def test_vmenu_plain_key_modal_command_is_dispatched():
|
||||
manager = FenrirManager.__new__(FenrirManager)
|
||||
manager.modifierInput = False
|
||||
manager.modifier_prefix_input = False
|
||||
manager.singleKeyCommand = False
|
||||
manager.command = ""
|
||||
|
||||
|
||||
@@ -425,3 +425,63 @@ def test_x11_handle_key_event_keeps_event_buffer_for_input_manager():
|
||||
|
||||
assert x11.env["input"]["event_buffer"][0]["event_name"] == "KEY_KP0"
|
||||
event_queue.put.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_x11_fenrir_press_emits_modifiers_from_raw_state_first():
|
||||
x11 = X11Driver()
|
||||
x11.active = True
|
||||
x11.fenrir_keys = {"KEY_KP0"}
|
||||
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=X.ControlMask)
|
||||
x11.keycode_to_key_name = Mock(return_value="KEY_KP0")
|
||||
|
||||
x11.handle_x_event(event, event_queue)
|
||||
|
||||
modifier_event = event_queue.put.call_args_list[0].args[0]
|
||||
fenrir_event = event_queue.put.call_args_list[1].args[0]
|
||||
assert modifier_event["data"]["event_name"] == "KEY_CTRL"
|
||||
assert modifier_event["data"]["event_state"] == 1
|
||||
assert fenrir_event["data"]["event_name"] == "KEY_KP0"
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_x11_fenrir_release_balances_synthesized_modifiers():
|
||||
x11 = X11Driver()
|
||||
x11.active = True
|
||||
x11.fenrir_keys = {"KEY_KP0"}
|
||||
x11.interesting_keys = {"KEY_KP0"}
|
||||
x11.command_key_active = True
|
||||
x11.chord_modifiers = {"KEY_CTRL"}
|
||||
x11.env = {
|
||||
"input": {
|
||||
"curr_input": ["KEY_CTRL", "KEY_FENRIR"],
|
||||
"event_buffer": [],
|
||||
},
|
||||
"runtime": {
|
||||
"InputManager": Mock(convert_event_name=lambda key: key),
|
||||
"DebugManager": Mock(),
|
||||
},
|
||||
}
|
||||
event_queue = Mock()
|
||||
event = Mock(type=X.KeyRelease, detail=90, state=X.ControlMask)
|
||||
x11.keycode_to_key_name = Mock(return_value="KEY_KP0")
|
||||
|
||||
x11.handle_x_event(event, event_queue)
|
||||
|
||||
fenrir_event = event_queue.put.call_args_list[0].args[0]
|
||||
modifier_event = event_queue.put.call_args_list[1].args[0]
|
||||
assert fenrir_event["data"]["event_name"] == "KEY_KP0"
|
||||
assert modifier_event["data"]["event_name"] == "KEY_CTRL"
|
||||
assert modifier_event["data"]["event_state"] == 0
|
||||
|
||||
Reference in New Issue
Block a user