Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit 873284b

Browse files
johnpemilio
authored andcommitted
Bug 1827615 - [Wayland] Fix Level3 and Level5 mappings. r=stransky
libxkbcommon actually uses the strings "LevelThree" and "LevelFive" for Level3 / Level5 respectively. To prevent this mixup from happening again, use the defines from libxkbcommon and add fallbacks on our side as well. Furthermore, GDK does not support Level3 / Level5 vmods in GdkModifierType, and we also can't expect bitwise compatibility between GdkModifierType and the opaque `(1 << xkb_keymap_mod_get_index(...))` result. Instead, use the libxkbcommon API to reverse the vmod->rmod mapping GDK does internally, and match against that. Do no translate the META, SUPER and HYPER vmods, which are natively supported by GDK, because they otherwise collide with rmods like ALT, which we don't want to happen. See also: xkbcommon/libxkbcommon#732 Differential Revision: https://phabricator.services.mozilla.com/D250529
1 parent 99ef23c commit 873284b

File tree

3 files changed

+80
-11
lines changed

3 files changed

+80
-11
lines changed

widget/gtk/mozwayland/mozwayland.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,3 +271,22 @@ MOZ_EXPORT int xkb_keymap_key_repeats(struct xkb_keymap* keymap,
271271
xkb_keycode_t kc) {
272272
return 0;
273273
}
274+
275+
MOZ_EXPORT struct xkb_state* xkb_state_new(struct xkb_keymap* keymap) {
276+
return NULL;
277+
}
278+
279+
MOZ_EXPORT void xkb_state_unref(struct xkb_state* state) {}
280+
281+
MOZ_EXPORT enum xkb_state_component xkb_state_update_mask(
282+
struct xkb_state* state, xkb_mod_mask_t depressed_mods,
283+
xkb_mod_mask_t latched_mods, xkb_mod_mask_t locked_mods,
284+
xkb_layout_index_t depressed_layout, xkb_layout_index_t latched_layout,
285+
xkb_layout_index_t locked_layout) {
286+
return 0;
287+
}
288+
289+
MOZ_EXPORT xkb_mod_mask_t xkb_state_serialize_mods(
290+
struct xkb_state* state, enum xkb_state_component components) {
291+
return 0;
292+
}

widget/gtk/nsGtkKeyUtils.cpp

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -651,23 +651,48 @@ void KeymapWrapper::SetModifierMask(xkb_keymap* aKeymap,
651651
ModifierIndex aModifierIndex,
652652
const char* aModifierName) {
653653
xkb_mod_index_t index = xkb_keymap_mod_get_index(aKeymap, aModifierName);
654-
if (index != XKB_MOD_INVALID) {
655-
mModifierMasks[aModifierIndex] = (1 << index);
654+
if (index == XKB_MOD_INVALID) {
655+
return;
656+
}
657+
struct xkb_state* xkb_state = xkb_state_new(aKeymap);
658+
if (!xkb_state) {
659+
return;
660+
}
661+
xkb_mod_mask_t mask = 1u << index;
662+
xkb_state_update_mask(xkb_state, mask, 0, 0, 0, 0, 0);
663+
xkb_mod_mask_t res =
664+
xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_EFFECTIVE);
665+
xkb_state_unref(xkb_state);
666+
if (res == mask) {
667+
// Either this already was an rmod, or it's an unmapped vmod. In the former
668+
// case we obviously want to use it, in the latter this allows us to handle
669+
// synthesized key events using that vmod, even if that vmod cannot be
670+
// generated by keyboard (with a slight risk of GdkModifierType collisions).
671+
mModifierMasks[aModifierIndex] = res;
672+
} else {
673+
// We found a mapped rmod for the vmod. Make sure to remove the opaque `1u
674+
// << index` mask, which does not get removed by xkb_state_serialize_mods,
675+
// because it can quite easily collide with the bitwise-incompatible parts
676+
// of the GdkModifierType enum (most likely GDK_BUTTON{N}_MASK).
677+
mModifierMasks[aModifierIndex] = res & ~(mask);
656678
}
657679
}
658680

