mirror of
https://dev.lirent.ru/Vatrog/vm-control-io.git
synced 2026-06-18 02:36:37 +03:00
vmctl: input-control library over QMP and Linux uinput
QMP client and driver, Linux uinput driver, keymap, open/power helpers, public header, and CMake build.
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
/* qmp_driver.c — QMP input driver: serialises an input batch into a single
|
||||
* input-send-event command and sends it in one round-trip. No guest driver is
|
||||
* required. Switches on vmctl_ev_kind (never on magic numbers). */
|
||||
|
||||
#include "driver.h"
|
||||
#include "keymap.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static const char* btn_names[] = {
|
||||
"left", "right", "middle", "side", "extra", "forward", "back", "task"
|
||||
};
|
||||
#define BTN_NAMES_LEN ((int)(sizeof btn_names / sizeof btn_names[0]))
|
||||
|
||||
static int qmp_driver_send(vmctl_t* v, const vmctl_batch* b) {
|
||||
char json[8192];
|
||||
int pos = 0;
|
||||
|
||||
pos += snprintf(json + pos, (int)sizeof json - pos,
|
||||
"{\"execute\":\"input-send-event\",\"arguments\":{\"events\":[");
|
||||
|
||||
for (int i = 0; i < b->count; i++) {
|
||||
if (i > 0)
|
||||
pos += snprintf(json + pos, (int)sizeof json - pos, ",");
|
||||
|
||||
int code = b->ev[i].code;
|
||||
int value = b->ev[i].value;
|
||||
double scl = b->ev[i].scroll;
|
||||
|
||||
switch ((vmctl_ev_kind)b->ev[i].kind) {
|
||||
case VMCTL_EV_ABS:
|
||||
pos += snprintf(json + pos, (int)sizeof json - pos,
|
||||
"{\"type\":\"abs\",\"data\":{\"axis\":\"%s\",\"value\":%d}}",
|
||||
code == VMCTL_AXIS_X ? "x" : "y", value);
|
||||
break;
|
||||
case VMCTL_EV_REL:
|
||||
pos += snprintf(json + pos, (int)sizeof json - pos,
|
||||
"{\"type\":\"rel\",\"data\":{\"axis\":\"%s\",\"value\":%d}}",
|
||||
code == VMCTL_AXIS_X ? "x" : "y", value);
|
||||
break;
|
||||
case VMCTL_EV_BTN:
|
||||
if (code < 0 || code >= BTN_NAMES_LEN) return -1;
|
||||
pos += snprintf(json + pos, (int)sizeof json - pos,
|
||||
"{\"type\":\"btn\",\"data\":{\"button\":\"%s\",\"down\":%s}}",
|
||||
btn_names[code], value ? "true" : "false");
|
||||
break;
|
||||
case VMCTL_EV_KEY: {
|
||||
const char* qcode = vmctl_evdev_to_qcode(code);
|
||||
if (!qcode) return -1;
|
||||
pos += snprintf(json + pos, (int)sizeof json - pos,
|
||||
"{\"type\":\"key\",\"data\":{\"key\":{\"type\":\"qcode\","
|
||||
"\"data\":\"%s\"},\"down\":%s}}",
|
||||
qcode, value ? "true" : "false");
|
||||
break;
|
||||
}
|
||||
case VMCTL_EV_SCROLL:
|
||||
pos += snprintf(json + pos, (int)sizeof json - pos,
|
||||
"{\"type\":\"scl\",\"data\":{\"axis\":\"%s\",\"value\":%g}}",
|
||||
code == VMCTL_SCROLL_V ? "vertical" : "horizontal", scl);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
pos += snprintf(json + pos, (int)sizeof json - pos, "]}}");
|
||||
|
||||
char resp[4096];
|
||||
return qmp_exec(v->qmp, json, resp, sizeof resp);
|
||||
}
|
||||
|
||||
static void qmp_driver_close(vmctl_t* v) {
|
||||
qmp_disconnect(v->qmp);
|
||||
}
|
||||
|
||||
vmctl_t* vmctl_open_qmp_driver(const vmctl_config* cfg) {
|
||||
qmp_conn* qmp = qmp_connect(cfg->qmp_path);
|
||||
if (!qmp) return NULL;
|
||||
|
||||
vmctl_t* v = calloc(1, sizeof *v);
|
||||
if (!v) {
|
||||
qmp_disconnect(qmp);
|
||||
return NULL;
|
||||
}
|
||||
v->driver = VMCTL_DRIVER_QMP;
|
||||
v->qmp = qmp;
|
||||
v->ui_fd_a = -1;
|
||||
v->ui_fd_b = -1;
|
||||
v->ptr_mode = 0;
|
||||
v->ops.send = qmp_driver_send;
|
||||
v->ops.close = qmp_driver_close;
|
||||
return v;
|
||||
}
|
||||
Reference in New Issue
Block a user