Files
vatrog-vm-control-io/src/vmctl/qmp_driver.c
T

95 lines
3.3 KiB
C
Raw Normal View History

/* 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;
}