Search code examples
keyboard-eventssdl-2

How to correctly handle control-key combinations in SDL2


In my SDL 2.0 based application, I would like to handle both Control + and Control =.

I understand that I could handle the SDL_KEYDOWN event and look for the SDLK_EQUALS keycode in combination with KEYMODE_CTRL. And even check for KEYMOD_SHIFT' to distinguish between+and=`. However, this is not portable and breaks on keyboards where those symbols are mapped to different keys.

Another thing I have tried is to enable SDL_StartTextInput() and then listen to SDL_TEXTINPUT events. However that only works for printable characters. It ignores control sequences completely.

What is the correct the way to do this? I see SDL 1.2 actually had a unicode field in the SDL_Keysym structure. That would definitely make this a lot easier for me. Does anyone know why that was removed and what the equivalent in SDL 2.0 would be?


Solution

  • Here is an example how you can get unicode input as SDL_TEXTINPUT but the rest as SDL_KEYDOWN:

    #include "SDL.h"
    #include <stdio.h>
    
    int main(int argc, char *argv[]) {
        int done = 0;
        SDL_Init(SDL_INIT_VIDEO);
        SDL_Window *w = SDL_CreateWindow("foo", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
                640, 480, 0);
    
        int lctrl = 0, rctrl = 0;
    
        SDL_StartTextInput();
        while (!done) {
            SDL_Event event;
            while(SDL_PollEvent(&event)) {
                switch (event.type) {
                case SDL_QUIT:
                    done = 1;
                    break;
                case SDL_TEXTINPUT: {
                    int ctrl_state = lctrl || rctrl;
                    printf("%s, ctrl %s\n", event.text.text, (ctrl_state) ? "pressed" : "released");
                } break;
                case SDL_KEYDOWN:
                    if(event.key.keysym.sym == SDLK_RCTRL) { rctrl = 1; }
                    else if(event.key.keysym.sym == SDLK_LCTRL) { lctrl = 1; }
                    break;
                case SDL_KEYUP:
                    if(event.key.keysym.sym == SDLK_RCTRL) { rctrl = 0; }
                    else if(event.key.keysym.sym == SDLK_LCTRL) { lctrl = 0; }
                    break;
                }
            }
            SDL_UpdateWindowSurface(w);
        }
    
        SDL_Quit();
    
        return 0;
    }
    

    To simplify things, it ignores SDL_TEXTEDITING, which may (or not) be what you want. Also SDL_GetKeyboardState can be used instead of manually processing events and accumulating modifier keys flags, with the same result.