Skip to content

Commit c1a9fca

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 c1a9fca

File tree

5 files changed

+130
-0
lines changed

5 files changed

+130
-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: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
from numpy.typing import ArrayLike, NDArray
2525

2626
__all__ = (
27+
"Capitalization",
2728
"FlashOperation",
29+
"TextInputType",
2830
"Window",
2931
"WindowFlags",
3032
"get_grabbed_window",
@@ -89,6 +91,56 @@ class FlashOperation(enum.IntEnum):
8991
"""Flash until focus is gained."""
9092

9193

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

@@ -133,6 +185,9 @@ def __eq__(self, other: object) -> bool:
133185
return NotImplemented
134186
return bool(self.p == other.p)
135187

188+
def __hash__(self) -> int:
189+
return hash(self.p)
190+
136191
def _as_property_pointer(self) -> Any: # noqa: ANN401
137192
return self.p
138193

@@ -369,6 +424,67 @@ def relative_mouse_mode(self) -> bool:
369424
def relative_mouse_mode(self, enable: bool, /) -> None:
370425
_check(lib.SDL_SetWindowRelativeMouseMode(self.p, enable))
371426

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

373489
def new_window( # noqa: PLR0913
374490
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)