feat(actions): implement ActionMapper config-driven gesture→action lookup
This commit is contained in:
parent
51a22cbe47
commit
5af689389e
2 changed files with 48 additions and 0 deletions
20
merlin/actions/mapper.py
Normal file
20
merlin/actions/mapper.py
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
"""ActionMapper — translates gesture event names to action names via config."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from merlin.config import MerlinConfig
|
||||||
|
|
||||||
|
|
||||||
|
class ActionMapper:
|
||||||
|
def __init__(self, config: MerlinConfig) -> None:
|
||||||
|
self._mappings = dict(config.mappings)
|
||||||
|
|
||||||
|
def map(self, gesture: str) -> Optional[str]:
|
||||||
|
"""Return the action name for a gesture, or None if unmapped."""
|
||||||
|
return self._mappings.get(gesture)
|
||||||
|
|
||||||
|
def reload(self, config: MerlinConfig) -> None:
|
||||||
|
"""Replace mappings from a new config (e.g. after user edits in UI)."""
|
||||||
|
self._mappings = dict(config.mappings)
|
||||||
28
tests/test_actions/test_mapper.py
Normal file
28
tests/test_actions/test_mapper.py
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
from merlin.actions.mapper import ActionMapper
|
||||||
|
from merlin.config import MerlinConfig
|
||||||
|
|
||||||
|
|
||||||
|
def test_maps_known_gesture():
|
||||||
|
config = MerlinConfig()
|
||||||
|
mapper = ActionMapper(config)
|
||||||
|
assert mapper.map("left_blink") == "left_click"
|
||||||
|
|
||||||
|
|
||||||
|
def test_returns_none_for_unknown_gesture():
|
||||||
|
config = MerlinConfig()
|
||||||
|
mapper = ActionMapper(config)
|
||||||
|
assert mapper.map("nonexistent_gesture") is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_custom_mapping_overrides_default():
|
||||||
|
config = MerlinConfig(mappings={"left_blink": "key_enter"})
|
||||||
|
mapper = ActionMapper(config)
|
||||||
|
assert mapper.map("left_blink") == "key_enter"
|
||||||
|
|
||||||
|
|
||||||
|
def test_reload_picks_up_new_config():
|
||||||
|
config = MerlinConfig()
|
||||||
|
mapper = ActionMapper(config)
|
||||||
|
config.mappings["head_nod"] = "double_click"
|
||||||
|
mapper.reload(config)
|
||||||
|
assert mapper.map("head_nod") == "double_click"
|
||||||
Loading…
Reference in a new issue