summaryrefslogtreecommitdiff
path: root/src/contrib/SDL-3.2.20/test/checkkeys.c
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-08-30 16:53:58 -0700
committer3gg <3gg@shellblade.net>2025-08-30 16:53:58 -0700
commit6aaedb813fa11ba0679c3051bc2eb28646b9506c (patch)
tree34acbfc9840e02cb4753e6306ea7ce978bf8b58e /src/contrib/SDL-3.2.20/test/checkkeys.c
parent8f228ade99dd3d4c8da9b78ade1815c9adf85c8f (diff)
Update to SDL3
Diffstat (limited to 'src/contrib/SDL-3.2.20/test/checkkeys.c')
-rw-r--r--src/contrib/SDL-3.2.20/test/checkkeys.c531
1 files changed, 531 insertions, 0 deletions
diff --git a/src/contrib/SDL-3.2.20/test/checkkeys.c b/src/contrib/SDL-3.2.20/test/checkkeys.c
new file mode 100644
index 0000000..ab7df8e
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/test/checkkeys.c
@@ -0,0 +1,531 @@
1/*
2 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely.
11*/
12
13/* Simple program: Loop, watching keystrokes
14 Note that you need to call SDL_PollEvent() or SDL_WaitEvent() to
15 pump the event loop and catch keystrokes.
16*/
17
18#include <SDL3/SDL.h>
19#include <SDL3/SDL_main.h>
20#include <SDL3/SDL_test.h>
21
22#ifdef SDL_PLATFORM_EMSCRIPTEN
23#include <emscripten/emscripten.h>
24#endif
25
26#define TEXT_WINDOW_OFFSET_X 2.0f
27#define TEXT_WINDOW_OFFSET_Y (2.0f + FONT_LINE_HEIGHT)
28
29#define CURSOR_BLINK_INTERVAL_MS 500
30
31typedef struct
32{
33 SDLTest_TextWindow *textwindow;
34 char *edit_text;
35 int edit_cursor;
36 int edit_length;
37} TextWindowState;
38
39static SDLTest_CommonState *state;
40static TextWindowState *windowstates;
41static bool escape_pressed;
42static bool cursor_visible;
43static Uint64 last_cursor_change;
44static int done;
45
46static TextWindowState *GetTextWindowStateForWindowID(SDL_WindowID id)
47{
48 int i;
49
50 for (i = 0; i < state->num_windows; ++i) {
51 if (id == SDL_GetWindowID(state->windows[i])) {
52 return &windowstates[i];
53 }
54 }
55 return NULL;
56}
57
58static SDLTest_TextWindow *GetTextWindowForWindowID(SDL_WindowID id)
59{
60 TextWindowState *windowstate = GetTextWindowStateForWindowID(id);
61 if (windowstate) {
62 return windowstate->textwindow;
63 }
64 return NULL;
65}
66
67static void UpdateTextWindowInputRect(SDL_WindowID id)
68{
69 int i;
70
71 for (i = 0; i < state->num_windows; ++i) {
72 if (id == SDL_GetWindowID(state->windows[i])) {
73 SDLTest_TextWindow *textwindow = windowstates[i].textwindow;
74 int w, h;
75 SDL_Rect rect;
76 int cursor = 0;
77 int current = textwindow->current;
78 const char *current_line = textwindow->lines[current];
79
80 SDL_GetWindowSize(state->windows[i], &w, &h);
81
82 if (current_line) {
83 cursor = (int)SDL_utf8strlen(current_line) * FONT_CHARACTER_SIZE;
84 }
85
86 rect.x = (int)TEXT_WINDOW_OFFSET_X;
87 rect.y = (int)TEXT_WINDOW_OFFSET_Y + current * FONT_LINE_HEIGHT;
88 rect.w = (int)(w - (2 * TEXT_WINDOW_OFFSET_X));
89 rect.h = FONT_CHARACTER_SIZE;
90 SDL_SetTextInputArea(state->windows[i], &rect, cursor);
91 return;
92 }
93 }
94}
95
96static void print_string(char **text, size_t *maxlen, const char *fmt, ...)
97{
98 int len;
99 va_list ap;
100
101 va_start(ap, fmt);
102 len = SDL_vsnprintf(*text, *maxlen, fmt, ap);
103 if (len > 0) {
104 *text += len;
105 if (((size_t)len) < *maxlen) {
106 *maxlen -= (size_t)len;
107 } else {
108 *maxlen = 0;
109 }
110 }
111 va_end(ap);
112}
113
114static void print_modifiers(char **text, size_t *maxlen, SDL_Keymod mod)
115{
116 print_string(text, maxlen, " modifiers:");
117 if (mod == SDL_KMOD_NONE) {
118 print_string(text, maxlen, " (none)");
119 return;
120 }
121 if ((mod & SDL_KMOD_SHIFT) == SDL_KMOD_SHIFT) {
122 print_string(text, maxlen, " SHIFT");
123 } else {
124 if (mod & SDL_KMOD_LSHIFT) {
125 print_string(text, maxlen, " LSHIFT");
126 }
127 if (mod & SDL_KMOD_RSHIFT) {
128 print_string(text, maxlen, " RSHIFT");
129 }
130 }
131 if ((mod & SDL_KMOD_CTRL) == SDL_KMOD_CTRL) {
132 print_string(text, maxlen, " CTRL");
133 } else {
134 if (mod & SDL_KMOD_LCTRL) {
135 print_string(text, maxlen, " LCTRL");
136 }
137 if (mod & SDL_KMOD_RCTRL) {
138 print_string(text, maxlen, " RCTRL");
139 }
140 }
141 if ((mod & SDL_KMOD_ALT) == SDL_KMOD_ALT) {
142 print_string(text, maxlen, " ALT");
143 } else {
144 if (mod & SDL_KMOD_LALT) {
145 print_string(text, maxlen, " LALT");
146 }
147 if (mod & SDL_KMOD_RALT) {
148 print_string(text, maxlen, " RALT");
149 }
150 }
151 if ((mod & SDL_KMOD_GUI) == SDL_KMOD_GUI) {
152 print_string(text, maxlen, " GUI");
153 } else {
154 if (mod & SDL_KMOD_LGUI) {
155 print_string(text, maxlen, " LGUI");
156 }
157 if (mod & SDL_KMOD_RGUI) {
158 print_string(text, maxlen, " RGUI");
159 }
160 }
161 if (mod & SDL_KMOD_NUM) {
162 print_string(text, maxlen, " NUM");
163 }
164 if (mod & SDL_KMOD_CAPS) {
165 print_string(text, maxlen, " CAPS");
166 }
167 if (mod & SDL_KMOD_MODE) {
168 print_string(text, maxlen, " MODE");
169 }
170 if (mod & SDL_KMOD_LEVEL5) {
171 print_string(text, maxlen, " LEVEL5");
172 }
173 if (mod & SDL_KMOD_SCROLL) {
174 print_string(text, maxlen, " SCROLL");
175 }
176}
177
178static void PrintModifierState(void)
179{
180 char message[512];
181 char *spot;
182 size_t left;
183
184 spot = message;
185 left = sizeof(message);
186
187 print_modifiers(&spot, &left, SDL_GetModState());
188 SDL_Log("Initial state:%s", message);
189}
190
191static void PrintKey(SDL_KeyboardEvent *event)
192{
193 char message[512];
194 char *spot;
195 size_t left;
196
197 spot = message;
198 left = sizeof(message);
199
200 /* Print the keycode, name and state */
201 if (event->key) {
202 print_string(&spot, &left,
203 "Key %s: raw 0x%.2x, scancode %d = %s, keycode 0x%08X = %s ",
204 event->down ? "pressed " : "released",
205 event->raw,
206 event->scancode,
207 event->scancode == SDL_SCANCODE_UNKNOWN ? "UNKNOWN" : SDL_GetScancodeName(event->scancode),
208 event->key, SDL_GetKeyName(event->key));
209 } else {
210 print_string(&spot, &left,
211 "Unknown Key (raw 0x%.2x, scancode %d = %s) %s ",
212 event->raw,
213 event->scancode,
214 event->scancode == SDL_SCANCODE_UNKNOWN ? "UNKNOWN" : SDL_GetScancodeName(event->scancode),
215 event->down ? "pressed " : "released");
216 }
217 print_modifiers(&spot, &left, event->mod);
218 if (event->repeat) {
219 print_string(&spot, &left, " (repeat)");
220 }
221 SDL_Log("%s", message);
222}
223
224static void PrintText(const char *eventtype, const char *text)
225{
226 const char *spot;
227 char expanded[1024];
228
229 expanded[0] = '\0';
230 for (spot = text; *spot; ++spot) {
231 size_t length = SDL_strlen(expanded);
232 (void)SDL_snprintf(expanded + length, sizeof(expanded) - length, "\\x%.2x", (unsigned char)*spot);
233 }
234 SDL_Log("%s Text (%s): \"%s%s\"", eventtype, expanded, *text == '"' ? "\\" : "", text);
235}
236
237static void CountKeysDown(void)
238{
239 int i, count = 0, max_keys = 0;
240 const bool *keystate = SDL_GetKeyboardState(&max_keys);
241
242 for (i = 0; i < max_keys; ++i) {
243 if (keystate[i]) {
244 ++count;
245 }
246 }
247 SDL_Log("Keys down: %d", count);
248}
249
250static void DrawCursor(int i)
251{
252 SDL_FRect rect;
253 TextWindowState *windowstate = &windowstates[i];
254 SDLTest_TextWindow *textwindow = windowstate->textwindow;
255 int current = textwindow->current;
256 const char *current_line = textwindow->lines[current];
257
258 rect.x = TEXT_WINDOW_OFFSET_X;
259 if (current_line) {
260 rect.x += SDL_utf8strlen(current_line) * FONT_CHARACTER_SIZE;
261 }
262 if (windowstate->edit_cursor > 0) {
263 rect.x += (float)windowstate->edit_cursor * FONT_CHARACTER_SIZE;
264 }
265 rect.y = TEXT_WINDOW_OFFSET_Y + current * FONT_LINE_HEIGHT;
266 rect.w = FONT_CHARACTER_SIZE * 0.75f;
267 rect.h = (float)FONT_CHARACTER_SIZE;
268
269 SDL_SetRenderDrawColor(state->renderers[i], 0xAA, 0xAA, 0xAA, 255);
270 SDL_RenderFillRect(state->renderers[i], &rect);
271}
272
273static void DrawEditText(int i)
274{
275 SDL_FRect rect;
276 TextWindowState *windowstate = &windowstates[i];
277 SDLTest_TextWindow *textwindow = windowstate->textwindow;
278 int current = textwindow->current;
279 const char *current_line = textwindow->lines[current];
280
281 if (windowstate->edit_text == NULL) {
282 return;
283 }
284
285 /* Draw the highlight under the selected text */
286 if (windowstate->edit_length > 0) {
287 rect.x = TEXT_WINDOW_OFFSET_X;
288 if (current_line) {
289 rect.x += SDL_utf8strlen(current_line) * FONT_CHARACTER_SIZE;
290 }
291 if (windowstate->edit_cursor > 0) {
292 rect.x += (float)windowstate->edit_cursor * FONT_CHARACTER_SIZE;
293 }
294 rect.y = TEXT_WINDOW_OFFSET_Y + current * FONT_LINE_HEIGHT;
295 rect.w = (float)windowstate->edit_length * FONT_CHARACTER_SIZE;
296 rect.h = (float)FONT_CHARACTER_SIZE;
297
298 SDL_SetRenderDrawColor(state->renderers[i], 0xAA, 0xAA, 0xAA, 255);
299 SDL_RenderFillRect(state->renderers[i], &rect);
300 }
301
302 /* Draw the edit text */
303 rect.x = TEXT_WINDOW_OFFSET_X;
304 if (current_line) {
305 rect.x += SDL_utf8strlen(current_line) * FONT_CHARACTER_SIZE;
306 }
307 rect.y = TEXT_WINDOW_OFFSET_Y + current * FONT_LINE_HEIGHT;
308 SDL_SetRenderDrawColor(state->renderers[i], 255, 255, 0, 255);
309 SDLTest_DrawString(state->renderers[i], rect.x, rect.y, windowstate->edit_text);
310}
311
312static void loop(void)
313{
314 SDL_Event event;
315 Uint64 now;
316 int i;
317 char line[1024];
318
319 while (SDL_PollEvent(&event)) {
320 switch (event.type) {
321 case SDL_EVENT_KEY_DOWN:
322 case SDL_EVENT_KEY_UP:
323 PrintKey(&event.key);
324 if (event.type == SDL_EVENT_KEY_DOWN) {
325 switch (event.key.key) {
326 case SDLK_BACKSPACE:
327 SDLTest_TextWindowAddText(GetTextWindowForWindowID(event.key.windowID), "\b");
328 UpdateTextWindowInputRect(event.key.windowID);
329 break;
330 case SDLK_RETURN:
331 SDLTest_TextWindowAddText(GetTextWindowForWindowID(event.key.windowID), "\n");
332 UpdateTextWindowInputRect(event.key.windowID);
333 break;
334 default:
335 break;
336 }
337 if (event.key.key == SDLK_ESCAPE) {
338 /* Pressing escape twice will stop the application */
339 if (escape_pressed) {
340 done = 1;
341 } else {
342 escape_pressed = true;
343 }
344 } else {
345 escape_pressed = true;
346 }
347 }
348 CountKeysDown();
349 break;
350 case SDL_EVENT_TEXT_EDITING:
351 {
352 TextWindowState *windowstate = GetTextWindowStateForWindowID(event.edit.windowID);
353 if (windowstate->edit_text) {
354 SDL_free(windowstate->edit_text);
355 windowstate->edit_text = NULL;
356 }
357 if (event.edit.text && *event.edit.text) {
358 windowstate->edit_text = SDL_strdup(event.edit.text);
359 }
360 windowstate->edit_cursor = event.edit.start;
361 windowstate->edit_length = event.edit.length;
362
363 SDL_snprintf(line, sizeof(line), "EDIT %" SDL_PRIs32 ":%" SDL_PRIs32, event.edit.start, event.edit.length);
364 PrintText(line, event.edit.text);
365 break;
366 }
367 case SDL_EVENT_TEXT_INPUT:
368 PrintText("INPUT", event.text.text);
369 SDLTest_TextWindowAddText(GetTextWindowForWindowID(event.text.windowID), "%s", event.text.text);
370 UpdateTextWindowInputRect(event.text.windowID);
371 break;
372 case SDL_EVENT_FINGER_DOWN:
373 {
374 SDL_Window *window = SDL_GetWindowFromEvent(&event);
375 if (SDL_TextInputActive(window)) {
376 SDL_Log("Stopping text input for window %" SDL_PRIu32, event.tfinger.windowID);
377 SDL_StopTextInput(window);
378 } else {
379 SDL_Log("Starting text input for window %" SDL_PRIu32, event.tfinger.windowID);
380 SDL_StartTextInput(window);
381 }
382 break;
383 }
384 case SDL_EVENT_MOUSE_BUTTON_DOWN:
385 if (event.button.button == SDL_BUTTON_RIGHT) {
386 SDL_Window *window = SDL_GetWindowFromEvent(&event);
387 if (SDL_TextInputActive(window)) {
388 SDL_Log("Stopping text input for window %" SDL_PRIu32, event.button.windowID);
389 SDL_StopTextInput(window);
390 } else {
391 SDL_Log("Starting text input for window %" SDL_PRIu32, event.button.windowID);
392 SDL_StartTextInput(window);
393 }
394 }
395 break;
396 case SDL_EVENT_KEYMAP_CHANGED:
397 SDL_Log("Keymap changed!");
398 break;
399 case SDL_EVENT_QUIT:
400 done = 1;
401 break;
402 default:
403 break;
404 }
405 }
406
407 now = SDL_GetTicks();
408 for (i = 0; i < state->num_windows; i++) {
409 char caption[1024];
410
411 /* Clear the window */
412 SDL_SetRenderDrawColor(state->renderers[i], 0, 0, 0, 255);
413 SDL_RenderClear(state->renderers[i]);
414
415 /* Draw the text */
416 SDL_SetRenderDrawColor(state->renderers[i], 255, 255, 255, 255);
417 SDL_snprintf(caption, sizeof(caption), "Text input %s (click right mouse button to toggle)\n", SDL_TextInputActive(state->windows[i]) ? "enabled" : "disabled");
418 SDLTest_DrawString(state->renderers[i], TEXT_WINDOW_OFFSET_X, TEXT_WINDOW_OFFSET_X, caption);
419 SDLTest_TextWindowDisplay(windowstates[i].textwindow, state->renderers[i]);
420
421 /* Draw the cursor */
422 if ((now - last_cursor_change) >= CURSOR_BLINK_INTERVAL_MS) {
423 cursor_visible = !cursor_visible;
424 last_cursor_change = now;
425 }
426 if (cursor_visible) {
427 DrawCursor(i);
428 }
429
430 /* Draw the composition text */
431 DrawEditText(i);
432
433 SDL_RenderPresent(state->renderers[i]);
434 }
435
436 /* Slow down framerate */
437 SDL_Delay(100);
438
439#ifdef SDL_PLATFORM_EMSCRIPTEN
440 if (done) {
441 emscripten_cancel_main_loop();
442 }
443#endif
444}
445
446int main(int argc, char *argv[])
447{
448 int i;
449
450 SDL_SetHint(SDL_HINT_WINDOWS_RAW_KEYBOARD, "1");
451
452 /* Initialize test framework */
453 state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
454 if (!state) {
455 return 1;
456 }
457 state->window_title = "CheckKeys Test";
458
459 /* Parse commandline */
460 if (!SDLTest_CommonDefaultArgs(state, argc, argv)) {
461 return 1;
462 }
463
464 /* Disable mouse emulation */
465 SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
466
467 /* Initialize SDL */
468 if (!SDLTest_CommonInit(state)) {
469 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError());
470 return 1;
471 }
472
473 windowstates = (TextWindowState *)SDL_calloc(state->num_windows, sizeof(*windowstates));
474 if (!windowstates) {
475 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't allocate text windows: %s", SDL_GetError());
476 goto done;
477 }
478
479 for (i = 0; i < state->num_windows; ++i) {
480 int w, h;
481 SDL_FRect rect;
482
483 SDL_GetWindowSize(state->windows[i], &w, &h);
484 rect.x = TEXT_WINDOW_OFFSET_X;
485 rect.y = TEXT_WINDOW_OFFSET_Y;
486 rect.w = w - (2 * TEXT_WINDOW_OFFSET_X);
487 rect.h = h - TEXT_WINDOW_OFFSET_Y;
488 windowstates[i].textwindow = SDLTest_TextWindowCreate(rect.x, rect.y, rect.w, rect.h);
489 }
490
491#ifdef SDL_PLATFORM_IOS
492 {
493 /* Creating the context creates the view, which we need to show keyboard */
494 for (i = 0; i < state->num_windows; i++) {
495 SDL_GL_CreateContext(state->windows[i]);
496 }
497 }
498#endif
499
500 for (i = 0; i < state->num_windows; ++i) {
501 UpdateTextWindowInputRect(SDL_GetWindowID(state->windows[i]));
502
503 SDL_StartTextInput(state->windows[i]);
504 }
505
506 /* Print initial state */
507 SDL_PumpEvents();
508 PrintModifierState();
509
510 /* Watch keystrokes */
511 done = 0;
512
513#ifdef SDL_PLATFORM_EMSCRIPTEN
514 emscripten_set_main_loop(loop, 0, 1);
515#else
516 while (!done) {
517 loop();
518 }
519#endif
520
521done:
522 if (windowstates) {
523 for (i = 0; i < state->num_windows; ++i) {
524 SDLTest_TextWindowDestroy(windowstates[i].textwindow);
525 }
526 SDL_free(windowstates);
527 }
528 SDLTest_CleanupTextDrawing();
529 SDLTest_CommonQuit(state);
530 return 0;
531}