Skip to content

Commit ca58a26

Browse files
committed
Add SDL Window text input methods
Text input events were missing since version 19.0.0 and had to be added again.
1 parent bebbb9a commit ca58a26

File tree

5 files changed

+128
-0
lines changed

5 files changed

+128
-0
lines changed

.vscode/settings.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"AUDIOREWIND",
4646
"AUDIOSTOP",
4747
"autoclass",
48+
"AUTOCORRECT",
4849
"autofunction",
4950
"autogenerated",
5051
"automodule",
@@ -200,6 +201,7 @@
200201
"imageio",
201202
"imread",
202203
"INCOL",
204+
"INPUTTYPE",
203205
"INROW",
204206
"interactable",
205207
"intersphinx",

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ This project adheres to [Semantic Versioning](https://semver.org/) since version
66

77
## [Unreleased]
88

9+
### Added
10+
11+
- Added text input support to `tcod.sdl.video.Window` which was missing since the SDL3 update.
12+
After creating a context use `assert context.sdl_window` or `if context.sdl_window:` to verify that an SDL window exists then use `context.sdl_window.start_text_input` to enable text input events.
13+
Keep in mind that this can open an on-screen keyboard.
14+
915
## [19.0.2] - 2025-07-11
1016

1117
Resolve wheel deployment issue.

examples/eventget.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ def main() -> None:
2222
joysticks: set[tcod.sdl.joystick.Joystick] = set()
2323

2424
with tcod.context.new(width=WIDTH, height=HEIGHT) as context:
25+
if context.sdl_window:
26+
context.sdl_window.start_text_input()
2527
console = context.new_console()
2628
while True:
2729
# Display all event items.

tcod/sdl/video.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,56 @@ class FlashOperation(enum.IntEnum):
8989
"""Flash until focus is gained."""
9090

9191

92+
class TextInputType(enum.IntEnum):
93+
"""SDL input types for text input.
94+
95+
.. seealso::
96+
:any:`Window.start_text_input`
97+
https://wiki.libsdl.org/SDL3/SDL_TextInputType
98+
99+
.. versionadded:: Unreleased
100+
"""
101+
102+
TEXT = lib.SDL_TEXTINPUT_TYPE_TEXT
103+
"""The input is text."""
104+
TEXT_NAME = lib.SDL_TEXTINPUT_TYPE_TEXT_NAME
105+
"""The input is a person's name."""
106+
TEXT_EMAIL = lib.SDL_TEXTINPUT_TYPE_TEXT_EMAIL
107+
"""The input is an e-mail address."""
108+
TEXT_USERNAME = lib.SDL_TEXTINPUT_TYPE_TEXT_USERNAME
109+
"""The input is a username."""
110+
TEXT_PASSWORD_HIDDEN = lib.SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN
111+
"""The input is a secure password that is hidden."""
112+
TEXT_PASSWORD_VISIBLE = lib.SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_VISIBLE
113+
"""The input is a secure password that is visible."""
114+
NUMBER = lib.SDL_TEXTINPUT_TYPE_NUMBER
115+
"""The input is a number."""
116+
NUMBER_PASSWORD_HIDDEN = lib.SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN
117+
"""The input is a secure PIN that is hidden."""
118+
NUMBER_PASSWORD_VISIBLE = lib.SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_VISIBLE
119+
"""The input is a secure PIN that is visible."""
120+
121+
122+
class Capitalization(enum.IntEnum):
123+
"""Text capitalization for text input.
124+
125+
.. seealso::
126+
:any:`Window.start_text_input`
127+
https://wiki.libsdl.org/SDL3/SDL_Capitalization
128+
129+
.. versionadded:: Unreleased
130+
"""
131+
132+
NONE = lib.SDL_CAPITALIZE_NONE
133+
"""No auto-capitalization will be done."""
134+
SENTENCES = lib.SDL_CAPITALIZE_SENTENCES
135+
"""The first letter of sentences will be capitalized."""
136+
WORDS = lib.SDL_CAPITALIZE_WORDS
137+
"""The first letter of words will be capitalized."""
138+
LETTERS = lib.SDL_CAPITALIZE_LETTERS
139+
"""All letters will be capitalized."""
140+
141+
92142
class _TempSurface:
93143
"""Holds a temporary surface derived from a NumPy array."""
94144

@@ -133,6 +183,9 @@ def __eq__(self, other: object) -> bool:
133183
return NotImplemented
134184
return bool(self.p == other.p)
135185

186+
def __hash__(self) -> int:
187+
return hash(self.p)
188+
136189
def _as_property_pointer(self) -> Any: # noqa: ANN401
137190
return self.p
138191

@@ -369,6 +422,67 @@ def relative_mouse_mode(self) -> bool:
369422
def relative_mouse_mode(self, enable: bool, /) -> None:
370423
_check(lib.SDL_SetWindowRelativeMouseMode(self.p, enable))
371424

425+
def start_text_input(
426+
self,
427+
*,
428+
type: TextInputType = TextInputType.TEXT, # noqa: A002
429+
capitalization: Capitalization | None = None,
430+
autocorrect: bool = True,
431+
multiline: bool | None = None,
432+
android_type: int | None = None,
433+
) -> None:
434+
"""Start receiving text input events supporting Unicode. This may open an on-screen keyboard.
435+
436+
Args:
437+
type: Type of text being inputted, see :any:`TextInputType`
438+
capitalization: Capitalization hint, default is based on `type` given, see :any:`Capitalization`.
439+
autocorrect: Enable auto completion and auto correction.
440+
multiline: Allow multiple lines of text.
441+
android_type: Input type for Android, see SDL docs.
442+
443+
.. seealso::
444+
:any:`stop_text_input`
445+
:any:`set_text_input_area`
446+
https://wiki.libsdl.org/SDL3/SDL_StartTextInputWithProperties
447+
448+
.. versionadded:: Unreleased
449+
"""
450+
props = Properties()
451+
props[("SDL_PROP_TEXTINPUT_TYPE_NUMBER", int)] = int(type)
452+
if capitalization is not None:
453+
props[("SDL_PROP_TEXTINPUT_CAPITALIZATION_NUMBER", int)] = int(capitalization)
454+
props[("SDL_PROP_TEXTINPUT_AUTOCORRECT_BOOLEAN", bool)] = autocorrect
455+
if multiline is not None:
456+
props[("SDL_PROP_TEXTINPUT_MULTILINE_BOOLEAN", bool)] = multiline
457+
if android_type is not None:
458+
props[("SDL_PROP_TEXTINPUT_ANDROID_INPUTTYPE_NUMBER", int)] = int(android_type)
459+
_check(lib.SDL_StartTextInputWithProperties(self.p, props.p))
460+
461+
def set_text_input_area(self, rect: tuple[int, int, int, int], cursor: int) -> None:
462+
"""Assign the area used for entering Unicode text input.
463+
464+
Args:
465+
rect: `(x, y, width, height)` rectangle used for text input
466+
cursor: Cursor X position, relative to `rect[0]`
467+
468+
.. seealso::
469+
:any:`start_text_input`
470+
https://wiki.libsdl.org/SDL3/SDL_SetTextInputArea
471+
472+
.. versionadded:: Unreleased
473+
"""
474+
_check(lib.SDL_SetTextInputArea(self.p, (rect,), cursor))
475+
476+
def stop_text_input(self) -> None:
477+
"""Stop receiving text events for this window and close relevant on-screen keyboards.
478+
479+
.. seealso::
480+
:any:`start_text_input`
481+
482+
.. versionadded:: Unreleased
483+
"""
484+
_check(lib.SDL_StopTextInput(self.p))
485+
372486

373487
def new_window( # noqa: PLR0913
374488
width: int,

tests/test_sdl.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ def test_sdl_window(uses_window: None) -> None:
3838
window.opacity = window.opacity
3939
window.grab = window.grab
4040

41+
window.start_text_input(capitalization=tcod.sdl.video.Capitalization.NONE, multiline=False)
42+
window.set_text_input_area((0, 0, 8, 8), 0)
43+
window.stop_text_input()
44+
4145

4246
def test_sdl_window_bad_types() -> None:
4347
with pytest.raises(TypeError):

0 commit comments

Comments
 (0)