659681
void KeymapWrapper::SetModifierMasks(xkb_keymap* aKeymap) {
660682
KeymapWrapper* keymapWrapper = GetInstance();
661683

662-
// This mapping is derived from get_xkb_modifiers() at gdkkeys-wayland.c
663-
keymapWrapper->SetModifierMask(aKeymap, INDEX_NUM_LOCK, XKB_MOD_NAME_NUM);
684+
// These mappings are derived from get_xkb_modifiers() at gdkkeys-wayland.c,
685+
// as well as libxkbcommon. The first two are practically fixed.
664686
keymapWrapper->SetModifierMask(aKeymap, INDEX_ALT, XKB_MOD_NAME_ALT);
665-
keymapWrapper->SetModifierMask(aKeymap, INDEX_META, "Meta");
666-
keymapWrapper->SetModifierMask(aKeymap, INDEX_HYPER, "Hyper");
667-
668-
keymapWrapper->SetModifierMask(aKeymap, INDEX_SCROLL_LOCK, "ScrollLock");
669-
keymapWrapper->SetModifierMask(aKeymap, INDEX_LEVEL3, "Level3");
670-
keymapWrapper->SetModifierMask(aKeymap, INDEX_LEVEL5, "Level5");
687+
keymapWrapper->SetModifierMask(aKeymap, INDEX_NUM_LOCK, XKB_MOD_NAME_NUM);
688+
// We have to find the rmods for these vmods, which are not supported by GDK.
689+
keymapWrapper->SetModifierMask(aKeymap, INDEX_LEVEL3, XKB_VMOD_NAME_LEVEL3);
690+
keymapWrapper->SetModifierMask(aKeymap, INDEX_LEVEL5, XKB_VMOD_NAME_LEVEL5);
691+
keymapWrapper->SetModifierMask(aKeymap, INDEX_SCROLL_LOCK,
692+
XKB_VMOD_NAME_SCROLL);
693+
// GDK specific vmods we don't want to map to rmods to preserve behavior.
694+
keymapWrapper->mModifierMasks[INDEX_HYPER] = GDK_HYPER_MASK;
695+
keymapWrapper->mModifierMasks[INDEX_META] = GDK_META_MASK;
671696

672697
keymapWrapper->SetKeymap(aKeymap);
673698

@@ -2658,7 +2683,8 @@ void KeymapWrapper::WillDispatchKeyboardEventInternal(
26582683
guint baseState = aGdkKeyEvent->state &
26592684
~(GetGdkModifierMask(SHIFT) | GetGdkModifierMask(CTRL) |
26602685
GetGdkModifierMask(ALT) | GetGdkModifierMask(META) |
2661-
GetGdkModifierMask(SUPER) | GetGdkModifierMask(HYPER));
2686+
GetGdkModifierMask(SUPER) | GetGdkModifierMask(HYPER) |
2687+
GDK_META_MASK | GDK_SUPER_MASK | GDK_HYPER_MASK);
26622688

26632689
// We shold send both shifted char and unshifted char, all keyboard layout
26642690
// users can use all keys. Don't change event.mCharCode. On some keyboard

widget/gtk/nsGtkKeyUtils.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,30 @@
1919
#ifdef MOZ_WAYLAND
2020
# include <gdk/gdkwayland.h>
2121
# include <xkbcommon/xkbcommon.h>
22+
# ifndef XKB_VMOD_NAME_ALT
23+
# define XKB_VMOD_NAME_ALT "Alt"
24+
# endif
25+
# ifndef XKB_VMOD_NAME_HYPER
26+
# define XKB_VMOD_NAME_HYPER "Hyper"
27+
# endif
28+
# ifndef XKB_VMOD_NAME_LEVEL3
29+
# define XKB_VMOD_NAME_LEVEL3 "LevelThree"
30+
# endif
31+
# ifndef XKB_VMOD_NAME_LEVEL5
32+
# define XKB_VMOD_NAME_LEVEL5 "LevelFive"
33+
# endif
34+
# ifndef XKB_VMOD_NAME_META
35+
# define XKB_VMOD_NAME_META "Meta"
36+
# endif
37+
# ifndef XKB_VMOD_NAME_NUM
38+
# define XKB_VMOD_NAME_NUM "NumLock"
39+
# endif
40+
# ifndef XKB_VMOD_NAME_SCROLL
41+
# define XKB_VMOD_NAME_SCROLL "ScrollLock"
42+
# endif
43+
# ifndef XKB_VMOD_NAME_SUPER
44+
# define XKB_VMOD_NAME_SUPER "Super"
45+
# endif
2246
#endif
2347
#include "X11UndefineNone.h"
2448

0 commit comments

Comments
 (0)