input: one-packet pointer moves, uinput-only injection, fire-and-forget

- Pointer motion is now a single event carrying both coordinates (MOVE_ABS /
  MOVE_REL with x,y) rather than one event per axis; the adapter actuates both
  axes in a single batch. The per-axis ABS/REL kinds are removed.
- Input injection is uinput-only: the driver selection and the optional
  guest-side passthrough drop out of the adapter config (the driver is the
  driver's concern). A QMP path is still carried for the unchanged service
  power/lifecycle path.
- A per-event fire-and-forget flag lets a control inject input without an
  actuation acknowledgement, for high-rate streams; without it the addressed
  ACT_ACK is emitted as before. Service commands always acknowledge.

The neutral input payload gains x/y/flags, still within the inline event body.
Capability, lease and source gates are unchanged.
This commit is contained in:
2026-06-21 10:31:36 +03:00
parent e6c7aed8eb
commit 0d387a4249
6 changed files with 72 additions and 47 deletions
+24 -14
View File
@@ -148,24 +148,34 @@ enum {
};
/* ===== Input (DOWN VMSIG_EV_CMD_INPUT, in inln) — NEUTRAL =====
* control describes input abstractly (axis/button/key/scroll), WITHOUT knowing the driver
* (uinput/QMP): the input adapter translates it into its contract. Requires CAP_INPUT. This
* is the ONLY public input-encoding contract — an external control encodes vmsig_input into
* vmsig_event.inln. */
* control describes input abstractly (pointer motion / button / key / scroll), WITHOUT knowing
* the driver: the input adapter translates it into its contract (injection is always uinput).
* Requires CAP_INPUT. This is the ONLY public input-encoding contract — an external control
* encodes vmsig_input into vmsig_event.inln.
*
* Pointer motion carries BOTH coordinates in ONE event (a pointer position is a single entity,
* not two independent axis updates). btn/key/scroll stay single-valued. */
typedef enum {
VMSIG_INPUT_ABS = 0, /* absolute axis: code=axis, value=coordinate */
VMSIG_INPUT_REL = 1, /* relative axis: code=axis, value=delta */
VMSIG_INPUT_BTN = 2, /* button: code=button, value=pressed(1)/released(0) */
VMSIG_INPUT_KEY = 3, /* key: code=evdev code, value=pressed/released */
VMSIG_INPUT_SCROLL = 4 /* scroll: code=axis, scroll=magnitude */
VMSIG_INPUT_MOVE_ABS = 0, /* absolute pointer: x,y are coordinates (0..VMCTL_ABS_MAX) */
VMSIG_INPUT_MOVE_REL = 1, /* relative pointer: x,y are deltas (dx,dy) */
VMSIG_INPUT_BTN = 2, /* button: code=button, value=pressed(1)/released(0) */
VMSIG_INPUT_KEY = 3, /* key: code=evdev code, value=pressed/released */
VMSIG_INPUT_SCROLL = 4 /* scroll: code=axis, scroll=magnitude */
} vmsig_input_kind;
/* Per-event transfer-context flags (signaling owns the transfer context). */
#define VMSIG_INPUT_F_NOACK 0x1u /* fire-and-forget: adapter actuates, emits NO ACT_ACK */
typedef struct {
uint32_t kind; /* vmsig_input_kind */
int32_t code; /* axis / button / evdev code (neutral event code) */
int32_t value; /* abs coordinate / rel delta / pressed(1)|released(0) */
double scroll; /* scroll magnitude (VMSIG_INPUT_SCROLL only) */
} vmsig_input; /* fits in vmsig_event.inln[48] */
uint16_t kind; /* vmsig_input_kind */
uint16_t code; /* button / evdev code / scroll axis (NOT used by MOVE_*) */
int32_t value; /* pressed(1)|released(0) for BTN/KEY (not used by MOVE or SCROLL) */
int32_t x; /* MOVE_ABS: abs X (0..VMCTL_ABS_MAX); MOVE_REL: dx */
int32_t y; /* MOVE_ABS: abs Y; MOVE_REL: dy */
double scroll; /* SCROLL magnitude only */
uint32_t flags; /* VMSIG_INPUT_F_* (see above) */
uint32_t _pad; /* reserved; zero on emit */
} vmsig_input; /* 32 bytes; fits in vmsig_event.inln[48] */
/* ===== Memory write (DOWN VMSIG_EV_CMD_MEMWRITE) — NEUTRAL, write-signaled =====
* control describes an ATOMIC write into guest memory abstractly: a TARGET address space