mirror of
https://dev.lirent.ru/Vatrog/vm-automation-signaling.git
synced 2026-06-26 04:36:37 +03:00
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:
+32
-24
@@ -22,12 +22,15 @@ typedef struct {
|
||||
uint32_t corr;
|
||||
uint32_t origin; /* initiator (addressed ACK) */
|
||||
int kind; /* vmsig_input_kind (for cmd==0) */
|
||||
int code; /* axis/btn/evdev-code */
|
||||
int value; /* abs/rel/down */
|
||||
int code; /* btn/evdev-code/scroll-axis */
|
||||
int value; /* pressed(1)/released(0) for btn/key */
|
||||
int x; /* MOVE_ABS: abs X; MOVE_REL: dx */
|
||||
int y; /* MOVE_ABS: abs Y; MOVE_REL: dy */
|
||||
double scroll;
|
||||
int noack; /* CMD_INPUT fire-and-forget: emit no ACT_ACK */
|
||||
int life_op; /* VMSIG_LIFE_* (powerdown/reset/wakeup/pause/resume) */
|
||||
} input_req;
|
||||
typedef struct { int ok; uint32_t corr; uint32_t origin; } input_res;
|
||||
typedef struct { int ok; uint32_t corr; uint32_t origin; int noack; } input_res;
|
||||
|
||||
/* signaling does NOT track held state: the record of what is pressed lives in the
|
||||
* ACTUATOR (vmctl); we hand it to control on request (CMD_QUERY_INPUT), release is control's decision. */
|
||||
@@ -36,10 +39,7 @@ struct vmsig_adapter {
|
||||
int stub;
|
||||
vmsig_emit emit;
|
||||
vmsig_worker* worker;
|
||||
int driver; /* 0=QMP, 1=UINPUT (VMCTL_DRIVER_*); carried open->attach */
|
||||
const char* qmp_path; /* borrowed from cfg (valid through attach) */
|
||||
const char* input_bus;
|
||||
int ptr_mode;
|
||||
const char* qmp_path; /* borrowed from cfg (valid through attach); SERVICE power/lifecycle */
|
||||
#ifdef VMSIG_WITH_VMCTL
|
||||
vmctl_t* vmctl;
|
||||
#endif
|
||||
@@ -52,14 +52,22 @@ static int input_job(void* user, const void* reqp, void* resp) {
|
||||
memset(rs, 0, sizeof *rs);
|
||||
rs->corr = rq->corr;
|
||||
rs->origin = rq->origin;
|
||||
rs->noack = rq->noack;
|
||||
#ifdef VMSIG_WITH_VMCTL
|
||||
if (a->vmctl) {
|
||||
int r = -1;
|
||||
if (rq->cmd == 0) {
|
||||
/* Pointer motion is ONE packet: both axes in a single batch -> one round-trip. */
|
||||
vmctl_batch b; vmctl_batch_init(&b);
|
||||
switch (rq->kind) {
|
||||
case VMSIG_INPUT_ABS: vmctl_batch_abs(&b, rq->code, rq->value); break;
|
||||
case VMSIG_INPUT_REL: vmctl_batch_rel(&b, rq->code, rq->value); break;
|
||||
case VMSIG_INPUT_MOVE_ABS:
|
||||
vmctl_batch_abs(&b, VMCTL_AXIS_X, rq->x);
|
||||
vmctl_batch_abs(&b, VMCTL_AXIS_Y, rq->y);
|
||||
break;
|
||||
case VMSIG_INPUT_MOVE_REL:
|
||||
vmctl_batch_rel(&b, VMCTL_AXIS_X, rq->x);
|
||||
vmctl_batch_rel(&b, VMCTL_AXIS_Y, rq->y);
|
||||
break;
|
||||
case VMSIG_INPUT_BTN: vmctl_batch_btn(&b, rq->code, rq->value); break;
|
||||
case VMSIG_INPUT_KEY: vmctl_batch_key(&b, rq->code, rq->value); break;
|
||||
case VMSIG_INPUT_SCROLL: vmctl_batch_scroll(&b, rq->code, rq->scroll); break;
|
||||
@@ -91,12 +99,7 @@ static vmsig_adapter* in_open(const void* cfg, uint32_t endpoint) {
|
||||
if (!a) return NULL;
|
||||
a->endpoint = endpoint;
|
||||
a->stub = c ? c->stub : 1;
|
||||
if (c) { /* carry the driver selection to attach (cfg not passed there) */
|
||||
a->driver = c->driver;
|
||||
a->qmp_path = c->qmp_path;
|
||||
a->input_bus = c->input_bus;
|
||||
a->ptr_mode = c->ptr_mode;
|
||||
}
|
||||
if (c) a->qmp_path = c->qmp_path; /* carry to attach (cfg not passed there); SERVICE power */
|
||||
return a;
|
||||
}
|
||||
|
||||
@@ -108,15 +111,16 @@ static int in_attach(vmsig_adapter* a, const vmsig_emit* emit, vmsig_fd_reg* reg
|
||||
|
||||
#ifdef VMSIG_WITH_VMCTL
|
||||
if (!a->stub) {
|
||||
/* armed: build vmctl_config from the carried cfg and open the actuator. UINPUT
|
||||
* (host uinput + optional virtio-input-host-pci passthrough via QMP) is the primary
|
||||
* input driver; QMP input-send-event is the fallback. */
|
||||
/* armed: open the actuator. Injection is ALWAYS uinput (orphaned host uinput + external
|
||||
* QEMU input-linux). PTR_BOTH gives both pointer forms a device (A=abs tablet, B=rel
|
||||
* mouse) — the contract now promises both MOVE_ABS and MOVE_REL, so neither may be
|
||||
* disabled. qmp_path serves the SERVICE power/lifecycle path, not input injection. */
|
||||
vmctl_config vcfg;
|
||||
memset(&vcfg, 0, sizeof vcfg);
|
||||
vcfg.driver = (a->driver == 1) ? VMCTL_DRIVER_UINPUT : VMCTL_DRIVER_QMP;
|
||||
vcfg.driver = VMCTL_DRIVER_UINPUT;
|
||||
vcfg.qmp_path = a->qmp_path;
|
||||
vcfg.input_bus = a->input_bus;
|
||||
vcfg.ptr_mode = a->ptr_mode;
|
||||
vcfg.input_bus = "";
|
||||
vcfg.ptr_mode = VMCTL_PTR_BOTH;
|
||||
vcfg.uinput_id = NULL; /* built-in HID identity defaults */
|
||||
a->vmctl = vmctl_open(&vcfg);
|
||||
if (!a->vmctl) { vmsig_worker_free(a->worker); a->worker = NULL; return -1; }
|
||||
@@ -141,6 +145,7 @@ static int in_on_ready(vmsig_adapter* a, uint32_t cookie, uint32_t events) {
|
||||
vmsig_worker_ack(a->worker);
|
||||
input_res rs; int rc;
|
||||
while (vmsig_worker_poll(a->worker, &rs, sizeof rs, &rc) == 1) {
|
||||
if (rs.noack) continue; /* fire-and-forget CMD_INPUT: actuated, emit no ACT_ACK */
|
||||
vmsig_event up;
|
||||
memset(&up, 0, sizeof up);
|
||||
up.kind = VMSIG_EV_ACT_ACK; up.source = VMSIG_SRC_INPUT; up.dir = VMSIG_DIR_UP;
|
||||
@@ -199,10 +204,13 @@ static int in_submit(vmsig_adapter* a, const vmsig_event* ev) {
|
||||
* held — that is the vmctl actuator's record (returned via CMD_QUERY_INPUT). */
|
||||
vmsig_input in;
|
||||
memcpy(&in, ev->inln, sizeof in <= sizeof ev->inln ? sizeof in : sizeof ev->inln);
|
||||
rq.kind = (int)in.kind;
|
||||
rq.code = (int)in.code;
|
||||
rq.value = (int)in.value;
|
||||
rq.kind = (int)in.kind;
|
||||
rq.code = (int)in.code;
|
||||
rq.value = (int)in.value;
|
||||
rq.x = (int)in.x;
|
||||
rq.y = (int)in.y;
|
||||
rq.scroll = in.scroll;
|
||||
rq.noack = (in.flags & VMSIG_INPUT_F_NOACK) ? 1 : 0;
|
||||
} else if (ev->kind == VMSIG_EV_CMD_LIFECYCLE) {
|
||||
rq.cmd = 1;
|
||||
rq.life_op = (int)(unsigned char)ev->inln[0];
|
||||
|
||||
Reference in New Issue
Block a user