mirror of
https://dev.lirent.ru/Vatrog/vm-control-io.git
synced 2026-06-18 00:26:38 +03:00
9b75494380
QMP client and driver, Linux uinput driver, keymap, open/power helpers, public header, and CMake build.
95 lines
3.3 KiB
C
95 lines
3.3 KiB
C
/* 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;
|
|
}
|