Mi2dRPGamEng/engine/config.py

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, [])