Files
raven/native/desktop/keyboard_test.cpp
T
Ray Bennett cdc4283f22 fix: accept Wayland keymaps without a terminator and keys with no symbol (#26)
Some compositors, niri among them, send the XKB keymap without a
trailing null, which the protocol allows; Raven treated that as an input
failure and gave up on the desktop before the first window. The keymap
is now taken whole when it has no terminator. A key the layout gives no
symbol (an unassigned or vendor key) passes with no virtual key instead
of ending the process, and one that gives several is known by the first.

Assisted-by: Claude Code:claude-opus-5-5
AI-Scope: Diagnosed the "unsupported native input event" failure on niri
 from WAYLAND_DEBUG output and a small wayland-client probe, and wrote
 both changes and the keyboard_test case. Prompt: get an MSI installer
 and the program it installs running under Raven on niri.
2026-10-28 16:50:10 +01:00

51 lines
2.7 KiB
C++

#include "keyboard.h"
#include <xkbcommon/xkbcommon.h>
#include <cstdlib>
#include <iostream>
#include <stdexcept>
static void check(bool value,const char *message)
{
if (!value) throw std::runtime_error(message);
}
int main()
{
try {
auto *context=xkb_context_new(XKB_CONTEXT_NO_FLAGS); check(context,"cannot create reference XKB context");
for (const auto *layout : {"us","de"}) {
xkb_rule_names names{}; names.layout=layout;
auto *map=xkb_keymap_new_from_names(context,&names,XKB_KEYMAP_COMPILE_NO_FLAGS); check(map,"cannot build reference layout");
auto *text=xkb_keymap_get_as_string(map,XKB_KEYMAP_FORMAT_TEXT_V1); check(text,"cannot serialize reference layout");
raven::KeyboardMap keyboard; keyboard.load(text); std::free(text);
const uint32_t events[]{125,126,127,69,70},virtual_keys[]{0x5b,0x5c,0x5d,0x90,0x91},scans[]{91,92,93,69,70};
for (size_t i=0;i<5;++i) {
const auto key=keyboard.decode(events[i]);
check(key.code==virtual_keys[i] && key.scan==scans[i] && !key.character && key.extended==(i<3),"system key translation differs");
}
// Keys the layout gives no symbol (the Japanese Ro key, a vendor key) pass with no virtual key instead of failing.
const auto ro=keyboard.decode(89),vendor=keyboard.decode(141);
check(!ro.code && ro.scan==89 && !ro.character && !vendor.code && !vendor.scan && !vendor.character,"key without a symbol differs");
const auto g=keyboard.decode(34),y=keyboard.decode(21);
check(g.code==71 && g.scan==34 && g.character=='g' && !g.extended,"G keyboard contract differs");
check(y.code==(layout[0]=='u' ? 89U : 90U) && y.character==(layout[0]=='u' ? 'y' : 'z'),"layout-dependent virtual key differs");
const auto shift=xkb_keymap_mod_get_index(map,XKB_MOD_NAME_SHIFT),control=xkb_keymap_mod_get_index(map,XKB_MOD_NAME_CTRL);
check(shift<32 && control<32,"reference modifier index exceeds ABI");
keyboard.modifiers(1U<<shift,0,0,0);
check(keyboard.decode(34).character=='G' && keyboard.mouse_modifiers()==4,"shift translation differs");
keyboard.modifiers(1U<<control,0,0,0);
check(keyboard.decode(34).character==7 && keyboard.mouse_modifiers()==8,"control translation differs");
keyboard.modifiers(0,0,0,0);
bool rejected=false;
try { keyboard.load("invalid keymap"); } catch (const std::runtime_error &) { rejected=true; }
check(rejected && keyboard.decode(34).character=='g',"failed keymap reload damaged state");
rejected=false;
try { keyboard.decode(999); } catch (const std::runtime_error &) { rejected=true; }
check(rejected,"out-of-range keyboard code succeeded");
xkb_keymap_unref(map);
}
xkb_context_unref(context);
} catch (const std::exception &error) { std::cerr<<error.what()<<'\n'; return 1; }
return 0;
}