Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SDL2 wayland SDL_KEYUP/SDL_KEYDOWN input mapping code possibly confused by changing key maps [major issue on Librem 5/PinePhone] #4142

Closed
ell1e opened this issue Mar 1, 2021 · 14 comments · Fixed by #4303

Comments

@ell1e
Copy link
Contributor

ell1e commented Mar 1, 2021

When using SDL2 with SDL_VIDEODRIVER=wayland with the common Linux phone desktop Phosh with it's common on-screen keyboard squeekboard, all the SDL_KEYUP/SDL_KEYDOWN events will have very wrong values for what keys the event supposedly maps to.

It was suggested on the Squeekboard issue tracker that this might actually be either a bug, or shortcoming on the SDL2 side, since squeekboard basically switches key maps out a lot which may not be something SDL2's code is tested to handle: https://source.puri.sm/Librem5/squeekboard/-/issues/218

Would it be possible to maybe look into this? Is this a scenario that is at least supposed to work, or is SDL2 currently not equipped at all to deal with live switching keymaps under Wayland on a conceptual level?

Steps to reproduce:

  1. Compile this as ./testapp:
#include <SDL2/SDL.h>
#include <signal.h>

volatile _Atomic int sigterm_received = 0;
volatile _Atomic int sigint_received = 0;

void handle_sigterm(int signum) {
    sigterm_received = 1;
}

void handle_sigint(int signum) {
    sigint_received = 1;
}

