Skip to content

Circumflex key is not directly sent with compat sdl2 version #465

@serpilliere

Description

@serpilliere

Hi!

I have a minimalist program that uses SDL2 to create a window, and display key down event.
This program work fine with SDL2 and SDL3 library, but has a strange behavior with sdl2-compat, with the circumflex key.
I am using an azerty keyboard (https://en.wikipedia.org/wiki/AZERTY)

In SDL2, with "legacy" version (2.30.0 2.30.8, 2.32.0, 2.32.4) if I push any keyboard key (including circumflex), the event key down is directly displayed (I push A then ^):

version SDL Version: 2.32.4 (Compiled: 2.32.54)
Event 97
Event 1073741824

If I do this on SDL3, same behavior, everything is ok, including the circumflex key. (I push A then ^)

We compiled against SDL version 3.2.10 ...
But we are linking against SDL version 3.2.10.
Press keys on the keyboard. Press ESC or close the window to quit.
Key pressed: key = 97
Key pressed: key = 1073741871

But If I use sdl2-comptat, the circumflex key event is not send.

version SDL Version: 2.30.54 (Compiled: 2.32.54)
Event 97

and the lastest conpat version:

version SDL Version: 2.32.54 (Compiled: 2.32.54)
Event 97

Am I missing something? Is there a HINT that has changed this behavior?

Here it is in sdl2:

#include <SDL2/SDL.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>

#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define MAX_TEXT_LENGTH 1024

int main(int argc, char *argv[]) {
    SDL_version compiled;
    SDL_version linked;
    SDL_GetVersion(&linked);
    SDL_VERSION(&compiled);

    if (SDL_Init(SDL_INIT_VIDEO) != 0) {
        printf("SDL_Init Error: %s\n", SDL_GetError());
        return 1;
    }

    char sdlVersionText[128];
    snprintf(sdlVersionText, sizeof(sdlVersionText), "SDL Version: %d.%d.%d (Compiled: %d.%d.%d)",
             linked.major, linked.minor, linked.patch,
             compiled.major, compiled.minor, compiled.patch);
    printf("version %s\n", sdlVersionText);

    SDL_Window *win = SDL_CreateWindow("Key Display", 100, 100, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN);
    if (!win) {
        printf("SDL_CreateWindow Error: %s\n", SDL_GetError());
        SDL_Quit();
        return 1;
    }

    SDL_Renderer *ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    if (!ren) {
        printf("SDL_CreateRenderer Error: %s\n", SDL_GetError());
        SDL_DestroyWindow(win);
        SDL_Quit();
        return 1;
    }

    bool quit = false;
    SDL_Event e;

    while (!quit) {
        while (SDL_PollEvent(&e)) {
            if (e.type == SDL_QUIT) {
                quit = true;
            } else if (e.type == SDL_KEYDOWN) {
                printf("Event %d\n", e.key.keysym.sym);
            }
        }

        SDL_RenderClear(ren);
        SDL_RenderPresent(ren);
    }

    SDL_DestroyRenderer(ren);
    SDL_DestroyWindow(win);
    SDL_Quit();
    return 0;
}

The sdl3 code:

#include <SDL3/SDL.h>
#include <stdio.h>
#include <stdbool.h>

int main(int argc, char *argv[]) {
        const int compiled = SDL_VERSION;  /* hardcoded number from SDL headers */
        const int linked = SDL_GetVersion();  /* reported by linked SDL library */

        SDL_Log("We compiled against SDL version %d.%d.%d ...\n",
                SDL_VERSIONNUM_MAJOR(compiled),
                SDL_VERSIONNUM_MINOR(compiled),
                SDL_VERSIONNUM_MICRO(compiled));

        SDL_Log("But we are linking against SDL version %d.%d.%d.\n",
                SDL_VERSIONNUM_MAJOR(linked),
                SDL_VERSIONNUM_MINOR(linked),
                SDL_VERSIONNUM_MICRO(linked));

        if (SDL_Init(SDL_INIT_VIDEO) == 0) {
                SDL_Log("SDL_Init Error: %s\n", SDL_GetError());
                return 1;
        }

        SDL_Window *window = SDL_CreateWindow(
                                              "SDL3 KeySym Example",
                                              800, 600,
                                              SDL_WINDOW_OPENGL
                                              );

        if (!window) {
                SDL_Log("SDL_CreateWindow Error: %s\n", SDL_GetError());
                SDL_Quit();
                return 1;
        }

        bool running = true;
        SDL_Event event;

        printf("Press keys on the keyboard. Press ESC or close the window to quit.\n");

        while (running) {
                while (SDL_PollEvent(&event)) {
                        switch (event.type) {
                                case SDL_EVENT_QUIT:
                                        running = false;
                                        break;
                                case SDL_EVENT_KEY_DOWN:
                                        printf("Key pressed: key = %d\n",
                                               event.key.key);
                                        break;
                                default:
                                        break;
                        }
                }

                SDL_Delay(10); // reduce CPU usage
        }

        SDL_DestroyWindow(window);
        SDL_Quit();
        return 0;
}

Activity

cgutman

cgutman commented on Apr 20, 2025

@cgutman
Contributor

This change is due to a combination of SDL3's improved X11 IME support and the fact that SDL2 (but not SDL3) enables text input (read: IME input) by default.

Because the circumflex key is a dead key used to compose accented characters, this is not delivered to the app as a normal key press. It is consumed by the IME which then waits for the next character to accent. You will get a SDL_EVENT_TEXT_INPUT for the accented character once you press another letter on the keyboard.

For SDL2 apps, you should call SDL_StopTextInput() after initializing the video subsystem if you want to receive all keypresses without any IME interference. On SDL3, text input is disabled by default, so this is why you get events for dead keys by default.

Now with all that said, the Wayland driver on SDL3 actually sends both the SDL_EVENT_KEY_DOWN and SDL_EVENT_TEXT_INPUT events in this scenario, which I think is the safer option (and what SDL2 did). I created a PR to change the X11 driver to do the same.

serpilliere

serpilliere commented on Apr 21, 2025

@serpilliere
Author

Hi @cgutman,
I just tested the SDL_StopTextInput, and everything is ok: Thanks for this!

version SDL Version: 2.32.54 (Compiled: 2.32.54)
Event 97
Event 1073741871

Thank you for the fix to mimic wayland @cgutman !
Can I close the issue or wait for the PR merge?

cgutman

cgutman commented on Apr 22, 2025

@cgutman
Contributor

Let's keep this open until we decide if we want to change SDL3's X11 behavior to match Wayland and SDL2.

added this to the SDL 3.2.12 milestone on Apr 22, 2025
modified the milestones: SDL 3.2.12, SDL 3.2.14 on May 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      Participants

      @slouken@cgutman@serpilliere

      Issue actions

        Circumflex key is not directly sent with compat sdl2 version · Issue #465 · libsdl-org/sdl2-compat