Source code for mini_arcade_core.runtime.input.input_adapter
"""
Module providing runtime adapters for window and scene management.
"""
from __future__ import annotations
from dataclasses import dataclass, field
from mini_arcade_core.backend.events import Event, EventType
from mini_arcade_core.backend.keys import Key
from mini_arcade_core.runtime.input.input_port import InputPort
from mini_arcade_core.runtime.input_frame import ButtonState, InputFrame
[docs]
@dataclass
class InputAdapter(InputPort):
"""Adapter for processing input events."""
_down: set[Key] = field(default_factory=set)
_buttons_down: set[str] = field(default_factory=set)
_axes: dict[str, float] = field(default_factory=dict)
_mouse_pos: tuple[int, int] = (0, 0)
# pylint: disable=too-many-locals,too-many-branches
[docs]
def build(
self, events: list[Event], frame_index: int, dt: float
) -> InputFrame:
pressed: set[Key] = set()
released: set[Key] = set()
buttons_pressed: set[str] = set()
buttons_released: set[str] = set()
quit_req = False
mouse_dx = 0
mouse_dy = 0
text_parts: list[str] = []
for ev in events:
if ev.type == EventType.QUIT:
quit_req = True
elif ev.type == EventType.KEYDOWN and ev.key is not None:
if ev.key not in self._down:
pressed.add(ev.key)
self._down.add(ev.key)
elif ev.type == EventType.KEYUP and ev.key is not None:
if ev.key in self._down:
self._down.remove(ev.key)
released.add(ev.key)
elif ev.type == EventType.ACTIONDOWN and ev.action:
if ev.action not in self._buttons_down:
buttons_pressed.add(ev.action)
self._buttons_down.add(ev.action)
elif ev.type == EventType.ACTIONUP and ev.action:
if ev.action in self._buttons_down:
self._buttons_down.remove(ev.action)
buttons_released.add(ev.action)
elif ev.type == EventType.AXISMOTION and ev.axis:
self._axes[ev.axis] = float(ev.value or 0.0)
elif ev.type == EventType.MOUSEMOTION:
x = int(ev.x) if ev.x is not None else self._mouse_pos[0]
y = int(ev.y) if ev.y is not None else self._mouse_pos[1]
self._mouse_pos = (x, y)
mouse_dx += int(ev.dx or 0)
mouse_dy += int(ev.dy or 0)
elif ev.type in (
EventType.MOUSEBUTTONDOWN,
EventType.MOUSEBUTTONUP,
):
if ev.x is not None and ev.y is not None:
self._mouse_pos = (int(ev.x), int(ev.y))
elif ev.type == EventType.TEXTINPUT and ev.text:
text_parts.append(str(ev.text))
buttons: dict[str, ButtonState] = {}
all_buttons = self._buttons_down | buttons_pressed | buttons_released
for name in all_buttons:
buttons[name] = ButtonState(
down=name in self._buttons_down,
pressed=name in buttons_pressed,
released=name in buttons_released,
)
return InputFrame(
frame_index=frame_index,
dt=dt,
keys_down=frozenset(self._down),
keys_pressed=frozenset(pressed),
keys_released=frozenset(released),
buttons=buttons,
axes=dict(self._axes),
mouse_pos=self._mouse_pos,
mouse_delta=(mouse_dx, mouse_dy),
text_input="".join(text_parts),
quit=quit_req,
)