int main(int argc, const char **argv) {
    signal(SIGTERM, handle_sigterm);
    signal(SIGINT, handle_sigint);

    printf("testapp: verbose: running SDL_Init()\n");
    if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_EVENTS|SDL_INIT_TIMER) < 0) {
        fprintf(stderr, "testapp: error: SDL_Init() failed\n");
        return 1;
    }
    printf("testapp: verbose: opening window\n");
    SDL_Window *window = SDL_CreateWindow(
        "testapp", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
        512, 512, SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI |
        SDL_WINDOW_OPENGL
    );
    if (!window) {
        fprintf(stderr, "testapp: error: SDL_CreateWindow() failed\n");
        return 1;
    }
    printf("testapp: verbose: entering event loop\n");

    int windowclosed = 0;
    while (!sigterm_received && !sigint_received && !windowclosed) {
        SDL_Event e;
        while (SDL_PollEvent(&e) > 0) {
            switch (e.type) {
                case SDL_QUIT: {
                    windowclosed = 1;
                    break;
                }
                case SDL_WINDOWEVENT: {
                    if (e.window.event ==
                            SDL_WINDOWEVENT_CLOSE) {
                        windowclosed = 1;
                        break;
                    }
                    break;
                }
                case SDL_KEYDOWN: {
                    printf(
                        "testapp: verbose: "
                        "SDL_KEYDOWN: keysym.sym=%d\n",
                        (int)e.key.keysym.sym
                    );
                    break;
                }
            }
        }
        SDL_Surface *srf = SDL_GetWindowSurface(window);
        SDL_FillRect(
            srf, NULL, SDL_MapRGB(srf->format, 255, 200, 220)
        );
        SDL_UpdateWindowSurface(window);
        SDL_Delay(100);
    }
    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}
  1. Launch a desktop using Phosh - I tested this on a PinePhone with the mobian distribution, although some desktop distributions like Fedora I think also ship Phosh for x64 machines where this should at least in theory also reproduce

  2. When the desktop is running, launch the application like this: SDL_VIDEODRIVER=wayland ./testapp

  3. Press C on squeekboard (Phosh's default visual keyboard)

Expected result:

$ SDL_VIDEODRIVER=wayland ./testapp
testapp: verbose: running SDL_Init()
testapp: verbose: opening window
testapp: verbose: entering event loop
testapp: verbose: SDL_KEYDOWN: keysym.sym=99

Actual result:

$ SDL_VIDEODRIVER=wayland ./testapp
testapp: verbose: running SDL_Init()
testapp: verbose: opening window
testapp: verbose: entering event loop
testapp: verbose: SDL_KEYDOWN: keysym.sym=1073742106

@ell1e ell1e changed the title SDL2 wayland SDL_KEYUP/SDL_KEYDOWN input mapping code possibly confused by changing key maps SDL2 wayland SDL_KEYUP/SDL_KEYDOWN input mapping code possibly confused by changing key maps [major issue on Librem 5/PinePhone] Mar 8, 2021
@ell1e
Copy link
Contributor Author

ell1e commented Mar 9, 2021

For what it's worth this bug/limitation/whatever makes SDL2 apps completely unusable on Linux phones since if using X11/XWayland/SDL_VIDEODRIVER=x11 there is another bug that breaks which=SDL_TOUCH_MOUSEID/some SDL_FINGERUP events (which is probably not worth fixing since all Linux phone desktops are Wayland-only anyway, so there is no point in investing into a blurry inferior X11/XWayland mode with libdecoration support on the way). But this means this issue here is a major blocker for Linux phone adoption, way more than e.g. virtual keyboard toggle support on Wayland in my opinion. (Since e.g. the Phosh mobile desktop has a manual toggle for that as a workaround.)

@Cacodemon345
Copy link
Contributor

Cacodemon345 commented Mar 15, 2021

The SDL_KEYMAPCHANGED event isn't sent at all on Wayland and there seems to be no mechanism to detect keymap changes there which would explain this bug.

@Cacodemon345
Copy link
Contributor

Actually, I was wrong; the Wayland backend does have the mechanism to detect keymap changes but it doesn't seem to be made to handle inputs from multiple keyboards.

@ell1e
Copy link
Contributor Author

ell1e commented Mar 16, 2021

I could be very wrong on this, but from my very limited understanding of the squeekboard discussions I don't think multiple keyboard support should be required. It seems to basically compose a fully artificial keymap on-the-fly with all the needed keys. But it seems like something goes wrong when the keymap change happens under wayland. (With SDL_VIDEODRIVER=x11 everything related to key input works.) SDL_TEXTINPUT also works, so it must be something specific to the key sym translation under Wayland that gets confused.

@Cacodemon345
Copy link
Contributor

Taking a look at XWayland's source code might be of help then.

@flibitijibibo
Copy link
Collaborator

This may be a duplicate of #3471 - though I noticed that the latest revision does have the keymap handler...

https://github.com/libsdl-org/SDL/blob/main/src/video/wayland/SDL_waylandevents.c#L645

... we don't ever queue the event to update the keymap. This is probably what the issue is. X11 for reference:

https://github.com/libsdl-org/SDL/blob/main/src/video/x11/SDL_x11events.c#L783

@ell1e
Copy link
Contributor Author

ell1e commented Apr 8, 2021

Would be cool if this could be looked into. Wayland is really way beyond my skillset, but this would help a ton with SDL2's current borderline unusable state on Linux phones

@flibitijibibo
Copy link
Collaborator

flibitijibibo commented Apr 9, 2021

Tried to get some more details on how the callbacks work... I think there might be a pretty big feature gap somewhere, and it's not just Wayland (as #4187 points out).

In short: There is a keymap update, but it only gets fired when you change your global keyboard settings in your desktop's settings menu. It does NOT fire when you change layout via a shortcut (i.e. the button in your taskbar). As far as I can tell, the behavior is identical between X and Wayland, so unfortunately this is NOTABUG in the sense that Wayland and X are the same, but it's still a blatant issue and I'm not actually sure that it's something we can fix on our end without an updated protocol (X is probably screwed at this point).

The good news is that text events do update layout properly, and that's probably why most applications other than games appear to work just fine - it just happens to be that games care about the keysym, which we don't get any updates for.

I did find one place where X and Wayland were different, and that was the lack of an UpdateKeymap routine. I have this set up here...

flibitijibibo@ec6ad51

... but as you might expect, this doesn't work (if anything it just breaks the stock layout). I swear xkbcommon has a real way to map scancodes to keycodes in a way that lets us just call the equivalent of "GetKeyFromScancode" but every path I take just returns exactly what I pass no matter what my layout is. This is where someone who actually understands xkbcommon will have to take over; I at least set up the SDL side but this loop isn't cooperating with me!

@flibitijibibo
Copy link
Collaborator

Today was an errand day for me so I wasn't about to get any real work done... which means running head-first into the xkbcommon wall at full speed was on my list!

I was finally able to dig up the APIs that should let us get the layout properly. Here's the latest version of my attempt at fixing this: flibitijibibo@36f73f6

Two items of concern:

Any further insight on this new stuff is appreciated!

@flibitijibibo
Copy link
Collaborator

flibitijibibo commented Apr 13, 2021

Oh my gracious I figured it out:

flibitijibibo@410b6cb

What I was looking for was groups - probably obvious if, unlike me, you are familiar with X keyboard support, but xkbcommon decided to rename it to layout_index_t and I couldn't quite parse what happened until I saw it in some X documentation and eventually tripped over it in waylandevents.c by accident.

With this commit, live layout changes now actually work! The last item is making the big ugly dictionary to translate xkb_keysym_t to SDL_Keycode, which can get assigned to the keymap array here:

flibitijibibo@410b6cb#diff-8a9cade1c69cd3c5c95378f2b386222c68aa893ea73ae792bb865061b8b9ebf2R786-R788

@flibitijibibo
Copy link
Collaborator

#4303 is live and ready to test.

@ghost
Copy link

ghost commented May 9, 2021

Hi, @flibitijibibo I've tested this patch, here is my feedback:

  • all alphanumeric keys work on the virtual keyboard
  • some symbols work on the virtual keyboard, many do nothing
  • all numbers work with a physical keyboard
  • letters are still messed up on physical keyboards
    here is a video demonstration

@ghost
Copy link

ghost commented May 9, 2021

I'm not very familiar with this codebase, but if you have a systematic way for me to test out the keycodes or dump debug information for you, then I'd be willing to try that and get back to you as I have a device availiable.
But in any case, I think this issue should be re-opened because some use-cases, for example anbox, require keys like ESC to work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants