1010
1111from .dom_codes import DomCode
1212from .console import Console , InputGetter
13- from .blessed_keyboard_input import blessed_key_pressed_context
13+ from .blessed_keyboard_input import KeyboardState , blessed_key_pressed_context
1414from .pynput_keyboard_input import pynput_key_pressed_context
1515from .x11_keyboard_input import x11_key_pressed_context
1616
@@ -43,6 +43,10 @@ def get_input_mapping(console: Console) -> dict[DomCode, Console.Input]:
4343 DomCode .ARROW_DOWN : console .Input .DOWN ,
4444 DomCode .ARROW_LEFT : console .Input .LEFT ,
4545 DomCode .ARROW_RIGHT : console .Input .RIGHT ,
46+ DomCode .NUMPAD8 : console .Input .UP ,
47+ DomCode .NUMPAD2 : console .Input .DOWN ,
48+ DomCode .NUMPAD4 : console .Input .LEFT ,
49+ DomCode .NUMPAD6 : console .Input .RIGHT ,
4650 DomCode .US_Z : console .Input .A ,
4751 DomCode .US_X : console .Input .B ,
4852 # WASD controls
@@ -72,31 +76,46 @@ def get_event_mapping(console: Console) -> dict[DomCode, Console.Event]:
7276 }
7377
7478
75- def make_get_input (
76- console : Console ,
77- get_pressed : Callable [[], set [DomCode ]],
78- ) -> InputGetter :
79- current_pressed : set [DomCode ] = set ()
80- input_mapping = get_input_mapping (console )
81- event_mapping = get_event_mapping (console )
82-
83- def get_input () -> set [Console .Input ]:
84- nonlocal current_pressed
85- old_pressed , current_pressed = current_pressed , set (get_pressed ())
86- # Propagate CPR flag from keyboard handler to run loop
87- get_input .cpr_received = getattr (get_pressed , "cpr_received" , False )
88- for event in map (event_mapping .get , current_pressed - old_pressed ):
79+ class GameInputGetter :
80+ """Callable that translates raw key state into console inputs."""
81+
82+ def __init__ (
83+ self ,
84+ console : Console ,
85+ get_pressed : Callable [[], set [DomCode ] | KeyboardState ],
86+ ) -> None :
87+ self ._get_pressed = get_pressed
88+ self ._current_pressed : set [DomCode ] = set ()
89+ self ._input_mapping = get_input_mapping (console )
90+ self ._event_mapping = get_event_mapping (console )
91+ self ._console = console
92+ self .cpr_state = KeyboardState ()
93+
94+ def __call__ (self ) -> set [Console .Input ]:
95+ result = self ._get_pressed ()
96+ if isinstance (result , KeyboardState ):
97+ self .cpr_state .cpr_received = result .cpr_received
98+ new_pressed = set (result .pressed )
99+ else :
100+ self .cpr_state .cpr_received = False
101+ new_pressed = set (result )
102+ old_pressed , self ._current_pressed = self ._current_pressed , new_pressed
103+ for event in map (self ._event_mapping .get , new_pressed - old_pressed ):
89104 if event is None :
90105 continue
91- console .handle_event (event )
106+ self . _console .handle_event (event )
92107 return {
93- input_mapping [keysym ]
94- for keysym in current_pressed
95- if keysym in input_mapping
108+ self . _input_mapping [keysym ]
109+ for keysym in self . _current_pressed
110+ if keysym in self . _input_mapping
96111 }
97112
98- get_input .cpr_received = False
99- return get_input
113+
114+ def make_get_input (
115+ console : Console ,
116+ get_pressed : Callable [[], set [DomCode ] | KeyboardState ],
117+ ) -> GameInputGetter :
118+ return GameInputGetter (console , get_pressed )
100119
101120
102121def _kitty_supported (term : Terminal ) -> bool :
@@ -153,7 +172,7 @@ def console_input_from_keyboard_context(
153172 if xdg_session_type is None :
154173 xdg_session_type = os .environ .get ("XDG_SESSION_TYPE" , "" )
155174 if xdg_session_type != "x11" :
156- raise RuntimeError (MESSAGE_FOR_WAYLAND_USERS )
175+ raise RuntimeError (MESSAGE_SUGGESTING_KITTY_SUPPORT )
157176 with console_input_from_x11_keyboard_context (console , display ) as get_input :
158177 yield get_input
159178 else :
@@ -166,7 +185,7 @@ def key_pressed_context(
166185 term : Terminal ,
167186 display : str | None = None ,
168187 xdg_session_type : str | None = None ,
169- ) -> Iterator [Callable [[], set [DomCode ]]]:
188+ ) -> Iterator [Callable [[], set [DomCode ] | KeyboardState ]]:
170189 if _kitty_supported (term ):
171190 with blessed_key_pressed_context (term ) as get_pressed :
172191 yield get_pressed
@@ -193,7 +212,11 @@ def main() -> None:
193212 with key_pressed_context (term ) as get_pressed :
194213 while True :
195214 # Get codes
196- codes = (x .value for x in get_pressed ())
215+ result = get_pressed ()
216+ pressed = result .pressed if isinstance (
217+ result , KeyboardState
218+ ) else result
219+ codes = (x .value for x in pressed )
197220 # Print pressed key codes
198221 print ("\r " , * codes , flush = True , end = term .clear_eol )
199222 # Tick
0 commit comments