wayland: Phase 77 — XKB keymap + keysym_to_keycode + modifier masks
Set a default XKB keymap on the headless keyboard device in wl_display_open() so the keyboard has a keycode↔keysym mapping available from startup. Implement wl_keysym_to_keycode() by scanning the XKB keymap for the first keycode that produces the given keysym; XKB keycodes equal evdev+8 == X11 keycodes, so wKeyBindings are directly compatible. Implement wl_keysym_from_keycode() as the reverse lookup. Call wSetModifierMasks(Mod1Mask, Mod1Mask, Mod4Mask, 0) from wl_screen_create_internals() so AltMask/MetaMask/SuperMask are non-zero in Wayland mode, making modifier parsing in wXModifierFromKey produce correct values. Add wSetModifierMasks() to xmodifier.c/h as the non-X11 entry point. Replace the four XKeysymToKeycode(dpy, ksym) call sites in defaults.c, rootmenu.c, and usermenu.c with wm_backend->keysym_to_keycode() so they work when dpy==NULL. Smoke test: check for "XKB keymap set on headless keyboard" log line. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
c7acf9d89d
commit
b1e4a99c5d
|
|
@ -88,10 +88,13 @@
|
|||
/* Generated xdg-shell protocol implementation (Wayland glue code) */
|
||||
#include "protocols/xdg-shell-protocol.c"
|
||||
#include <wlr/util/log.h>
|
||||
/* Phase 77: XKB for keysym→keycode translation and modifier mask setup */
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
#include "../../WindowMaker.h"
|
||||
#include "../../screen.h"
|
||||
#include "../../window.h"
|
||||
#include "../../xmodifier.h" /* Phase 77: wSetModifierMasks */
|
||||
#include "../backend.h"
|
||||
#include "wl_backend.h"
|
||||
|
||||
|
|
@ -500,8 +503,27 @@ wl_display_open(const char *name)
|
|||
* wlr_seat_keyboard_notify_enter() can deliver keyboard focus. */
|
||||
wl_state.keyboard_dev =
|
||||
wlr_headless_add_input_device(wl_state.backend, WLR_INPUT_DEVICE_KEYBOARD);
|
||||
if (wl_state.keyboard_dev)
|
||||
if (wl_state.keyboard_dev) {
|
||||
/* Phase 77: set a default XKB keymap on the headless keyboard so that
|
||||
* wl_keysym_to_keycode() can populate wKeyBindings during StartUp().
|
||||
* The xkb_keymap_new_from_names(NULL) produces the system default
|
||||
* layout (usually "us"), giving us the same keycode space as X11. */
|
||||
struct wlr_keyboard *kb = wl_state.keyboard_dev ? wl_state.keyboard_dev->keyboard : NULL;
|
||||
if (kb) {
|
||||
struct xkb_context *xkb_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||
if (xkb_ctx) {
|
||||
struct xkb_keymap *keymap = xkb_keymap_new_from_names(
|
||||
xkb_ctx, NULL, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
if (keymap) {
|
||||
wlr_keyboard_set_keymap(kb, keymap);
|
||||
xkb_keymap_unref(keymap);
|
||||
wwarning("wl_backend: XKB keymap set on headless keyboard");
|
||||
}
|
||||
xkb_context_unref(xkb_ctx);
|
||||
}
|
||||
}
|
||||
wlr_seat_set_keyboard(wl_state.seat, wl_state.keyboard_dev);
|
||||
}
|
||||
|
||||
/* Phase 53: create a headless pointer so the seat advertises pointer
|
||||
* capability to clients (required for clients that bind wl_pointer). */
|
||||
|
|
@ -1299,6 +1321,11 @@ wl_screen_create_internals(WScreen *scr)
|
|||
wPreferences.auto_focus = 1;
|
||||
if (wl_state.seat)
|
||||
wlr_seat_keyboard_clear_focus(wl_state.seat);
|
||||
|
||||
/* Phase 77: initialise modifier masks to standard XKB/X11 values so
|
||||
* that wXModifierFromKey("ALT") etc. return non-zero values.
|
||||
* Mod1Mask=8 (Alt), Mod4Mask=64 (Super/Win); Meta aliases Alt. */
|
||||
wSetModifierMasks(Mod1Mask, Mod1Mask, Mod4Mask, 0);
|
||||
}
|
||||
static void wl_screen_create_pixmaps(WScreen *scr) { (void)scr; }
|
||||
static void wl_screen_load_tech_font(WScreen *scr) { (void)scr; }
|
||||
|
|
@ -1368,8 +1395,59 @@ wl_workspace_badge_update(WScreen *scr, WNativeWindow badge_win, RImage *img)
|
|||
/* XKB */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static WKeyCode wl_keysym_to_keycode(unsigned long keysym) { (void)keysym; return 0; }
|
||||
static unsigned long wl_keysym_from_keycode(unsigned int keycode, unsigned int index) { (void)keycode; (void)index; return 0; }
|
||||
static WKeyCode
|
||||
wl_keysym_to_keycode(unsigned long keysym)
|
||||
{
|
||||
/* Phase 77: scan the XKB keymap on the headless keyboard to find the first
|
||||
* keycode that produces the given keysym at any level/layout.
|
||||
* The XKB keycode == evdev_scancode + 8, which equals the X11 keycode —
|
||||
* so the values stored in wKeyBindings are directly compatible. */
|
||||
if (!wl_state.keyboard_dev || !wl_state.keyboard_dev->keyboard)
|
||||
return 0;
|
||||
struct wlr_keyboard *kb = wl_state.keyboard_dev->keyboard;
|
||||
if (!kb->keymap)
|
||||
return 0;
|
||||
|
||||
xkb_keycode_t min_kc = xkb_keymap_min_keycode(kb->keymap);
|
||||
xkb_keycode_t max_kc = xkb_keymap_max_keycode(kb->keymap);
|
||||
|
||||
for (xkb_keycode_t kc = min_kc; kc <= max_kc; kc++) {
|
||||
xkb_layout_index_t nlayouts = xkb_keymap_num_layouts_for_key(kb->keymap, kc);
|
||||
xkb_layout_index_t layout;
|
||||
for (layout = 0; layout < nlayouts; layout++) {
|
||||
xkb_level_index_t nlevels = xkb_keymap_num_levels_for_key(kb->keymap, kc, layout);
|
||||
xkb_level_index_t level;
|
||||
for (level = 0; level < nlevels; level++) {
|
||||
const xkb_keysym_t *syms = NULL;
|
||||
int n = xkb_keymap_key_get_syms_by_level(kb->keymap, kc, layout, level, &syms);
|
||||
int si;
|
||||
for (si = 0; si < n; si++) {
|
||||
if (syms[si] == (xkb_keysym_t)keysym)
|
||||
return (WKeyCode)kc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
wl_keysym_from_keycode(unsigned int keycode, unsigned int index)
|
||||
{
|
||||
/* Phase 77: reverse lookup — return the keysym at the given keycode/level. */
|
||||
if (!wl_state.keyboard_dev || !wl_state.keyboard_dev->keyboard)
|
||||
return 0;
|
||||
struct wlr_keyboard *kb = wl_state.keyboard_dev->keyboard;
|
||||
if (!kb->keymap)
|
||||
return 0;
|
||||
const xkb_keysym_t *syms = NULL;
|
||||
int n = xkb_keymap_key_get_syms_by_level(kb->keymap, (xkb_keycode_t)keycode,
|
||||
0, (xkb_level_index_t)index, &syms);
|
||||
if (n > 0 && syms)
|
||||
return (unsigned long)syms[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wl_xkb_lock_group(int group) { (void)group; }
|
||||
static int wl_xkb_get_group(void) { return 0; }
|
||||
|
||||
|
|
|
|||
|
|
@ -2225,7 +2225,8 @@ static int getKeybind(WScreen * scr, WDefaultEntry * entry, WMPropList * value,
|
|||
return False;
|
||||
}
|
||||
|
||||
shortcut.keycode = XKeysymToKeycode(dpy, ksym);
|
||||
/* Phase 77: use vtable so keysym lookup works for both X11 and Wayland. */
|
||||
shortcut.keycode = wm_backend->keysym_to_keycode((unsigned long)ksym);
|
||||
if (shortcut.keycode == 0) {
|
||||
wwarning(_("%s:invalid key in shortcut \"%s\""), entry->key, val);
|
||||
return False;
|
||||
|
|
|
|||
|
|
@ -433,7 +433,8 @@ static Bool addShortcut(const char *file, const char *shortcutDefinition, WMenu
|
|||
return False;
|
||||
}
|
||||
|
||||
ptr->keycode = XKeysymToKeycode(dpy, ksym);
|
||||
/* Phase 77: use vtable so keysym lookup works for both X11 and Wayland. */
|
||||
ptr->keycode = wm_backend->keysym_to_keycode((unsigned long)ksym);
|
||||
if (ptr->keycode == 0) {
|
||||
wwarning(_("%s:invalid key in shortcut \"%s\" for entry %s"), file,
|
||||
shortcutDefinition, entry->text);
|
||||
|
|
|
|||
|
|
@ -173,7 +173,8 @@ static WUserMenuData *convertShortcuts(WScreen *scr, WMPropList *shortcut)
|
|||
if (ksym == NoSymbol)
|
||||
continue;
|
||||
|
||||
data->key[j].keycode = XKeysymToKeycode(dpy, ksym);
|
||||
/* Phase 77: use vtable so keysym lookup works for both X11 and Wayland. */
|
||||
data->key[j].keycode = wm_backend->keysym_to_keycode((unsigned long)ksym);
|
||||
if (data->key[j].keycode)
|
||||
j++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -328,6 +328,17 @@ int wXModifierFromKey(const char *key)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* Phase 77: allow non-X11 backends to set standard modifier masks directly.
|
||||
* Called from wl_screen_create_internals with XKB-standard values:
|
||||
* AltMask=Mod1Mask, MetaMask=Mod1Mask, SuperMask=Mod4Mask, HyperMask=0. */
|
||||
void wSetModifierMasks(int alt, int meta, int super, int hyper)
|
||||
{
|
||||
AltMask = alt;
|
||||
MetaMask = meta;
|
||||
SuperMask = super;
|
||||
HyperMask = hyper;
|
||||
}
|
||||
|
||||
/* Wrapper so that we may fit the WM naming conventions, yet leave the
|
||||
original XEmacs function name in place. */
|
||||
void wXModifierInitialize(void)
|
||||
|
|
|
|||
|
|
@ -23,5 +23,7 @@
|
|||
void wXModifierInitialize(void);
|
||||
int wXModifierFromKey(const char *key);
|
||||
const char *wXModifierToShortcutLabel(int mask);
|
||||
/* Phase 77: set modifier masks for non-X11 backends (Wayland). */
|
||||
void wSetModifierMasks(int alt, int meta, int super, int hyper);
|
||||
|
||||
#endif /* _XMODIFIER_H_INCLUDED */
|
||||
|
|
|
|||
|
|
@ -91,6 +91,12 @@
|
|||
# 34. (Phase 76) switchpanel.c: Alt-Tab panel title falls back to
|
||||
# wwin->wm_class when frame is NULL so Wayland windows appear in the
|
||||
# switcher without crashing (build-only check).
|
||||
# 35. (Phase 77) XKB keymap set on headless keyboard so wl_keysym_to_keycode
|
||||
# produces real keycodes; modifier masks (Alt=Mod1Mask, Super=Mod4Mask)
|
||||
# set via wSetModifierMasks so wKeyBindings are populated correctly;
|
||||
# XKeysymToKeycode(dpy,...) replaced by vtable in defaults.c/rootmenu.c/
|
||||
# usermenu.c so keyboard shortcuts are correctly configured in Wayland mode.
|
||||
# Verified by "XKB keymap set on headless keyboard" log.
|
||||
#
|
||||
# This test grows as wl_backend vtable slots are implemented.
|
||||
#
|
||||
|
|
@ -203,6 +209,14 @@ grep -q 'xdg-decoration-manager created' /tmp/wl-smoke-stderr \
|
|||
|| die "compositor did not log xdg-decoration-manager creation"
|
||||
echo " decoration check: xdg-decoration-manager created"
|
||||
|
||||
# -- 4d. Phase 77: XKB keymap must be set on headless keyboard ------------
|
||||
#
|
||||
# wl_display_open() logs "XKB keymap set on headless keyboard" after
|
||||
# Phase 77 changes; verify the log line is present.
|
||||
grep -q 'XKB keymap set on headless keyboard' /tmp/wl-smoke-stderr \
|
||||
|| die "compositor did not log XKB keymap setup (wl_keysym_to_keycode will return 0)"
|
||||
echo " xkb check: XKB keymap set on headless keyboard"
|
||||
|
||||
# -- 5. Core Wayland globals must be advertised ---------------------------
|
||||
#
|
||||
# Phase 35: wl_compositor, wl_seat, and xdg_wm_base must appear in the
|
||||
|
|
|
|||
Loading…
Reference in New Issue