mirror of
https://dev.lirent.ru/Vatrog/vm-control-io.git
synced 2026-07-09 01:26:37 +03:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
8c878b6d77
|
@@ -53,6 +53,9 @@ void vmctl_close(vmctl_t* v); /* safe on NULL */
|
||||
#define VMCTL_BTN_BACK 6
|
||||
#define VMCTL_BTN_TASK 7
|
||||
|
||||
#define VMCTL_KEY_CODE_MAX 0x2ff /* highest supported evdev key code (inclusive) */
|
||||
#define VMCTL_KEYS_SNAPSHOT_BYTES ((VMCTL_KEY_CODE_MAX + 1) / 8) /* bytes for vmctl_keys_snapshot */
|
||||
|
||||
/* ===== Event batch (value-type, stack; build ONLY via builders — ev[] is not API) ===== */
|
||||
#define VMCTL_BATCH_MAX 64
|
||||
typedef struct {
|
||||
@@ -78,6 +81,19 @@ int vmctl_btn (vmctl_t* v, int btn, int down); /* VMCTL_BTN_* */
|
||||
int vmctl_key (vmctl_t* v, int evdev_code, int down); /* Linux KEY_* */
|
||||
int vmctl_scroll(vmctl_t* v, int axis, double value); /* VMCTL_SCROLL_* */
|
||||
|
||||
/* ===== Held-state receipt (read-only) =====
|
||||
* "held" = key/button state as THIS handle last actuated it, not guest truth.
|
||||
* It is the actuator's record of its own last output (sensing the guest belongs
|
||||
* to the sensors layer, not here). Updated only after a successful send; the
|
||||
* send path NEVER reads this map (no dedup, no auto-release, no autorepeat). */
|
||||
|
||||
int vmctl_key_held (vmctl_t* v, int evdev_code); /* Linux KEY_*; 1=down 0=up */
|
||||
int vmctl_btn_held (vmctl_t* v, int btn); /* VMCTL_BTN_*; 1=down 0=up */
|
||||
int vmctl_keys_snapshot(vmctl_t* v, unsigned char* bits, size_t nbytes);
|
||||
/* copy key down-bits (EVIOCGKEY-style);
|
||||
returns bytes written, -1 on bad args */
|
||||
unsigned vmctl_btns_snapshot(vmctl_t* v); /* VMCTL_BTN_* down-bits as a mask (bits 0..7) */
|
||||
|
||||
/* ===== Power/lifecycle actuation (requires a QMP connection; -1 if there is none) ===== */
|
||||
int vmctl_powerdown(vmctl_t* v); /* system_powerdown (ACPI soft-off) */
|
||||
int vmctl_reset (vmctl_t* v); /* system_reset */
|
||||
|
||||
@@ -23,6 +23,13 @@ struct vmctl {
|
||||
int ui_fd_a; /* uinput driver: device A; -1 for QMP */
|
||||
int ui_fd_b; /* uinput driver: device B (BOTH); -1 */
|
||||
int ptr_mode; /* uinput driver: VMCTL_PTR_*; 0 for QMP */
|
||||
|
||||
/* Held-state receipt: key/btn down-bits as THIS handle last actuated them
|
||||
* (not guest truth). Written only after a successful send in
|
||||
* vmctl_batch_send; the send path never reads them. Zero-initialised by
|
||||
* calloc at open = all up. Single-threaded (one handle owner): no locks. */
|
||||
unsigned char keys_held[VMCTL_KEYS_SNAPSHOT_BYTES]; /* evdev-indexed key down-bits */
|
||||
unsigned btns_held; /* VMCTL_BTN_* 0..7 down-bits */
|
||||
};
|
||||
|
||||
/* driver factories (called from open.c per cfg->driver) */
|
||||
|
||||
+56
-1
@@ -6,6 +6,7 @@
|
||||
#include "driver.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
vmctl_t* vmctl_open(const vmctl_config* cfg) {
|
||||
if (!cfg) return NULL;
|
||||
@@ -60,7 +61,35 @@ void vmctl_batch_scroll(vmctl_batch* b, int axis, double value) {
|
||||
|
||||
int vmctl_batch_send(vmctl_t* v, vmctl_batch* b) {
|
||||
if (b->count == 0) return 0;
|
||||
return v->ops.send(v, b);
|
||||
int rc = v->ops.send(v, b);
|
||||
if (rc != 0) return rc; /* not sent = not recorded; never touch the receipt */
|
||||
|
||||
/* Record the actuated key/btn down-bits (write-only; the send path above
|
||||
* never reads this map). abs/rel/scroll have no held state. */
|
||||
for (int i = 0; i < b->count; i++) {
|
||||
const vmctl_event* e = &b->ev[i];
|
||||
int down = e->value ? 1 : 0;
|
||||
switch (e->kind) {
|
||||
case VMCTL_EV_KEY: {
|
||||
int code = e->code;
|
||||
if (code < 0 || code > VMCTL_KEY_CODE_MAX) break; /* out of range: ignore */
|
||||
unsigned char mask = (unsigned char)(1u << (code & 7));
|
||||
if (down) v->keys_held[code >> 3] |= mask;
|
||||
else v->keys_held[code >> 3] &= (unsigned char)~mask;
|
||||
break;
|
||||
}
|
||||
case VMCTL_EV_BTN: {
|
||||
int btn = e->code;
|
||||
if (btn < 0 || btn >= 8) break; /* out of range: ignore */
|
||||
unsigned mask = 1u << btn;
|
||||
if (down) v->btns_held |= mask;
|
||||
else v->btns_held &= ~mask;
|
||||
break;
|
||||
}
|
||||
default: break; /* abs/rel/scroll: no-op for receipt */
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* ===== Single-event wrappers ===== */
|
||||
@@ -99,3 +128,29 @@ int vmctl_scroll(vmctl_t* v, int axis, double value) {
|
||||
vmctl_batch_scroll(&b, axis, value);
|
||||
return vmctl_batch_send(v, &b);
|
||||
}
|
||||
|
||||
/* ===== Held-state receipt (read-only) =====
|
||||
* Reads of the actuator's own last output; never mutate driver state. The
|
||||
* in-range predicate matches the write path in vmctl_batch_send. */
|
||||
|
||||
int vmctl_key_held(vmctl_t* v, int evdev_code) {
|
||||
if (!v || evdev_code < 0 || evdev_code > VMCTL_KEY_CODE_MAX) return 0;
|
||||
return (v->keys_held[evdev_code >> 3] >> (evdev_code & 7)) & 1;
|
||||
}
|
||||
|
||||
int vmctl_btn_held(vmctl_t* v, int btn) {
|
||||
if (!v || btn < 0 || btn >= 8) return 0;
|
||||
return (int)((v->btns_held >> btn) & 1u);
|
||||
}
|
||||
|
||||
int vmctl_keys_snapshot(vmctl_t* v, unsigned char* bits, size_t nbytes) {
|
||||
if (!v || !bits) return -1;
|
||||
size_t n = nbytes < VMCTL_KEYS_SNAPSHOT_BYTES ? nbytes : VMCTL_KEYS_SNAPSHOT_BYTES;
|
||||
memcpy(bits, v->keys_held, n);
|
||||
return (int)n;
|
||||
}
|
||||
|
||||
unsigned vmctl_btns_snapshot(vmctl_t* v) {
|
||||
if (!v) return 0;
|
||||
return v->btns_held;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user