Source code for simvx.core.input.map
"""InputMap — singleton registry of action -> bindings."""
from __future__ import annotations
import logging
from typing import ClassVar
from .enums import JoyButton, Key, MouseButton
from .events import InputBinding
log = logging.getLogger(__name__)
[docs]
class InputMap:
"""Maps action names to physical inputs. Class-level singleton."""
_actions: ClassVar[dict[str, list[InputBinding]]] = {}
[docs]
@classmethod
def add_action(cls, name: str, bindings: list[InputBinding | Key | MouseButton | JoyButton] | None = None):
"""Register a named action with optional initial bindings.
Convenience: passing bare Key/MouseButton/JoyButton values auto-wraps them.
"""
if name in cls._actions:
log.warning("Input action %r overwritten (had %s bindings)", name, len(cls._actions[name]))
else:
cls._actions[name] = []
log.debug("InputMap.add_action(%r, %s)", name, bindings)
if bindings:
cls._actions[name].extend(cls._to_binding(b) for b in bindings)
[docs]
@classmethod
def remove_action(cls, name: str):
"""Remove a named action and all its bindings."""
cls._actions.pop(name, None)
[docs]
@classmethod
def add_binding(cls, name: str, binding: InputBinding | Key | MouseButton | JoyButton):
"""Add a binding to an existing action. Creates the action if it does not exist."""
if name not in cls._actions:
cls._actions[name] = []
cls._actions[name].append(cls._to_binding(binding))
[docs]
@classmethod
def remove_binding(cls, name: str, binding: InputBinding):
"""Remove a specific binding from an action."""
if name in cls._actions:
try:
cls._actions[name].remove(binding)
except ValueError:
pass
[docs]
@classmethod
def get_bindings(cls, name: str) -> list[InputBinding]:
"""Return bindings for an action (empty list if unknown)."""
return cls._actions.get(name, [])
[docs]
@classmethod
def has_action(cls, name: str) -> bool:
"""Check if an action is registered."""
return name in cls._actions
[docs]
@classmethod
def get_actions(cls) -> list[str]:
"""Return all registered action names."""
return list(cls._actions)
@classmethod
def _to_binding(cls, b: InputBinding | Key | MouseButton | JoyButton) -> InputBinding:
if isinstance(b, InputBinding):
return b
if isinstance(b, Key):
return InputBinding(key=b)
if isinstance(b, MouseButton):
return InputBinding(mouse_button=b)
if isinstance(b, JoyButton):
return InputBinding(joy_button=b)
raise TypeError(f"Cannot create InputBinding from {type(b).__name__}")