Files
vatrog-vm-signaling/src/test/test_uinputlayout.c
T
lirent d6c45ddb04 feat(input): daemon sets up the host->guest input-linux bridge via QMP
The uinput devices the input adapter creates were never forwarded into the
guest: the input-linux bridge was external (manual monitor object_add), so it
was lost on every reconfigure and whenever the kernel-assigned device numbers
changed. Make the vmhost seam -- which already owns the VM's single QMP
connection -- add the input-linux objects itself on reaching READY (A=keyboard
+abs with grab_all, B=mouse) and object_del them on teardown. The input adapter
publishes the uinput evdev paths into a per-endpoint home; discovery attaches
input before vmhost so the paths are ready. No second QMP socket or connection.

Also move the mouse buttons (incl. middle) and the wheel onto device B, so B is
a complete relative mouse and A is keyboard+abs only.

Bump 0.3.8.
2026-06-24 16:31:23 +03:00

62 lines
3.2 KiB
C

/* test_uinputlayout.c — DECLARATIVE uinput capability split (pure, no /dev/uinput).
*
* Verifies the ptr_mode -> A/B role mapping that drives both device creation and the hot-path
* button/wheel carrier selection: in PTR_BOTH A is keyboard+abs and B is rel+buttons+wheel, and
* the button/wheel carrier is B; single-pointer modes keep buttons+wheel on the sole device.
* The actuation ioctls remain armed-only (they need a real /dev/uinput); this covers the logic
* that decides the layout, which is the part that single-mode regressions would break. */
#include "vmctl.h"
#include "uinput_layout.h"
#include <stdio.h>
static int g_fail = 0;
#define CHECK(cond, msg) do { \
if (!(cond)) { printf(" FAIL: %s\n", (msg)); g_fail = 1; } \
} while (0)
int main(void) {
uinput_role a, b; int btn_on_b;
/* PTR_BOTH: A = keyboard + absolute pointer, no buttons/wheel; B = relative pointer +
* buttons + wheel; carrier is B. This is the requested layout (mouse buttons incl. middle
* and the wheel moved off A onto B). */
vmctl_uinput_layout(VMCTL_PTR_BOTH, &a, &b, &btn_on_b);
CHECK(a.present && b.present, "BOTH: two devices");
CHECK(a.want_keyboard, "BOTH: A has keyboard");
CHECK(!a.rel_motion, "BOTH: A is absolute");
CHECK(!a.want_buttons, "BOTH: A has NO mouse buttons");
CHECK(!a.want_wheel, "BOTH: A has NO wheel");
CHECK(!b.want_keyboard, "BOTH: B has no keyboard");
CHECK(b.rel_motion, "BOTH: B is relative");
CHECK(b.want_buttons, "BOTH: B has mouse buttons");
CHECK(b.want_wheel, "BOTH: B has wheel");
CHECK(btn_on_b == 1, "BOTH: button/wheel carrier is B");
/* PTR_REL: single relative device A carries motion + buttons + wheel (no B). */
vmctl_uinput_layout(VMCTL_PTR_REL, &a, &b, &btn_on_b);
CHECK(a.present && !b.present, "REL: single device A");
CHECK(a.rel_motion, "REL: A is relative");
CHECK(a.want_buttons, "REL: A has buttons");
CHECK(a.want_wheel, "REL: A has wheel");
CHECK(a.want_keyboard, "REL: A has keyboard");
CHECK(btn_on_b == 0, "REL: carrier is A");
/* PTR_ABS: single absolute device A carries abs + buttons + wheel (the only device). */
vmctl_uinput_layout(VMCTL_PTR_ABS, &a, &b, &btn_on_b);
CHECK(a.present && !b.present, "ABS: single device A");
CHECK(!a.rel_motion, "ABS: A is absolute");
CHECK(a.want_buttons, "ABS: A has buttons (sole device)");
CHECK(a.want_wheel, "ABS: A has wheel (sole device)");
CHECK(btn_on_b == 0, "ABS: carrier is A");
/* evdev export contract: a NULL handle reports "not a uinput handle" (-1). The populated
* path (real /dev/input/eventN) is armed-only — it needs a created uinput device. */
{
char ea[64], eb[64];
CHECK(vmctl_uinput_evdev(NULL, ea, eb) == -1, "evdev export: NULL handle -> -1");
}
printf("uinputlayout tests: %s\n", g_fail ? "FAIL" : "PASS");
return g_fail ? 1 : 0;
}