From 6aaedb813fa11ba0679c3051bc2eb28646b9506c Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 30 Aug 2025 16:53:58 -0700 Subject: Update to SDL3 --- src/contrib/SDL-3.2.20/test/checkkeys.c | 531 ++++++++++++++++++++++++++++++++ 1 file changed, 531 insertions(+) create mode 100644 src/contrib/SDL-3.2.20/test/checkkeys.c (limited to 'src/contrib/SDL-3.2.20/test/checkkeys.c') 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 @@ +/* + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely. +*/ + +/* Simple program: Loop, watching keystrokes + Note that you need to call SDL_PollEvent() or SDL_WaitEvent() to + pump the event loop and catch keystrokes. +*/ + +#include +#include +#include + +#ifdef SDL_PLATFORM_EMSCRIPTEN +#include +#endif + +#define TEXT_WINDOW_OFFSET_X 2.0f +#define TEXT_WINDOW_OFFSET_Y (2.0f + FONT_LINE_HEIGHT) + +#define CURSOR_BLINK_INTERVAL_MS 500 + +typedef struct +{ + SDLTest_TextWindow *textwindow; + char *edit_text; + int edit_cursor; + int edit_length; +} TextWindowState; + +static SDLTest_CommonState *state; +static TextWindowState *windowstates; +static bool escape_pressed; +static bool cursor_visible; +static Uint64 last_cursor_change; +static int done; + +static TextWindowState *GetTextWindowStateForWindowID(SDL_WindowID id) +{ + int i; + + for (i = 0; i < state->num_windows; ++i) { + if (id == SDL_GetWindowID(state->windows[i])) { + return &windowstates[i]; + } + } + return NULL; +} + +static SDLTest_TextWindow *GetTextWindowForWindowID(SDL_WindowID id) +{ + TextWindowState *windowstate = GetTextWindowStateForWindowID(id); + if (windowstate) { + return windowstate->textwindow; + } + return NULL; +} + +static void UpdateTextWindowInputRect(SDL_WindowID id) +{ + int i; + + for (i = 0; i < state->num_windows; ++i) { + if (id == SDL_GetWindowID(state->windows[i])) { + SDLTest_TextWindow *textwindow = windowstates[i].textwindow; + int w, h; + SDL_Rect rect; + int cursor = 0; + int current = textwindow->current; + const char *current_line = textwindow->lines[current]; + + SDL_GetWindowSize(state->windows[i], &w, &h); + + if (current_line) { + cursor = (int)SDL_utf8strlen(current_line) * FONT_CHARACTER_SIZE; + } + + rect.x = (int)TEXT_WINDOW_OFFSET_X; + rect.y = (int)TEXT_WINDOW_OFFSET_Y + current * FONT_LINE_HEIGHT; + rect.w = (int)(w - (2 * TEXT_WINDOW_OFFSET_X)); + rect.h = FONT_CHARACTER_SIZE; + SDL_SetTextInputArea(state->windows[i], &rect, cursor); + return; + } + } +} + +static void print_string(char **text, size_t *maxlen, const char *fmt, ...) +{ + int len; + va_list ap; + + va_start(ap, fmt); + len = SDL_vsnprintf(*text, *maxlen, fmt, ap); + if (len > 0) { + *text += len; + if (((size_t)len) < *maxlen) { + *maxlen -= (size_t)len; + } else { + *maxlen = 0; + } + } + va_end(ap); +} + +static void print_modifiers(char **text, size_t *maxlen, SDL_Keymod mod) +{ + print_string(text, maxlen, " modifiers:"); + if (mod == SDL_KMOD_NONE) { + print_string(text, maxlen, " (none)"); + return; + } + if ((mod & SDL_KMOD_SHIFT) == SDL_KMOD_SHIFT) { + print_string(text, maxlen, " SHIFT"); + } else { + if (mod & SDL_KMOD_LSHIFT) { + print_string(text, maxlen, " LSHIFT"); + } + if (mod & SDL_KMOD_RSHIFT) { + print_string(text, maxlen, " RSHIFT"); + } + } + if ((mod & SDL_KMOD_CTRL) == SDL_KMOD_CTRL) { + print_string(text, maxlen, " CTRL"); + } else { + if (mod & SDL_KMOD_LCTRL) { + print_string(text, maxlen, " LCTRL"); + } + if (mod & SDL_KMOD_RCTRL) { + print_string(text, maxlen, " RCTRL"); + } + } + if ((mod & SDL_KMOD_ALT) == SDL_KMOD_ALT) { + print_string(text, maxlen, " ALT"); + } else { + if (mod & SDL_KMOD_LALT) { + print_string(text, maxlen, " LALT"); + } + if (mod & SDL_KMOD_RALT) { + print_string(text, maxlen, " RALT"); + } + } + if ((mod & SDL_KMOD_GUI) == SDL_KMOD_GUI) { + print_string(text, maxlen, " GUI"); + } else { + if (mod & SDL_KMOD_LGUI) { + print_string(text, maxlen, " LGUI"); + } + if (mod & SDL_KMOD_RGUI) { + print_string(text, maxlen, " RGUI"); + } + } + if (mod & SDL_KMOD_NUM) { + print_string(text, maxlen, " NUM"); + } + if (mod & SDL_KMOD_CAPS) { + print_string(text, maxlen, " CAPS"); + } + if (mod & SDL_KMOD_MODE) { + print_string(text, maxlen, " MODE"); + } + if (mod & SDL_KMOD_LEVEL5) { + print_string(text, maxlen, " LEVEL5"); + } + if (mod & SDL_KMOD_SCROLL) { + print_string(text, maxlen, " SCROLL"); + } +} + +static void PrintModifierState(void) +{ + char message[512]; + char *spot; + size_t left; + + spot = message; + left = sizeof(message); + + print_modifiers(&spot, &left, SDL_GetModState()); + SDL_Log("Initial state:%s", message); +} + +static void PrintKey(SDL_KeyboardEvent *event) +{ + char message[512]; + char *spot; + size_t left; + + spot = message; + left = sizeof(message); + + /* Print the keycode, name and state */ + if (event->key) { + print_string(&spot, &left, + "Key %s: raw 0x%.2x, scancode %d = %s, keycode 0x%08X = %s ", + event->down ? "pressed " : "released", + event->raw, + event->scancode, + event->scancode == SDL_SCANCODE_UNKNOWN ? "UNKNOWN" : SDL_GetScancodeName(event->scancode), + event->key, SDL_GetKeyName(event->key)); + } else { + print_string(&spot, &left, + "Unknown Key (raw 0x%.2x, scancode %d = %s) %s ", + event->raw, + event->scancode, + event->scancode == SDL_SCANCODE_UNKNOWN ? "UNKNOWN" : SDL_GetScancodeName(event->scancode), + event->down ? "pressed " : "released"); + } + print_modifiers(&spot, &left, event->mod); + if (event->repeat) { + print_string(&spot, &left, " (repeat)"); + } + SDL_Log("%s", message); +} + +static void PrintText(const char *eventtype, const char *text) +{ + const char *spot; + char expanded[1024]; + + expanded[0] = '\0'; + for (spot = text; *spot; ++spot) { + size_t length = SDL_strlen(expanded); + (void)SDL_snprintf(expanded + length, sizeof(expanded) - length, "\\x%.2x", (unsigned char)*spot); + } + SDL_Log("%s Text (%s): \"%s%s\"", eventtype, expanded, *text == '"' ? "\\" : "", text); +} + +static void CountKeysDown(void) +{ + int i, count = 0, max_keys = 0; + const bool *keystate = SDL_GetKeyboardState(&max_keys); + + for (i = 0; i < max_keys; ++i) { + if (keystate[i]) { + ++count; + } + } + SDL_Log("Keys down: %d", count); +} + +static void DrawCursor(int i) +{ + SDL_FRect rect; + TextWindowState *windowstate = &windowstates[i]; + SDLTest_TextWindow *textwindow = windowstate->textwindow; + int current = textwindow->current; + const char *current_line = textwindow->lines[current]; + + rect.x = TEXT_WINDOW_OFFSET_X; + if (current_line) { + rect.x += SDL_utf8strlen(current_line) * FONT_CHARACTER_SIZE; + } + if (windowstate->edit_cursor > 0) { + rect.x += (float)windowstate->edit_cursor * FONT_CHARACTER_SIZE; + } + rect.y = TEXT_WINDOW_OFFSET_Y + current * FONT_LINE_HEIGHT; + rect.w = FONT_CHARACTER_SIZE * 0.75f; + rect.h = (float)FONT_CHARACTER_SIZE; + + SDL_SetRenderDrawColor(state->renderers[i], 0xAA, 0xAA, 0xAA, 255); + SDL_RenderFillRect(state->renderers[i], &rect); +} + +static void DrawEditText(int i) +{ + SDL_FRect rect; + TextWindowState *windowstate = &windowstates[i]; + SDLTest_TextWindow *textwindow = windowstate->textwindow; + int current = textwindow->current; + const char *current_line = textwindow->lines[current]; + + if (windowstate->edit_text == NULL) { + return; + } + + /* Draw the highlight under the selected text */ + if (windowstate->edit_length > 0) { + rect.x = TEXT_WINDOW_OFFSET_X; + if (current_line) { + rect.x += SDL_utf8strlen(current_line) * FONT_CHARACTER_SIZE; + } + if (windowstate->edit_cursor > 0) { + rect.x += (float)windowstate->edit_cursor * FONT_CHARACTER_SIZE; + } + rect.y = TEXT_WINDOW_OFFSET_Y + current * FONT_LINE_HEIGHT; + rect.w = (float)windowstate->edit_length * FONT_CHARACTER_SIZE; + rect.h = (float)FONT_CHARACTER_SIZE; + + SDL_SetRenderDrawColor(state->renderers[i], 0xAA, 0xAA, 0xAA, 255); + SDL_RenderFillRect(state->renderers[i], &rect); + } + + /* Draw the edit text */ + rect.x = TEXT_WINDOW_OFFSET_X; + if (current_line) { + rect.x += SDL_utf8strlen(current_line) * FONT_CHARACTER_SIZE; + } + rect.y = TEXT_WINDOW_OFFSET_Y + current * FONT_LINE_HEIGHT; + SDL_SetRenderDrawColor(state->renderers[i], 255, 255, 0, 255); + SDLTest_DrawString(state->renderers[i], rect.x, rect.y, windowstate->edit_text); +} + +static void loop(void) +{ + SDL_Event event; + Uint64 now; + int i; + char line[1024]; + + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_EVENT_KEY_DOWN: + case SDL_EVENT_KEY_UP: + PrintKey(&event.key); + if (event.type == SDL_EVENT_KEY_DOWN) { + switch (event.key.key) { + case SDLK_BACKSPACE: + SDLTest_TextWindowAddText(GetTextWindowForWindowID(event.key.windowID), "\b"); + UpdateTextWindowInputRect(event.key.windowID); + break; + case SDLK_RETURN: + SDLTest_TextWindowAddText(GetTextWindowForWindowID(event.key.windowID), "\n"); + UpdateTextWindowInputRect(event.key.windowID); + break; + default: + break; + } + if (event.key.key == SDLK_ESCAPE) { + /* Pressing escape twice will stop the application */ + if (escape_pressed) { + done = 1; + } else { + escape_pressed = true; + } + } else { + escape_pressed = true; + } + } + CountKeysDown(); + break; + case SDL_EVENT_TEXT_EDITING: + { + TextWindowState *windowstate = GetTextWindowStateForWindowID(event.edit.windowID); + if (windowstate->edit_text) { + SDL_free(windowstate->edit_text); + windowstate->edit_text = NULL; + } + if (event.edit.text && *event.edit.text) { + windowstate->edit_text = SDL_strdup(event.edit.text); + } + windowstate->edit_cursor = event.edit.start; + windowstate->edit_length = event.edit.length; + + SDL_snprintf(line, sizeof(line), "EDIT %" SDL_PRIs32 ":%" SDL_PRIs32, event.edit.start, event.edit.length); + PrintText(line, event.edit.text); + break; + } + case SDL_EVENT_TEXT_INPUT: + PrintText("INPUT", event.text.text); + SDLTest_TextWindowAddText(GetTextWindowForWindowID(event.text.windowID), "%s", event.text.text); + UpdateTextWindowInputRect(event.text.windowID); + break; + case SDL_EVENT_FINGER_DOWN: + { + SDL_Window *window = SDL_GetWindowFromEvent(&event); + if (SDL_TextInputActive(window)) { + SDL_Log("Stopping text input for window %" SDL_PRIu32, event.tfinger.windowID); + SDL_StopTextInput(window); + } else { + SDL_Log("Starting text input for window %" SDL_PRIu32, event.tfinger.windowID); + SDL_StartTextInput(window); + } + break; + } + case SDL_EVENT_MOUSE_BUTTON_DOWN: + if (event.button.button == SDL_BUTTON_RIGHT) { + SDL_Window *window = SDL_GetWindowFromEvent(&event); + if (SDL_TextInputActive(window)) { + SDL_Log("Stopping text input for window %" SDL_PRIu32, event.button.windowID); + SDL_StopTextInput(window); + } else { + SDL_Log("Starting text input for window %" SDL_PRIu32, event.button.windowID); + SDL_StartTextInput(window); + } + } + break; + case SDL_EVENT_KEYMAP_CHANGED: + SDL_Log("Keymap changed!"); + break; + case SDL_EVENT_QUIT: + done = 1; + break; + default: + break; + } + } + + now = SDL_GetTicks(); + for (i = 0; i < state->num_windows; i++) { + char caption[1024]; + + /* Clear the window */ + SDL_SetRenderDrawColor(state->renderers[i], 0, 0, 0, 255); + SDL_RenderClear(state->renderers[i]); + + /* Draw the text */ + SDL_SetRenderDrawColor(state->renderers[i], 255, 255, 255, 255); + SDL_snprintf(caption, sizeof(caption), "Text input %s (click right mouse button to toggle)\n", SDL_TextInputActive(state->windows[i]) ? "enabled" : "disabled"); + SDLTest_DrawString(state->renderers[i], TEXT_WINDOW_OFFSET_X, TEXT_WINDOW_OFFSET_X, caption); + SDLTest_TextWindowDisplay(windowstates[i].textwindow, state->renderers[i]); + + /* Draw the cursor */ + if ((now - last_cursor_change) >= CURSOR_BLINK_INTERVAL_MS) { + cursor_visible = !cursor_visible; + last_cursor_change = now; + } + if (cursor_visible) { + DrawCursor(i); + } + + /* Draw the composition text */ + DrawEditText(i); + + SDL_RenderPresent(state->renderers[i]); + } + + /* Slow down framerate */ + SDL_Delay(100); + +#ifdef SDL_PLATFORM_EMSCRIPTEN + if (done) { + emscripten_cancel_main_loop(); + } +#endif +} + +int main(int argc, char *argv[]) +{ + int i; + + SDL_SetHint(SDL_HINT_WINDOWS_RAW_KEYBOARD, "1"); + + /* Initialize test framework */ + state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO); + if (!state) { + return 1; + } + state->window_title = "CheckKeys Test"; + + /* Parse commandline */ + if (!SDLTest_CommonDefaultArgs(state, argc, argv)) { + return 1; + } + + /* Disable mouse emulation */ + SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0"); + + /* Initialize SDL */ + if (!SDLTest_CommonInit(state)) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError()); + return 1; + } + + windowstates = (TextWindowState *)SDL_calloc(state->num_windows, sizeof(*windowstates)); + if (!windowstates) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't allocate text windows: %s", SDL_GetError()); + goto done; + } + + for (i = 0; i < state->num_windows; ++i) { + int w, h; + SDL_FRect rect; + + SDL_GetWindowSize(state->windows[i], &w, &h); + rect.x = TEXT_WINDOW_OFFSET_X; + rect.y = TEXT_WINDOW_OFFSET_Y; + rect.w = w - (2 * TEXT_WINDOW_OFFSET_X); + rect.h = h - TEXT_WINDOW_OFFSET_Y; + windowstates[i].textwindow = SDLTest_TextWindowCreate(rect.x, rect.y, rect.w, rect.h); + } + +#ifdef SDL_PLATFORM_IOS + { + /* Creating the context creates the view, which we need to show keyboard */ + for (i = 0; i < state->num_windows; i++) { + SDL_GL_CreateContext(state->windows[i]); + } + } +#endif + + for (i = 0; i < state->num_windows; ++i) { + UpdateTextWindowInputRect(SDL_GetWindowID(state->windows[i])); + + SDL_StartTextInput(state->windows[i]); + } + + /* Print initial state */ + SDL_PumpEvents(); + PrintModifierState(); + + /* Watch keystrokes */ + done = 0; + +#ifdef SDL_PLATFORM_EMSCRIPTEN + emscripten_set_main_loop(loop, 0, 1); +#else + while (!done) { + loop(); + } +#endif + +done: + if (windowstates) { + for (i = 0; i < state->num_windows; ++i) { + SDLTest_TextWindowDestroy(windowstates[i].textwindow); + } + SDL_free(windowstates); + } + SDLTest_CleanupTextDrawing(); + SDLTest_CommonQuit(state); + return 0; +} -- cgit v1.2.3