X11 MappingNotify не запускается, как ожидалось из документации X11

When developing an accessibility application, I encounter a behavior deferring from what should happen according to all Xlib documentation sets I could so far put my hands on:

The event MappingNotify is supposed to fire whenever the keyboard layout changes. It is my understanding that switching between input languages when multiple languages are installed, entails (behind the scenes) a keyboard layout change. However, conversely to this understanding, using the commandline for logging X events, xev, I can see the MappingNotify event being fired only when a keyboard shortcut is being changed by me via the Gnome Tweak Tool.

When switching input languages via the gnome menu-bar widget or the assigned keyboard shortcut, this event does not fire at all.

Arguably this is a systems development issue and not a common usage scenario.

Switching input language does take effect in all Windows ― immediately after switching between the installed input languages key presses do follow the chosen input language's layout as expected. However the MappingNotify event does not seem to fire or reach xev nor my own Xlib code listening to X events.

Would be happy to learn if this reproduces for you as well, or any pointers for the right developer forums to consult.

EDIT:

I do get in xev a KeyRelease event (yet not a KeyPress one) for ISO_Next_Group, which is likely the X Keyboard Extension event used for switching layouts if arch linux and Ubuntu share on that. Thus I could wildly speculate that gnome could be in fact grabbing the X11 MappingNotify event, preventing it from reaching X clients, but sending them a key release of this KeyPress event instead.

When using the commandline setxkbmap, e.g.

setxkbmap us

then MappingNotify does fire for clients! but it renders the gnome language switching inoperable thereafter. Windows will simply ignore Gnome's view of the current input language thereafter.

1
задан 19 June 2020 в 01:13

1 ответ

On my system, MappingNotify keyboard layout events from X do not normally fire. They do fire from within the Gnome Tweaks tool when modifying keyboard shortcuts through it, but not otherwise, so effectively, they seem not to be usefully and generally available to X clients (because that fringe case when fiddling shortcuts inside the Tweak tool is not the key use case we expect to get that notification at).

On my systems (18.04, and after upgrading to 20.04 alike), the X KEYBOARD Extension to X11 is active. This extension was designed to add various flexibilities over the standard X handling of keyboards.

So specifically to keyobard layout changes, since this X11 extension is active, MappingNotify will not fire under normal circumstances, but rather this extension will insert a different event into the client queue:

A XkbQueryExtension API call should query the X Keyboard extension for the "global" event code used by the X Keyboard Extension, and then when such an event is detected on the X11 queue, a XkbStateNotify sub-type included with the event will be used to inform clients of the keyboard layout change!

This flow is described along with a larger flow it belongs in, in the X Keyboard spec, and given in C code here. A slightly cleaned up version of that code follows:

#include <stdio.h>
#include <X11/XKBlib.h>

int main(int argc, char **argv)
{
        XEvent e;
        Display *d;

        if (!(d = XOpenDisplay(NULL))) {
                fprintf(stderr, "cannot open display\n");
                return 1;
        }

    // initialize the XKB protocol and obtain the integer event code that will be used by it
    int xkbEventType;
    XkbQueryExtension(d, 0, &xkbEventType, 0, 0, 0);  // assigns the integer code for XKB to xkbEventType
    printf("%d\n", xkbEventType);

    XkbSelectEvents(d, XkbUseCoreKbd, XkbAllEventsMask, XkbAllEventsMask);

    XSync(d, False);

    while (1) {
        XNextEvent(d, &e);
        if (e.type == xkbEventType) {
            XkbEvent* xkbEvent = (XkbEvent*) &e;
            if (xkbEvent->any.xkb_type == XkbStateNotify) {
                printf("keyboard layout change, or mouse click");
                fflush(stdout);
            }
        }
    }

    return(0);
}

Note that this same event will also fire for any mouse click ... something I believe we can filter away e.g. by tweaking our XkbSelectEvents arguments by device type if we mapped the devices on the system (haven't tried yet).

0
ответ дан 19 June 2020 в 21:25

Другие вопросы по тегам:

Похожие вопросы: