Gdk_x11_keymap_key_is_modifier on Wayland and behind

I’m trying to find an alternative to gdk_x11_keymap_key_is_modifier that may work on other platform than just on X11.

My application generates GDK_KEY_PRESS and GDK_KEY_RELEASE based on a sequence that have been previously saved by the user.

Based on each keycode I determine if that specific keycode is a modifier with gdk_x11_keymap_key_is_modifier to set event.is_modifier

As this cannot work on pure Wayland or other platform like Windows or on Quartz, I was wondering if it exists an alternative instead of reinventting the wheel, also because I don’t know from where to start .

This ismy function that as of today works only on X11

   /* Check if the requested keycode is a key modifier */
gboolean 
get_modifier_for_keycode(GdkKeymap *keymap, guint16 keycode)
{
        g_return_val_if_fail(keycode > 0, FALSE);
#ifdef GDK_WINDOWING_X11
        return gdk_x11_keymap_key_is_modifier(keymap, keycode);
#else
        return FALSE;
#endif
}

This is the piece of code that emit the key press/release and that call the previous function

void 
send_keys_signals(GtkWidget *widget, 
                                         const guint *keyvals, 
                                         int keyvals_length, 
                                         GdkEventType action)
{
        int i;
        GdkEventKey event;
        gboolean result;
        GdkKeymap *keymap = gdk_keymap_get_for_display(gdk_display_get_default());

        event.window = gtk_widget_get_window(widget);
        event.send_event = TRUE;
        event.time = GDK_CURRENT_TIME;
        event.state = 0;
        event.length = 0;
        event.string = "";
        event.group = 0;

        if (action & GDK_KEY_PRESS) {
                /* Press the requested buttons */
                event.type = GDK_KEY_PRESS;
                for (i = 0; i < keyvals_length; i++) {
                        event.keyval = keyvals[i];
                        event.hardware_keycode = get_keycode_for_keyval(keymap, event.keyval);
                        event.is_modifier = (int)get_modifier_for_keycode(keymap, event.hardware_keycode);
                        g_signal_emit_by_name(G_OBJECT(widget), "key-press-event", &event, &result);
                }
        }

        if (action & GDK_KEY_RELEASE) {
                /* Release the requested buttons in reverse order */
                event.type = GDK_KEY_RELEASE;
                for (i = (keyvals_length - 1); i >= 0; i--) {
                        event.keyval = keyvals[i];
                        event.hardware_keycode = get_keycode_for_keyval(keymap, event.keyval);
                        event.is_modifier = (int)get_modifier_for_keycode(keymap, event.hardware_keycode);
                        g_signal_emit_by_name(G_OBJECT(widget), "key-release-event", &event, &result);
                }
        }
}
2 Likes

You can look at the individual backends to see what they do there: Wayland, Win32,
macOS. But it seems unlikely you would want to duplicate this code in an application.

Is there another way you could record steps performed by the user, maybe by recording GAction invocations? It seems that recording keycode sequences would not really be usable in some situations, i.e. it won’t preserve interactions with input methods, it will have some odd behavior if the user plays it back in the middle of a compose sequence, and the sequence could do something completely different if the user changes keymap, etc.

Edit: Another reason not to do this is if you plan to port to GTK4, custom events are no longer possible there.

1 Like

Thanks.
The user has a simple widget where it enters the pre configured strings he want to send to the remote server, these strings may contains modifiers as well.

What I’d really like to do is a macro recorder/player, to be used like it’s done with a browser with selenium and/or webdriver.

I thought to use atk for this, but I’m not yet sure it’s the right solution.

At the moment I just wanted a quick and dirty solution that could work on most platform, at least on Wayland

If you just want to support Wayland, you can probably easily use the same technique with xkbcommon that is used by gtk internally that I posted above, specifically this part:

  xkb_state = xkb_state_new (xkb_keymap);

  if (xkb_state_update_key (xkb_state, keycode, XKB_KEY_DOWN) & XKB_STATE_MODS_EFFECTIVE)
    is_modifier = TRUE;

Managing the keymap is another story, maybe you would want to save the keymap at the time of macro record, and then restore it temporarily while the macro is played? Though that could also cause some issues. The only “safe” way I see virtual input being done is to create a separate virtual input device (either with evdev or internal to the compositor) that manages its own state. This would have to be done outside GTK.

Thanks!
libxkbcomp was something I was looking at, but I didnt get how to deal with the modifier keys.

Now it’s ckear

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.