diff options
Diffstat (limited to 'ui')
-rw-r--r-- | ui/Makefile.objs | 1 | ||||
-rw-r--r-- | ui/input-barrier.c | 750 | ||||
-rw-r--r-- | ui/input-barrier.h | 112 |
3 files changed, 863 insertions, 0 deletions
diff --git a/ui/Makefile.objs b/ui/Makefile.objs index ba39080..e6da6ff 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -9,6 +9,7 @@ vnc-obj-y += vnc-jobs.o common-obj-y += keymaps.o console.o cursor.o qemu-pixman.o common-obj-y += input.o input-keymap.o input-legacy.o kbd-state.o +common-obj-y += input-barrier.o common-obj-$(CONFIG_LINUX) += input-linux.o common-obj-$(CONFIG_SPICE) += spice-core.o spice-input.o spice-display.o common-obj-$(CONFIG_COCOA) += cocoa.o diff --git a/ui/input-barrier.c b/ui/input-barrier.c new file mode 100644 index 0000000..a2c961f --- /dev/null +++ b/ui/input-barrier.c @@ -0,0 +1,750 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "sysemu/sysemu.h" +#include "qemu/main-loop.h" +#include "qemu/sockets.h" +#include "qapi/error.h" +#include "qom/object_interfaces.h" +#include "io/channel-socket.h" +#include "ui/input.h" +#include "ui/vnc_keysym.h" /* use name2keysym from VNC as we use X11 values */ +#include "qemu/cutils.h" +#include "qapi/qmp/qerror.h" +#include "input-barrier.h" + +#define TYPE_INPUT_BARRIER "input-barrier" +#define INPUT_BARRIER(obj) \ + OBJECT_CHECK(InputBarrier, (obj), TYPE_INPUT_BARRIER) +#define INPUT_BARRIER_GET_CLASS(obj) \ + OBJECT_GET_CLASS(InputBarrierClass, (obj), TYPE_INPUT_BARRIER) +#define INPUT_BARRIER_CLASS(klass) \ + OBJECT_CLASS_CHECK(InputBarrierClass, (klass), TYPE_INPUT_BARRIER) + +typedef struct InputBarrier InputBarrier; +typedef struct InputBarrierClass InputBarrierClass; + +#define MAX_HELLO_LENGTH 1024 + +struct InputBarrier { + Object parent; + + QIOChannelSocket *sioc; + guint ioc_tag; + + /* display properties */ + gchar *name; + int16_t x_origin, y_origin; + int16_t width, height; + + /* keyboard/mouse server */ + + SocketAddress saddr; + + char buffer[MAX_HELLO_LENGTH]; +}; + +struct InputBarrierClass { + ObjectClass parent_class; +}; + +static const char *cmd_names[] = { + [barrierCmdCNoop] = "CNOP", + [barrierCmdCClose] = "CBYE", + [barrierCmdCEnter] = "CINN", + [barrierCmdCLeave] = "COUT", + [barrierCmdCClipboard] = "CCLP", + [barrierCmdCScreenSaver] = "CSEC", + [barrierCmdCResetOptions] = "CROP", + [barrierCmdCInfoAck] = "CIAK", + [barrierCmdCKeepAlive] = "CALV", + [barrierCmdDKeyDown] = "DKDN", + [barrierCmdDKeyRepeat] = "DKRP", + [barrierCmdDKeyUp] = "DKUP", + [barrierCmdDMouseDown] = "DMDN", + [barrierCmdDMouseUp] = "DMUP", + [barrierCmdDMouseMove] = "DMMV", + [barrierCmdDMouseRelMove] = "DMRM", + [barrierCmdDMouseWheel] = "DMWM", + [barrierCmdDClipboard] = "DCLP", + [barrierCmdDInfo] = "DINF", + [barrierCmdDSetOptions] = "DSOP", + [barrierCmdDFileTransfer] = "DFTR", + [barrierCmdDDragInfo] = "DDRG", + [barrierCmdQInfo] = "QINF", + [barrierCmdEIncompatible] = "EICV", + [barrierCmdEBusy] = "EBSY", + [barrierCmdEUnknown] = "EUNK", + [barrierCmdEBad] = "EBAD", + [barrierCmdHello] = "Barrier", + [barrierCmdHelloBack] = "Barrier", +}; + +static kbd_layout_t *kbd_layout; + +static int input_barrier_to_qcode(uint16_t keyid, uint16_t keycode) +{ + /* keycode is optional, if it is not provided use keyid */ + if (keycode && keycode <= qemu_input_map_xorgkbd_to_qcode_len) { + return qemu_input_map_xorgkbd_to_qcode[keycode]; + } + + if (keyid >= 0xE000 && keyid <= 0xEFFF) { + keyid += 0x1000; + } + + /* keyid is the X11 key id */ + if (kbd_layout) { + keycode = keysym2scancode(kbd_layout, keyid, NULL, false); + + return qemu_input_key_number_to_qcode(keycode); + } + + return qemu_input_map_x11_to_qcode[keyid]; +} + +static int input_barrier_to_mouse(uint8_t buttonid) +{ + switch (buttonid) { + case barrierButtonLeft: + return INPUT_BUTTON_LEFT; + case barrierButtonMiddle: + return INPUT_BUTTON_MIDDLE; + case barrierButtonRight: + return INPUT_BUTTON_RIGHT; + case barrierButtonExtra0: + return INPUT_BUTTON_SIDE; + } + return buttonid; +} + +#define read_char(x, p, l) \ +do { \ + int size = sizeof(char); \ + if (l < size) { \ + return G_SOURCE_REMOVE; \ + } \ + x = *(char *)p; \ + p += size; \ + l -= size; \ +} while (0) + +#define read_short(x, p, l) \ +do { \ + int size = sizeof(short); \ + if (l < size) { \ + return G_SOURCE_REMOVE; \ + } \ + x = ntohs(*(short *)p); \ + p += size; \ + l -= size; \ +} while (0) + +#define write_short(p, x, l) \ +do { \ + int size = sizeof(short); \ + if (l < size) { \ + return G_SOURCE_REMOVE; \ + } \ + *(short *)p = htons(x); \ + p += size; \ + l -= size; \ +} while (0) + +#define read_int(x, p, l) \ +do { \ + int size = sizeof(int); \ + if (l < size) { \ + return G_SOURCE_REMOVE; \ + } \ + x = ntohl(*(int *)p); \ + p += size; \ + l -= size; \ +} while (0) + +#define write_int(p, x, l) \ +do { \ + int size = sizeof(int); \ + if (l < size) { \ + return G_SOURCE_REMOVE; \ + } \ + *(int *)p = htonl(x); \ + p += size; \ + l -= size; \ +} while (0) + +#define write_cmd(p, c, l) \ +do { \ + int size = strlen(cmd_names[c]); \ + if (l < size) { \ + return G_SOURCE_REMOVE; \ + } \ + memcpy(p, cmd_names[c], size); \ + p += size; \ + l -= size; \ +} while (0) + +#define write_string(p, s, l) \ +do { \ + int size = strlen(s); \ + if (l < size + sizeof(int)) { \ + return G_SOURCE_REMOVE; \ + } \ + *(int *)p = htonl(size); \ + p += sizeof(size); \ + l -= sizeof(size); \ + memcpy(p, s, size); \ + p += size; \ + l -= size; \ +} while (0) + +static gboolean readcmd(InputBarrier *ib, struct barrierMsg *msg) +{ + int ret, len, i; + enum barrierCmd cmd; + char *p; + + ret = qio_channel_read(QIO_CHANNEL(ib->sioc), (char *)&len, sizeof(len), + NULL); + if (ret < 0) { + return G_SOURCE_REMOVE; + } + + len = ntohl(len); + if (len > MAX_HELLO_LENGTH) { + return G_SOURCE_REMOVE; + } + + ret = qio_channel_read(QIO_CHANNEL(ib->sioc), ib->buffer, len, NULL); + if (ret < 0) { + return G_SOURCE_REMOVE; + } + + p = ib->buffer; + if (len >= strlen(cmd_names[barrierCmdHello]) && + memcmp(p, cmd_names[barrierCmdHello], + strlen(cmd_names[barrierCmdHello])) == 0) { + cmd = barrierCmdHello; + p += strlen(cmd_names[barrierCmdHello]); + len -= strlen(cmd_names[barrierCmdHello]); + } else { + for (cmd = 0; cmd < barrierCmdHello; cmd++) { + if (memcmp(ib->buffer, cmd_names[cmd], 4) == 0) { + break; + } + } + + if (cmd == barrierCmdHello) { + return G_SOURCE_REMOVE; + } + p += 4; + len -= 4; + } + + msg->cmd = cmd; + switch (cmd) { + /* connection */ + case barrierCmdHello: + read_short(msg->version.major, p, len); + read_short(msg->version.minor, p, len); + break; + case barrierCmdDSetOptions: + read_int(msg->set.nb, p, len); + msg->set.nb /= 2; + if (msg->set.nb > BARRIER_MAX_OPTIONS) { + msg->set.nb = BARRIER_MAX_OPTIONS; + } + i = 0; + while (len && i < msg->set.nb) { + read_int(msg->set.option[i].id, p, len); + /* it's a string, restore endianness */ + msg->set.option[i].id = htonl(msg->set.option[i].id); + msg->set.option[i].nul = 0; + read_int(msg->set.option[i].value, p, len); + i++; + } + break; + case barrierCmdQInfo: + break; + + /* mouse */ + case barrierCmdDMouseMove: + case barrierCmdDMouseRelMove: + read_short(msg->mousepos.x, p, len); + read_short(msg->mousepos.y, p, len); + break; + case barrierCmdDMouseDown: + case barrierCmdDMouseUp: + read_char(msg->mousebutton.buttonid, p, len); + break; + case barrierCmdDMouseWheel: + read_short(msg->mousepos.y, p, len); + msg->mousepos.x = 0; + if (len) { + msg->mousepos.x = msg->mousepos.y; + read_short(msg->mousepos.y, p, len); + } + break; + + /* keyboard */ + case barrierCmdDKeyDown: + case barrierCmdDKeyUp: + read_short(msg->key.keyid, p, len); + read_short(msg->key.modifier, p, len); + msg->key.button = 0; + if (len) { + read_short(msg->key.button, p, len); + } + break; + case barrierCmdDKeyRepeat: + read_short(msg->repeat.keyid, p, len); + read_short(msg->repeat.modifier, p, len); + read_short(msg->repeat.repeat, p, len); + msg->repeat.button = 0; + if (len) { + read_short(msg->repeat.button, p, len); + } + break; + case barrierCmdCInfoAck: + case barrierCmdCResetOptions: + case barrierCmdCEnter: + case barrierCmdDClipboard: + case barrierCmdCKeepAlive: + case barrierCmdCLeave: + case barrierCmdCClose: + break; + + /* Invalid from the server */ + case barrierCmdHelloBack: + case barrierCmdCNoop: + case barrierCmdDInfo: + break; + + /* Error codes */ + case barrierCmdEIncompatible: + read_short(msg->version.major, p, len); + read_short(msg->version.minor, p, len); + break; + case barrierCmdEBusy: + case barrierCmdEUnknown: + case barrierCmdEBad: + break; + default: + return G_SOURCE_REMOVE; + } + + return G_SOURCE_CONTINUE; +} + +static gboolean writecmd(InputBarrier *ib, struct barrierMsg *msg) +{ + char *p; + int ret, i; + int avail, len; + + p = ib->buffer; + avail = MAX_HELLO_LENGTH; + + /* reserve space to store the length */ + p += sizeof(int); + avail -= sizeof(int); + + switch (msg->cmd) { + case barrierCmdHello: + if (msg->version.major < BARRIER_VERSION_MAJOR || + (msg->version.major == BARRIER_VERSION_MAJOR && + msg->version.minor < BARRIER_VERSION_MINOR)) { + ib->ioc_tag = 0; + return G_SOURCE_REMOVE; + } + write_cmd(p, barrierCmdHelloBack, avail); + write_short(p, BARRIER_VERSION_MAJOR, avail); + write_short(p, BARRIER_VERSION_MINOR, avail); + write_string(p, ib->name, avail); + break; + case barrierCmdCClose: + ib->ioc_tag = 0; + return G_SOURCE_REMOVE; + case barrierCmdQInfo: + write_cmd(p, barrierCmdDInfo, avail); + write_short(p, ib->x_origin, avail); + write_short(p, ib->y_origin, avail); + write_short(p, ib->width, avail); + write_short(p, ib->height, avail); + write_short(p, 0, avail); /* warpsize (obsolete) */ + write_short(p, 0, avail); /* mouse x */ + write_short(p, 0, avail); /* mouse y */ + break; + case barrierCmdCInfoAck: + break; + case barrierCmdCResetOptions: + /* TODO: reset options */ + break; + case barrierCmdDSetOptions: + /* TODO: set options */ + break; + case barrierCmdCEnter: + break; + case barrierCmdDClipboard: + break; + case barrierCmdCKeepAlive: + write_cmd(p, barrierCmdCKeepAlive, avail); + break; + case barrierCmdCLeave: + break; + + /* mouse */ + case barrierCmdDMouseMove: + qemu_input_queue_abs(NULL, INPUT_AXIS_X, msg->mousepos.x, + ib->x_origin, ib->width); + qemu_input_queue_abs(NULL, INPUT_AXIS_Y, msg->mousepos.y, + ib->y_origin, ib->height); + qemu_input_event_sync(); + break; + case barrierCmdDMouseRelMove: + qemu_input_queue_rel(NULL, INPUT_AXIS_X, msg->mousepos.x); + qemu_input_queue_rel(NULL, INPUT_AXIS_Y, msg->mousepos.y); + qemu_input_event_sync(); + break; + case barrierCmdDMouseDown: + qemu_input_queue_btn(NULL, + input_barrier_to_mouse(msg->mousebutton.buttonid), + true); + qemu_input_event_sync(); + break; + case barrierCmdDMouseUp: + qemu_input_queue_btn(NULL, + input_barrier_to_mouse(msg->mousebutton.buttonid), + false); + qemu_input_event_sync(); + break; + case barrierCmdDMouseWheel: + qemu_input_queue_btn(NULL, (msg->mousepos.y > 0) ? INPUT_BUTTON_WHEEL_UP + : INPUT_BUTTON_WHEEL_DOWN, true); + qemu_input_event_sync(); + qemu_input_queue_btn(NULL, (msg->mousepos.y > 0) ? INPUT_BUTTON_WHEEL_UP + : INPUT_BUTTON_WHEEL_DOWN, false); + qemu_input_event_sync(); + break; + + /* keyboard */ + case barrierCmdDKeyDown: + qemu_input_event_send_key_qcode(NULL, + input_barrier_to_qcode(msg->key.keyid, msg->key.button), + true); + break; + case barrierCmdDKeyRepeat: + for (i = 0; i < msg->repeat.repeat; i++) { + qemu_input_event_send_key_qcode(NULL, + input_barrier_to_qcode(msg->repeat.keyid, msg->repeat.button), + false); + qemu_input_event_send_key_qcode(NULL, + input_barrier_to_qcode(msg->repeat.keyid, msg->repeat.button), + true); + } + break; + case barrierCmdDKeyUp: + qemu_input_event_send_key_qcode(NULL, + input_barrier_to_qcode(msg->key.keyid, msg->key.button), + false); + break; + default: + write_cmd(p, barrierCmdEUnknown, avail); + break;; + } + + len = MAX_HELLO_LENGTH - avail - sizeof(int); + if (len) { + p = ib->buffer; + avail = sizeof(len); + write_int(p, len, avail); + ret = qio_channel_write(QIO_CHANNEL(ib->sioc), ib->buffer, + len + sizeof(len), NULL); + if (ret < 0) { + ib->ioc_tag = 0; + return G_SOURCE_REMOVE; + } + } + + return G_SOURCE_CONTINUE; +} + +static gboolean input_barrier_event(QIOChannel *ioc G_GNUC_UNUSED, + GIOCondition condition, void *opaque) +{ + InputBarrier *ib = opaque; + int ret; + struct barrierMsg msg; + + ret = readcmd(ib, &msg); + if (ret == G_SOURCE_REMOVE) { + ib->ioc_tag = 0; + return G_SOURCE_REMOVE; + } + + return writecmd(ib, &msg); +} + +static void input_barrier_complete(UserCreatable *uc, Error **errp) +{ + InputBarrier *ib = INPUT_BARRIER(uc); + Error *local_err = NULL; + + if (!ib->name) { + error_setg(errp, QERR_MISSING_PARAMETER, "name"); + return; + } + + /* + * Connect to the primary + * Primary is the server where the keyboard and the mouse + * are connected and forwarded to the secondary (the client) + */ + + ib->sioc = qio_channel_socket_new(); + qio_channel_set_name(QIO_CHANNEL(ib->sioc), "barrier-client"); + + qio_channel_socket_connect_sync(ib->sioc, &ib->saddr, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + qio_channel_set_delay(QIO_CHANNEL(ib->sioc), false); + + ib->ioc_tag = qio_channel_add_watch(QIO_CHANNEL(ib->sioc), G_IO_IN, + input_barrier_event, ib, NULL); +} + +static void input_barrier_instance_finalize(Object *obj) +{ + InputBarrier *ib = INPUT_BARRIER(obj); + + if (ib->ioc_tag) { + g_source_remove(ib->ioc_tag); + ib->ioc_tag = 0; + } + + if (ib->sioc) { + qio_channel_close(QIO_CHANNEL(ib->sioc), NULL); + object_unref(OBJECT(ib->sioc)); + } + g_free(ib->name); + g_free(ib->saddr.u.inet.host); + g_free(ib->saddr.u.inet.port); +} + +static char *input_barrier_get_name(Object *obj, Error **errp) +{ + InputBarrier *ib = INPUT_BARRIER(obj); + + return g_strdup(ib->name); +} + +static void input_barrier_set_name(Object *obj, const char *value, + Error **errp) +{ + InputBarrier *ib = INPUT_BARRIER(obj); + + if (ib->name) { + error_setg(errp, "name property already set"); + return; + } + ib->name = g_strdup(value); +} + +static char *input_barrier_get_server(Object *obj, Error **errp) +{ + InputBarrier *ib = INPUT_BARRIER(obj); + + return g_strdup(ib->saddr.u.inet.host); +} + +static void input_barrier_set_server(Object *obj, const char *value, + Error **errp) +{ + InputBarrier *ib = INPUT_BARRIER(obj); + + g_free(ib->saddr.u.inet.host); + ib->saddr.u.inet.host = g_strdup(value); +} + +static char *input_barrier_get_port(Object *obj, Error **errp) +{ + InputBarrier *ib = INPUT_BARRIER(obj); + + return g_strdup(ib->saddr.u.inet.port); +} + +static void input_barrier_set_port(Object *obj, const char *value, + Error **errp) +{ + InputBarrier *ib = INPUT_BARRIER(obj); + + g_free(ib->saddr.u.inet.port); + ib->saddr.u.inet.port = g_strdup(value); +} + +static void input_barrier_set_x_origin(Object *obj, const char *value, + Error **errp) +{ + InputBarrier *ib = INPUT_BARRIER(obj); + int result, err; + + err = qemu_strtoi(value, NULL, 0, &result); + if (err < 0 || result < 0 || result > SHRT_MAX) { + error_setg(errp, + "x-origin property must be in the range [0..%d]", SHRT_MAX); + return; + } + ib->x_origin = result; +} + +static char *input_barrier_get_x_origin(Object *obj, Error **errp) +{ + InputBarrier *ib = INPUT_BARRIER(obj); + + return g_strdup_printf("%d", ib->x_origin); +} + +static void input_barrier_set_y_origin(Object *obj, const char *value, + Error **errp) +{ + InputBarrier *ib = INPUT_BARRIER(obj); + int result, err; + + err = qemu_strtoi(value, NULL, 0, &result); + if (err < 0 || result < 0 || result > SHRT_MAX) { + error_setg(errp, + "y-origin property must be in the range [0..%d]", SHRT_MAX); + return; + } + ib->y_origin = result; +} + +static char *input_barrier_get_y_origin(Object *obj, Error **errp) +{ + InputBarrier *ib = INPUT_BARRIER(obj); + + return g_strdup_printf("%d", ib->y_origin); +} + +static void input_barrier_set_width(Object *obj, const char *value, + Error **errp) +{ + InputBarrier *ib = INPUT_BARRIER(obj); + int result, err; + + err = qemu_strtoi(value, NULL, 0, &result); + if (err < 0 || result < 0 || result > SHRT_MAX) { + error_setg(errp, + "width property must be in the range [0..%d]", SHRT_MAX); + return; + } + ib->width = result; +} + +static char *input_barrier_get_width(Object *obj, Error **errp) +{ + InputBarrier *ib = INPUT_BARRIER(obj); + + return g_strdup_printf("%d", ib->width); +} + +static void input_barrier_set_height(Object *obj, const char *value, + Error **errp) +{ + InputBarrier *ib = INPUT_BARRIER(obj); + int result, err; + + err = qemu_strtoi(value, NULL, 0, &result); + if (err < 0 || result < 0 || result > SHRT_MAX) { + error_setg(errp, + "height property must be in the range [0..%d]", SHRT_MAX); + return; + } + ib->height = result; +} + +static char *input_barrier_get_height(Object *obj, Error **errp) +{ + InputBarrier *ib = INPUT_BARRIER(obj); + + return g_strdup_printf("%d", ib->height); +} + +static void input_barrier_instance_init(Object *obj) +{ + InputBarrier *ib = INPUT_BARRIER(obj); + + ib->saddr.type = SOCKET_ADDRESS_TYPE_INET; + ib->saddr.u.inet.host = g_strdup("localhost"); + ib->saddr.u.inet.port = g_strdup("24800"); + + ib->x_origin = 0; + ib->y_origin = 0; + ib->width = 1920; + ib->height = 1080; + + object_property_add_str(obj, "name", + input_barrier_get_name, + input_barrier_set_name, NULL); + object_property_add_str(obj, "server", + input_barrier_get_server, + input_barrier_set_server, NULL); + object_property_add_str(obj, "port", + input_barrier_get_port, + input_barrier_set_port, NULL); + object_property_add_str(obj, "x-origin", + input_barrier_get_x_origin, + input_barrier_set_x_origin, NULL); + object_property_add_str(obj, "y-origin", + input_barrier_get_y_origin, + input_barrier_set_y_origin, NULL); + object_property_add_str(obj, "width", + input_barrier_get_width, + input_barrier_set_width, NULL); + object_property_add_str(obj, "height", + input_barrier_get_height, + input_barrier_set_height, NULL); +} + +static void input_barrier_class_init(ObjectClass *oc, void *data) +{ + UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); + + ucc->complete = input_barrier_complete; + + /* always use generic keymaps */ + if (keyboard_layout) { + /* We use X11 key id, so use VNC name2keysym */ + kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout, + &error_fatal); + } +} + +static const TypeInfo input_barrier_info = { + .name = TYPE_INPUT_BARRIER, + .parent = TYPE_OBJECT, + .class_size = sizeof(InputBarrierClass), + .class_init = input_barrier_class_init, + .instance_size = sizeof(InputBarrier), + .instance_init = input_barrier_instance_init, + .instance_finalize = input_barrier_instance_finalize, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + +static void register_types(void) +{ + type_register_static(&input_barrier_info); +} + +type_init(register_types); diff --git a/ui/input-barrier.h b/ui/input-barrier.h new file mode 100644 index 0000000..e5b0905 --- /dev/null +++ b/ui/input-barrier.h @@ -0,0 +1,112 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef UI_INPUT_BARRIER_H +#define UI_INPUT_BARRIER_H + +/* Barrier protocol */ +#define BARRIER_VERSION_MAJOR 1 +#define BARRIER_VERSION_MINOR 6 + +enum barrierCmd { + barrierCmdCNoop, + barrierCmdCClose, + barrierCmdCEnter, + barrierCmdCLeave, + barrierCmdCClipboard, + barrierCmdCScreenSaver, + barrierCmdCResetOptions, + barrierCmdCInfoAck, + barrierCmdCKeepAlive, + barrierCmdDKeyDown, + barrierCmdDKeyRepeat, + barrierCmdDKeyUp, + barrierCmdDMouseDown, + barrierCmdDMouseUp, + barrierCmdDMouseMove, + barrierCmdDMouseRelMove, + barrierCmdDMouseWheel, + barrierCmdDClipboard, + barrierCmdDInfo, + barrierCmdDSetOptions, + barrierCmdDFileTransfer, + barrierCmdDDragInfo, + barrierCmdQInfo, + barrierCmdEIncompatible, + barrierCmdEBusy, + barrierCmdEUnknown, + barrierCmdEBad, + /* connection sequence */ + barrierCmdHello, + barrierCmdHelloBack, +}; + +enum { + barrierButtonNone, + barrierButtonLeft, + barrierButtonMiddle, + barrierButtonRight, + barrierButtonExtra0 +}; + +struct barrierVersion { + int16_t major; + int16_t minor; +}; + +struct barrierMouseButton { + int8_t buttonid; +}; + +struct barrierEnter { + int16_t x; + int16_t y; + int32_t seqn; + int16_t modifier; +}; + +struct barrierMousePos { + int16_t x; + int16_t y; +}; + +struct barrierKey { + int16_t keyid; + int16_t modifier; + int16_t button; +}; + +struct barrierRepeat { + int16_t keyid; + int16_t modifier; + int16_t repeat; + int16_t button; +}; + +#define BARRIER_MAX_OPTIONS 32 +struct barrierSet { + int nb; + struct { + int id; + char nul; + int value; + } option[BARRIER_MAX_OPTIONS]; +}; + +struct barrierMsg { + enum barrierCmd cmd; + union { + struct barrierVersion version; + struct barrierMouseButton mousebutton; + struct barrierMousePos mousepos; + struct barrierEnter enter; + struct barrierKey key; + struct barrierRepeat repeat; + struct barrierSet set; + }; +}; +#endif |