Atlas - checkkeys.c
Home / ext / SDL / test Lines: 3 | Size: 16496 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 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 /* This is not necessary for text input handling, we just 451 * want to verify that input works with raw keyboard enabled. 452 */ 453 SDL_SetHint(SDL_HINT_WINDOWS_RAW_KEYBOARD, "1"); 454 455 /* Initialize test framework */ 456 state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO); 457 if (!state) { 458 return 1; 459 } 460 state->window_title = "CheckKeys Test"; 461 462 /* Parse commandline */ 463 if (!SDLTest_CommonDefaultArgs(state, argc, argv)) { 464 return 1; 465 } 466 467 /* Disable mouse emulation */ 468 SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0"); 469 470 /* Initialize SDL */ 471 if (!SDLTest_CommonInit(state)) { 472 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError()); 473 return 1; 474 } 475 476 windowstates = (TextWindowState *)SDL_calloc(state->num_windows, sizeof(*windowstates)); 477 if (!windowstates) { 478 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't allocate text windows: %s", SDL_GetError()); 479 goto done; 480 } 481 482 for (i = 0; i < state->num_windows; ++i) { 483 int w, h; 484 SDL_FRect rect; 485 486 SDL_GetWindowSize(state->windows[i], &w, &h); 487 rect.x = TEXT_WINDOW_OFFSET_X; 488 rect.y = TEXT_WINDOW_OFFSET_Y; 489 rect.w = w - (2 * TEXT_WINDOW_OFFSET_X); 490 rect.h = h - TEXT_WINDOW_OFFSET_Y; 491 windowstates[i].textwindow = SDLTest_TextWindowCreate(rect.x, rect.y, rect.w, rect.h); 492 } 493 494#ifdef SDL_PLATFORM_IOS 495 { 496 /* Creating the context creates the view, which we need to show keyboard */ 497 for (i = 0; i < state->num_windows; i++) { 498 SDL_GL_CreateContext(state->windows[i]); 499 } 500 } 501#endif 502 503 for (i = 0; i < state->num_windows; ++i) { 504 UpdateTextWindowInputRect(SDL_GetWindowID(state->windows[i])); 505 506 SDL_StartTextInput(state->windows[i]); 507 } 508 509 /* Print initial state */ 510 SDL_PumpEvents(); 511 PrintModifierState(); 512 513 /* Watch keystrokes */ 514 done = 0; 515 516#ifdef SDL_PLATFORM_EMSCRIPTEN 517 emscripten_set_main_loop(loop, 0, 1); 518#else 519 while (!done) { 520 loop(); 521 } 522#endif 523 524done: 525 if (windowstates) { 526 for (i = 0; i < state->num_windows; ++i) { 527 SDLTest_TextWindowDestroy(windowstates[i].textwindow); 528 } 529 SDL_free(windowstates); 530 } 531 SDLTest_CleanupTextDrawing(); 532 SDLTest_CommonQuit(state); 533 return 0; 534} 535[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.