67 lines
2.2 KiB
Python
67 lines
2.2 KiB
Python
from __future__ import annotations
|
|
|
|
import configparser
|
|
from pathlib import Path
|
|
|
|
DEFAULT_KEYBINDINGS: dict[str, list[str]] = {
|
|
"move_up": ["w", "ArrowUp"],
|
|
"move_down": ["s", "ArrowDown"],
|
|
"move_left": ["a", "ArrowLeft"],
|
|
"move_right": ["d", "ArrowRight"],
|
|
"leap": ["space"],
|
|
"block": ["b"],
|
|
"activate_right_hand": ["mouse_left"],
|
|
"activate_left_hand": ["mouse_right"],
|
|
"activate_right_hand_2": ["shift+mouse_left"],
|
|
"activate_left_hand_2": ["shift+mouse_right"],
|
|
"select_ability_1": ["1"],
|
|
"select_ability_2": ["2"],
|
|
"select_ability_3": ["3"],
|
|
"select_ability_4": ["4"],
|
|
"select_ability_5": ["5"],
|
|
"select_ability_6": ["6"],
|
|
"select_ability_7": ["7"],
|
|
"select_ability_8": ["8"],
|
|
"select_ability_9": ["9"],
|
|
"select_ability_0": ["0"],
|
|
}
|
|
|
|
# Human-friendly config names for keys that don't have a printable representation.
|
|
_KEY_ALIASES = {"space": " "}
|
|
|
|
|
|
def _normalize(key: str) -> str:
|
|
return _KEY_ALIASES.get(key, key)
|
|
|
|
|
|
class KeyBindings:
|
|
"""Action -> list of keys, loaded from an editable .conf file (arrays, so several keys
|
|
can share one action). Falls back to DEFAULT_KEYBINDINGS for anything the file omits.
|
|
"""
|
|
|
|
def __init__(self, bindings: dict[str, list[str]]):
|
|
self.bindings = bindings
|
|
self._action_by_key: dict[str, str] = {}
|
|
for action, keys in bindings.items():
|
|
for key in keys:
|
|
self._action_by_key[_normalize(key)] = action
|
|
|
|
@classmethod
|
|
def load(cls, path: Path) -> "KeyBindings":
|
|
bindings = {action: list(keys) for action, keys in DEFAULT_KEYBINDINGS.items()}
|
|
if path.exists():
|
|
parser = configparser.ConfigParser()
|
|
parser.read(path)
|
|
for section in parser.sections():
|
|
for action, raw in parser.items(section):
|
|
keys = [k.strip() for k in raw.split(",") if k.strip()]
|
|
if keys:
|
|
bindings[action] = keys
|
|
return cls(bindings)
|
|
|
|
def action_for_key(self, key: str) -> str | None:
|
|
return self._action_by_key.get(key)
|
|
|
|
def keys_for_action(self, action: str) -> list[str]:
|
|
return self.bindings.get(action, [])
|