Skip to content

Commit c21d4f8

Browse files
committed
Add new function get_key_state
1 parent e52a594 commit c21d4f8

File tree

3 files changed

+70
-4
lines changed

3 files changed

+70
-4
lines changed

doc/news.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ New Features:
99

1010
* Updated to wrap new function added in SDL_image 2.8.0 (PR #274).
1111
* Updated to wrap new hints added in SDL 2.28.2 and 2.28.5 (PR #274).
12-
12+
* Added a new function :func:`~sdl2.ext.get_key_state` for checking if a given
13+
key is currently down or up independently of the SDL event queue.
1314

1415
Fixed Bugs:
1516

sdl2/ext/input.py

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
1+
from ctypes import c_int, byref
12
from ..stdinc import SDL_TRUE
23
from ..keyboard import (
34
SDL_GetKeyFromName, SDL_GetKeyName, SDL_StartTextInput, SDL_StopTextInput,
4-
SDL_IsTextInputActive,
5+
SDL_IsTextInputActive, SDL_GetKeyboardState, SDL_GetScancodeFromName,
56
)
7+
from ..scancode import SDL_SCANCODE_UNKNOWN, SDL_NUM_SCANCODES
68
from ..keycode import KMOD_ALT, KMOD_CTRL, KMOD_GUI, KMOD_SHIFT
79
from ..mouse import (
810
SDL_BUTTON_LEFT, SDL_BUTTON_RIGHT, SDL_BUTTON_MIDDLE,
911
SDL_BUTTON_X1, SDL_BUTTON_X2,
1012
)
1113
from ..events import (
1214
SDL_KEYDOWN, SDL_KEYUP, SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP,
13-
SDL_TEXTINPUT,
15+
SDL_TEXTINPUT, SDL_PumpEvents,
1416
)
1517

1618
from .compat import _is_text, byteify, isiterable
1719

1820
__all__ = [
19-
"key_pressed", "mouse_clicked", "get_clicks", "get_text_input",
21+
"key_pressed", "get_key_state", "mouse_clicked", "get_clicks", "get_text_input",
2022
"start_text_input", "stop_text_input", "text_input_enabled",
2123
]
2224

@@ -197,6 +199,53 @@ def key_pressed(events, key=None, mod=None, released=False):
197199
return pressed
198200

199201

202+
def get_key_state(key):
203+
"""Checks the current state (pressed or released) of a given keyboard key.
204+
205+
Unlike :func:`key_pressed`, which checks an SDL event queue for key down
206+
and key up events, this function checks the current state of a given key
207+
directly. This can be helpful in certain situations, such as ignoring
208+
repeated keydown events from a held key::
209+
210+
key_released = False
211+
while True:
212+
q = pump(True)
213+
if not key_released:
214+
# Ignore repeated keydown events from held down space bar by
215+
# requiring key be 'up' on at least one loop before a response
216+
# can be registered
217+
if get_key_state('space') == 0:
218+
key_released = True
219+
else:
220+
if key_pressed('space', queue=q):
221+
break
222+
223+
Args:
224+
key (int or str): The name (or SDL scancode) of the key to check.
225+
226+
Returns:
227+
int: 1 if the key is currently pressed, otherwise 0.
228+
229+
"""
230+
# If key given as string, get the corresponding scancode
231+
if _is_text(key):
232+
scancode = SDL_GetScancodeFromName(byteify(key))
233+
if scancode == SDL_SCANCODE_UNKNOWN:
234+
e = "'{0}' is not a valid name for an SDL scancode."
235+
raise ValueError(e.format(key))
236+
else:
237+
if key <= 0 or key >= SDL_NUM_SCANCODES:
238+
e = "'{0}' is not a valid SDL scancode constant."
239+
raise ValueError(e.format(key))
240+
scancode = key
241+
242+
# Check for and return the current key state
243+
SDL_PumpEvents()
244+
numkeys = c_int(0)
245+
keys = SDL_GetKeyboardState(byref(numkeys))
246+
return keys[scancode]
247+
248+
200249
def mouse_clicked(events, button=None, released=False):
201250
"""Checks for any mouse clicks in a given event queue.
202251

sdl2/test/sdl2ext_input_test.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# -*- coding: utf-8 -*-
22
import pytest
3+
from ..scancode import SDL_SCANCODE_SPACE, SDL_SCANCODE_A
34
from ..keycode import SDLK_a, KMOD_LSHIFT, KMOD_RCTRL
45
from ..mouse import SDL_BUTTON_LEFT
56
from ..events import (
@@ -113,6 +114,21 @@ def test_key_pressed():
113114
sdl2ext.key_pressed(q, key=-100)
114115

115116

117+
def test_get_key_state():
118+
# NOTE: Can't fake key status for tests, so just test API
119+
assert sdl2ext.get_key_state('space') in (0, 1)
120+
assert sdl2ext.get_key_state('a') in (0, 1)
121+
assert sdl2ext.get_key_state(SDL_SCANCODE_SPACE) in (0, 1)
122+
assert sdl2ext.get_key_state(SDL_SCANCODE_A) in (0, 1)
123+
# Test exception on bad key names/scancodes
124+
with pytest.raises(ValueError):
125+
sdl2ext.get_key_state('nope')
126+
with pytest.raises(ValueError):
127+
sdl2ext.get_key_state(0)
128+
with pytest.raises(ValueError):
129+
sdl2ext.get_key_state(1000)
130+
131+
116132
def test_mouse_clicked():
117133
# Test with empty queue
118134
assert sdl2ext.mouse_clicked([]) == False

0 commit comments

Comments
 (0)