16105683dSLaurent Vivier /*
26105683dSLaurent Vivier * SPDX-License-Identifier: GPL-2.0-or-later
36105683dSLaurent Vivier *
46105683dSLaurent Vivier * This work is licensed under the terms of the GNU GPL, version 2 or later.
56105683dSLaurent Vivier * See the COPYING file in the top-level directory.
6*399a0477SPeter Maydell *
7*399a0477SPeter Maydell * TODO:
8*399a0477SPeter Maydell *
9*399a0477SPeter Maydell * - Enable SSL
10*399a0477SPeter Maydell * - Manage SetOptions/ResetOptions commands
116105683dSLaurent Vivier */
126105683dSLaurent Vivier
136105683dSLaurent Vivier #include "qemu/osdep.h"
146105683dSLaurent Vivier #include "sysemu/sysemu.h"
156105683dSLaurent Vivier #include "qemu/main-loop.h"
166105683dSLaurent Vivier #include "qemu/sockets.h"
176105683dSLaurent Vivier #include "qapi/error.h"
186105683dSLaurent Vivier #include "qom/object_interfaces.h"
196105683dSLaurent Vivier #include "io/channel-socket.h"
206105683dSLaurent Vivier #include "ui/input.h"
21db1015e9SEduardo Habkost #include "qom/object.h"
226105683dSLaurent Vivier #include "ui/vnc_keysym.h" /* use name2keysym from VNC as we use X11 values */
236105683dSLaurent Vivier #include "qemu/cutils.h"
246105683dSLaurent Vivier #include "qapi/qmp/qerror.h"
256105683dSLaurent Vivier #include "input-barrier.h"
266105683dSLaurent Vivier
276105683dSLaurent Vivier #define TYPE_INPUT_BARRIER "input-barrier"
2830b5707cSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(InputBarrier,
29c734cd40SEduardo Habkost INPUT_BARRIER)
306105683dSLaurent Vivier
316105683dSLaurent Vivier
326105683dSLaurent Vivier #define MAX_HELLO_LENGTH 1024
336105683dSLaurent Vivier
346105683dSLaurent Vivier struct InputBarrier {
356105683dSLaurent Vivier Object parent;
366105683dSLaurent Vivier
376105683dSLaurent Vivier QIOChannelSocket *sioc;
386105683dSLaurent Vivier guint ioc_tag;
396105683dSLaurent Vivier
406105683dSLaurent Vivier /* display properties */
416105683dSLaurent Vivier gchar *name;
426105683dSLaurent Vivier int16_t x_origin, y_origin;
436105683dSLaurent Vivier int16_t width, height;
446105683dSLaurent Vivier
456105683dSLaurent Vivier /* keyboard/mouse server */
466105683dSLaurent Vivier
476105683dSLaurent Vivier SocketAddress saddr;
486105683dSLaurent Vivier
496105683dSLaurent Vivier char buffer[MAX_HELLO_LENGTH];
506105683dSLaurent Vivier };
516105683dSLaurent Vivier
526105683dSLaurent Vivier
536105683dSLaurent Vivier static const char *cmd_names[] = {
546105683dSLaurent Vivier [barrierCmdCNoop] = "CNOP",
556105683dSLaurent Vivier [barrierCmdCClose] = "CBYE",
566105683dSLaurent Vivier [barrierCmdCEnter] = "CINN",
576105683dSLaurent Vivier [barrierCmdCLeave] = "COUT",
586105683dSLaurent Vivier [barrierCmdCClipboard] = "CCLP",
596105683dSLaurent Vivier [barrierCmdCScreenSaver] = "CSEC",
606105683dSLaurent Vivier [barrierCmdCResetOptions] = "CROP",
616105683dSLaurent Vivier [barrierCmdCInfoAck] = "CIAK",
626105683dSLaurent Vivier [barrierCmdCKeepAlive] = "CALV",
636105683dSLaurent Vivier [barrierCmdDKeyDown] = "DKDN",
646105683dSLaurent Vivier [barrierCmdDKeyRepeat] = "DKRP",
656105683dSLaurent Vivier [barrierCmdDKeyUp] = "DKUP",
666105683dSLaurent Vivier [barrierCmdDMouseDown] = "DMDN",
676105683dSLaurent Vivier [barrierCmdDMouseUp] = "DMUP",
686105683dSLaurent Vivier [barrierCmdDMouseMove] = "DMMV",
696105683dSLaurent Vivier [barrierCmdDMouseRelMove] = "DMRM",
706105683dSLaurent Vivier [barrierCmdDMouseWheel] = "DMWM",
716105683dSLaurent Vivier [barrierCmdDClipboard] = "DCLP",
726105683dSLaurent Vivier [barrierCmdDInfo] = "DINF",
736105683dSLaurent Vivier [barrierCmdDSetOptions] = "DSOP",
746105683dSLaurent Vivier [barrierCmdDFileTransfer] = "DFTR",
756105683dSLaurent Vivier [barrierCmdDDragInfo] = "DDRG",
766105683dSLaurent Vivier [barrierCmdQInfo] = "QINF",
776105683dSLaurent Vivier [barrierCmdEIncompatible] = "EICV",
786105683dSLaurent Vivier [barrierCmdEBusy] = "EBSY",
796105683dSLaurent Vivier [barrierCmdEUnknown] = "EUNK",
806105683dSLaurent Vivier [barrierCmdEBad] = "EBAD",
816105683dSLaurent Vivier [barrierCmdHello] = "Barrier",
826105683dSLaurent Vivier [barrierCmdHelloBack] = "Barrier",
836105683dSLaurent Vivier };
846105683dSLaurent Vivier
856105683dSLaurent Vivier static kbd_layout_t *kbd_layout;
866105683dSLaurent Vivier
input_barrier_to_qcode(uint16_t keyid,uint16_t keycode)876105683dSLaurent Vivier static int input_barrier_to_qcode(uint16_t keyid, uint16_t keycode)
886105683dSLaurent Vivier {
896105683dSLaurent Vivier /* keycode is optional, if it is not provided use keyid */
906105683dSLaurent Vivier if (keycode && keycode <= qemu_input_map_xorgkbd_to_qcode_len) {
916105683dSLaurent Vivier return qemu_input_map_xorgkbd_to_qcode[keycode];
926105683dSLaurent Vivier }
936105683dSLaurent Vivier
946105683dSLaurent Vivier if (keyid >= 0xE000 && keyid <= 0xEFFF) {
956105683dSLaurent Vivier keyid += 0x1000;
966105683dSLaurent Vivier }
976105683dSLaurent Vivier
986105683dSLaurent Vivier /* keyid is the X11 key id */
996105683dSLaurent Vivier if (kbd_layout) {
1006105683dSLaurent Vivier keycode = keysym2scancode(kbd_layout, keyid, NULL, false);
1016105683dSLaurent Vivier
1026105683dSLaurent Vivier return qemu_input_key_number_to_qcode(keycode);
1036105683dSLaurent Vivier }
1046105683dSLaurent Vivier
1056105683dSLaurent Vivier return qemu_input_map_x11_to_qcode[keyid];
1066105683dSLaurent Vivier }
1076105683dSLaurent Vivier
input_barrier_to_mouse(uint8_t buttonid)1086105683dSLaurent Vivier static int input_barrier_to_mouse(uint8_t buttonid)
1096105683dSLaurent Vivier {
1106105683dSLaurent Vivier switch (buttonid) {
1116105683dSLaurent Vivier case barrierButtonLeft:
1126105683dSLaurent Vivier return INPUT_BUTTON_LEFT;
1136105683dSLaurent Vivier case barrierButtonMiddle:
1146105683dSLaurent Vivier return INPUT_BUTTON_MIDDLE;
1156105683dSLaurent Vivier case barrierButtonRight:
1166105683dSLaurent Vivier return INPUT_BUTTON_RIGHT;
1176105683dSLaurent Vivier case barrierButtonExtra0:
1186105683dSLaurent Vivier return INPUT_BUTTON_SIDE;
1196105683dSLaurent Vivier }
1206105683dSLaurent Vivier return buttonid;
1216105683dSLaurent Vivier }
1226105683dSLaurent Vivier
1236105683dSLaurent Vivier #define read_char(x, p, l) \
1246105683dSLaurent Vivier do { \
1256105683dSLaurent Vivier int size = sizeof(char); \
1266105683dSLaurent Vivier if (l < size) { \
1276105683dSLaurent Vivier return G_SOURCE_REMOVE; \
1286105683dSLaurent Vivier } \
1296105683dSLaurent Vivier x = *(char *)p; \
1306105683dSLaurent Vivier p += size; \
1316105683dSLaurent Vivier l -= size; \
1326105683dSLaurent Vivier } while (0)
1336105683dSLaurent Vivier
1346105683dSLaurent Vivier #define read_short(x, p, l) \
1356105683dSLaurent Vivier do { \
1366105683dSLaurent Vivier int size = sizeof(short); \
1376105683dSLaurent Vivier if (l < size) { \
1386105683dSLaurent Vivier return G_SOURCE_REMOVE; \
1396105683dSLaurent Vivier } \
1406105683dSLaurent Vivier x = ntohs(*(short *)p); \
1416105683dSLaurent Vivier p += size; \
1426105683dSLaurent Vivier l -= size; \
1436105683dSLaurent Vivier } while (0)
1446105683dSLaurent Vivier
1456105683dSLaurent Vivier #define write_short(p, x, l) \
1466105683dSLaurent Vivier do { \
1476105683dSLaurent Vivier int size = sizeof(short); \
1486105683dSLaurent Vivier if (l < size) { \
1496105683dSLaurent Vivier return G_SOURCE_REMOVE; \
1506105683dSLaurent Vivier } \
1516105683dSLaurent Vivier *(short *)p = htons(x); \
1526105683dSLaurent Vivier p += size; \
1536105683dSLaurent Vivier l -= size; \
1546105683dSLaurent Vivier } while (0)
1556105683dSLaurent Vivier
1566105683dSLaurent Vivier #define read_int(x, p, l) \
1576105683dSLaurent Vivier do { \
1586105683dSLaurent Vivier int size = sizeof(int); \
1596105683dSLaurent Vivier if (l < size) { \
1606105683dSLaurent Vivier return G_SOURCE_REMOVE; \
1616105683dSLaurent Vivier } \
1626105683dSLaurent Vivier x = ntohl(*(int *)p); \
1636105683dSLaurent Vivier p += size; \
1646105683dSLaurent Vivier l -= size; \
1656105683dSLaurent Vivier } while (0)
1666105683dSLaurent Vivier
1676105683dSLaurent Vivier #define write_int(p, x, l) \
1686105683dSLaurent Vivier do { \
1696105683dSLaurent Vivier int size = sizeof(int); \
1706105683dSLaurent Vivier if (l < size) { \
1716105683dSLaurent Vivier return G_SOURCE_REMOVE; \
1726105683dSLaurent Vivier } \
1736105683dSLaurent Vivier *(int *)p = htonl(x); \
1746105683dSLaurent Vivier p += size; \
1756105683dSLaurent Vivier l -= size; \
1766105683dSLaurent Vivier } while (0)
1776105683dSLaurent Vivier
1786105683dSLaurent Vivier #define write_cmd(p, c, l) \
1796105683dSLaurent Vivier do { \
1806105683dSLaurent Vivier int size = strlen(cmd_names[c]); \
1816105683dSLaurent Vivier if (l < size) { \
1826105683dSLaurent Vivier return G_SOURCE_REMOVE; \
1836105683dSLaurent Vivier } \
1846105683dSLaurent Vivier memcpy(p, cmd_names[c], size); \
1856105683dSLaurent Vivier p += size; \
1866105683dSLaurent Vivier l -= size; \
1876105683dSLaurent Vivier } while (0)
1886105683dSLaurent Vivier
1896105683dSLaurent Vivier #define write_string(p, s, l) \
1906105683dSLaurent Vivier do { \
1916105683dSLaurent Vivier int size = strlen(s); \
1926105683dSLaurent Vivier if (l < size + sizeof(int)) { \
1936105683dSLaurent Vivier return G_SOURCE_REMOVE; \
1946105683dSLaurent Vivier } \
1956105683dSLaurent Vivier *(int *)p = htonl(size); \
1966105683dSLaurent Vivier p += sizeof(size); \
1976105683dSLaurent Vivier l -= sizeof(size); \
1986105683dSLaurent Vivier memcpy(p, s, size); \
1996105683dSLaurent Vivier p += size; \
2006105683dSLaurent Vivier l -= size; \
2016105683dSLaurent Vivier } while (0)
2026105683dSLaurent Vivier
readcmd(InputBarrier * ib,struct barrierMsg * msg)2036105683dSLaurent Vivier static gboolean readcmd(InputBarrier *ib, struct barrierMsg *msg)
2046105683dSLaurent Vivier {
2056105683dSLaurent Vivier int ret, len, i;
2066105683dSLaurent Vivier enum barrierCmd cmd;
2076105683dSLaurent Vivier char *p;
2086105683dSLaurent Vivier
2096105683dSLaurent Vivier ret = qio_channel_read(QIO_CHANNEL(ib->sioc), (char *)&len, sizeof(len),
2106105683dSLaurent Vivier NULL);
2116105683dSLaurent Vivier if (ret < 0) {
2126105683dSLaurent Vivier return G_SOURCE_REMOVE;
2136105683dSLaurent Vivier }
2146105683dSLaurent Vivier
2156105683dSLaurent Vivier len = ntohl(len);
2166105683dSLaurent Vivier if (len > MAX_HELLO_LENGTH) {
2176105683dSLaurent Vivier return G_SOURCE_REMOVE;
2186105683dSLaurent Vivier }
2196105683dSLaurent Vivier
2206105683dSLaurent Vivier ret = qio_channel_read(QIO_CHANNEL(ib->sioc), ib->buffer, len, NULL);
2216105683dSLaurent Vivier if (ret < 0) {
2226105683dSLaurent Vivier return G_SOURCE_REMOVE;
2236105683dSLaurent Vivier }
2246105683dSLaurent Vivier
2256105683dSLaurent Vivier p = ib->buffer;
2266105683dSLaurent Vivier if (len >= strlen(cmd_names[barrierCmdHello]) &&
2276105683dSLaurent Vivier memcmp(p, cmd_names[barrierCmdHello],
2286105683dSLaurent Vivier strlen(cmd_names[barrierCmdHello])) == 0) {
2296105683dSLaurent Vivier cmd = barrierCmdHello;
2306105683dSLaurent Vivier p += strlen(cmd_names[barrierCmdHello]);
2316105683dSLaurent Vivier len -= strlen(cmd_names[barrierCmdHello]);
2326105683dSLaurent Vivier } else {
2336105683dSLaurent Vivier for (cmd = 0; cmd < barrierCmdHello; cmd++) {
2346105683dSLaurent Vivier if (memcmp(ib->buffer, cmd_names[cmd], 4) == 0) {
2356105683dSLaurent Vivier break;
2366105683dSLaurent Vivier }
2376105683dSLaurent Vivier }
2386105683dSLaurent Vivier
2396105683dSLaurent Vivier if (cmd == barrierCmdHello) {
2406105683dSLaurent Vivier return G_SOURCE_REMOVE;
2416105683dSLaurent Vivier }
2426105683dSLaurent Vivier p += 4;
2436105683dSLaurent Vivier len -= 4;
2446105683dSLaurent Vivier }
2456105683dSLaurent Vivier
2466105683dSLaurent Vivier msg->cmd = cmd;
2476105683dSLaurent Vivier switch (cmd) {
2486105683dSLaurent Vivier /* connection */
2496105683dSLaurent Vivier case barrierCmdHello:
2506105683dSLaurent Vivier read_short(msg->version.major, p, len);
2516105683dSLaurent Vivier read_short(msg->version.minor, p, len);
2526105683dSLaurent Vivier break;
2536105683dSLaurent Vivier case barrierCmdDSetOptions:
2546105683dSLaurent Vivier read_int(msg->set.nb, p, len);
2556105683dSLaurent Vivier msg->set.nb /= 2;
2566105683dSLaurent Vivier if (msg->set.nb > BARRIER_MAX_OPTIONS) {
2576105683dSLaurent Vivier msg->set.nb = BARRIER_MAX_OPTIONS;
2586105683dSLaurent Vivier }
2596105683dSLaurent Vivier i = 0;
2606105683dSLaurent Vivier while (len && i < msg->set.nb) {
2616105683dSLaurent Vivier read_int(msg->set.option[i].id, p, len);
2626105683dSLaurent Vivier /* it's a string, restore endianness */
2636105683dSLaurent Vivier msg->set.option[i].id = htonl(msg->set.option[i].id);
2646105683dSLaurent Vivier msg->set.option[i].nul = 0;
2656105683dSLaurent Vivier read_int(msg->set.option[i].value, p, len);
2666105683dSLaurent Vivier i++;
2676105683dSLaurent Vivier }
2686105683dSLaurent Vivier break;
2696105683dSLaurent Vivier case barrierCmdQInfo:
2706105683dSLaurent Vivier break;
2716105683dSLaurent Vivier
2726105683dSLaurent Vivier /* mouse */
2736105683dSLaurent Vivier case barrierCmdDMouseMove:
2746105683dSLaurent Vivier case barrierCmdDMouseRelMove:
2756105683dSLaurent Vivier read_short(msg->mousepos.x, p, len);
2766105683dSLaurent Vivier read_short(msg->mousepos.y, p, len);
2776105683dSLaurent Vivier break;
2786105683dSLaurent Vivier case barrierCmdDMouseDown:
2796105683dSLaurent Vivier case barrierCmdDMouseUp:
2806105683dSLaurent Vivier read_char(msg->mousebutton.buttonid, p, len);
2816105683dSLaurent Vivier break;
2826105683dSLaurent Vivier case barrierCmdDMouseWheel:
2836105683dSLaurent Vivier read_short(msg->mousepos.y, p, len);
2846105683dSLaurent Vivier msg->mousepos.x = 0;
2856105683dSLaurent Vivier if (len) {
2866105683dSLaurent Vivier msg->mousepos.x = msg->mousepos.y;
2876105683dSLaurent Vivier read_short(msg->mousepos.y, p, len);
2886105683dSLaurent Vivier }
2896105683dSLaurent Vivier break;
2906105683dSLaurent Vivier
2916105683dSLaurent Vivier /* keyboard */
2926105683dSLaurent Vivier case barrierCmdDKeyDown:
2936105683dSLaurent Vivier case barrierCmdDKeyUp:
2946105683dSLaurent Vivier read_short(msg->key.keyid, p, len);
2956105683dSLaurent Vivier read_short(msg->key.modifier, p, len);
2966105683dSLaurent Vivier msg->key.button = 0;
2976105683dSLaurent Vivier if (len) {
2986105683dSLaurent Vivier read_short(msg->key.button, p, len);
2996105683dSLaurent Vivier }
3006105683dSLaurent Vivier break;
3016105683dSLaurent Vivier case barrierCmdDKeyRepeat:
3026105683dSLaurent Vivier read_short(msg->repeat.keyid, p, len);
3036105683dSLaurent Vivier read_short(msg->repeat.modifier, p, len);
3046105683dSLaurent Vivier read_short(msg->repeat.repeat, p, len);
3056105683dSLaurent Vivier msg->repeat.button = 0;
3066105683dSLaurent Vivier if (len) {
3076105683dSLaurent Vivier read_short(msg->repeat.button, p, len);
3086105683dSLaurent Vivier }
3096105683dSLaurent Vivier break;
3106105683dSLaurent Vivier case barrierCmdCInfoAck:
3116105683dSLaurent Vivier case barrierCmdCResetOptions:
3126105683dSLaurent Vivier case barrierCmdCEnter:
3136105683dSLaurent Vivier case barrierCmdDClipboard:
3146105683dSLaurent Vivier case barrierCmdCKeepAlive:
3156105683dSLaurent Vivier case barrierCmdCLeave:
3166105683dSLaurent Vivier case barrierCmdCClose:
3176105683dSLaurent Vivier break;
3186105683dSLaurent Vivier
3196105683dSLaurent Vivier /* Invalid from the server */
3206105683dSLaurent Vivier case barrierCmdHelloBack:
3216105683dSLaurent Vivier case barrierCmdCNoop:
3226105683dSLaurent Vivier case barrierCmdDInfo:
3236105683dSLaurent Vivier break;
3246105683dSLaurent Vivier
3256105683dSLaurent Vivier /* Error codes */
3266105683dSLaurent Vivier case barrierCmdEIncompatible:
3276105683dSLaurent Vivier read_short(msg->version.major, p, len);
3286105683dSLaurent Vivier read_short(msg->version.minor, p, len);
3296105683dSLaurent Vivier break;
3306105683dSLaurent Vivier case barrierCmdEBusy:
3316105683dSLaurent Vivier case barrierCmdEUnknown:
3326105683dSLaurent Vivier case barrierCmdEBad:
3336105683dSLaurent Vivier break;
3346105683dSLaurent Vivier default:
3356105683dSLaurent Vivier return G_SOURCE_REMOVE;
3366105683dSLaurent Vivier }
3376105683dSLaurent Vivier
3386105683dSLaurent Vivier return G_SOURCE_CONTINUE;
3396105683dSLaurent Vivier }
3406105683dSLaurent Vivier
writecmd(InputBarrier * ib,struct barrierMsg * msg)3416105683dSLaurent Vivier static gboolean writecmd(InputBarrier *ib, struct barrierMsg *msg)
3426105683dSLaurent Vivier {
3436105683dSLaurent Vivier char *p;
3446105683dSLaurent Vivier int ret, i;
3456105683dSLaurent Vivier int avail, len;
3466105683dSLaurent Vivier
3476105683dSLaurent Vivier p = ib->buffer;
3486105683dSLaurent Vivier avail = MAX_HELLO_LENGTH;
3496105683dSLaurent Vivier
3506105683dSLaurent Vivier /* reserve space to store the length */
3516105683dSLaurent Vivier p += sizeof(int);
3526105683dSLaurent Vivier avail -= sizeof(int);
3536105683dSLaurent Vivier
3546105683dSLaurent Vivier switch (msg->cmd) {
3556105683dSLaurent Vivier case barrierCmdHello:
3566105683dSLaurent Vivier if (msg->version.major < BARRIER_VERSION_MAJOR ||
3576105683dSLaurent Vivier (msg->version.major == BARRIER_VERSION_MAJOR &&
3586105683dSLaurent Vivier msg->version.minor < BARRIER_VERSION_MINOR)) {
3596105683dSLaurent Vivier ib->ioc_tag = 0;
3606105683dSLaurent Vivier return G_SOURCE_REMOVE;
3616105683dSLaurent Vivier }
3626105683dSLaurent Vivier write_cmd(p, barrierCmdHelloBack, avail);
3636105683dSLaurent Vivier write_short(p, BARRIER_VERSION_MAJOR, avail);
3646105683dSLaurent Vivier write_short(p, BARRIER_VERSION_MINOR, avail);
3656105683dSLaurent Vivier write_string(p, ib->name, avail);
3666105683dSLaurent Vivier break;
3676105683dSLaurent Vivier case barrierCmdCClose:
3686105683dSLaurent Vivier ib->ioc_tag = 0;
3696105683dSLaurent Vivier return G_SOURCE_REMOVE;
3706105683dSLaurent Vivier case barrierCmdQInfo:
3716105683dSLaurent Vivier write_cmd(p, barrierCmdDInfo, avail);
3726105683dSLaurent Vivier write_short(p, ib->x_origin, avail);
3736105683dSLaurent Vivier write_short(p, ib->y_origin, avail);
3746105683dSLaurent Vivier write_short(p, ib->width, avail);
3756105683dSLaurent Vivier write_short(p, ib->height, avail);
3766105683dSLaurent Vivier write_short(p, 0, avail); /* warpsize (obsolete) */
3776105683dSLaurent Vivier write_short(p, 0, avail); /* mouse x */
3786105683dSLaurent Vivier write_short(p, 0, avail); /* mouse y */
3796105683dSLaurent Vivier break;
3806105683dSLaurent Vivier case barrierCmdCInfoAck:
3816105683dSLaurent Vivier break;
3826105683dSLaurent Vivier case barrierCmdCResetOptions:
3836105683dSLaurent Vivier /* TODO: reset options */
3846105683dSLaurent Vivier break;
3856105683dSLaurent Vivier case barrierCmdDSetOptions:
3866105683dSLaurent Vivier /* TODO: set options */
3876105683dSLaurent Vivier break;
3886105683dSLaurent Vivier case barrierCmdCEnter:
3896105683dSLaurent Vivier break;
3906105683dSLaurent Vivier case barrierCmdDClipboard:
3916105683dSLaurent Vivier break;
3926105683dSLaurent Vivier case barrierCmdCKeepAlive:
3936105683dSLaurent Vivier write_cmd(p, barrierCmdCKeepAlive, avail);
3946105683dSLaurent Vivier break;
3956105683dSLaurent Vivier case barrierCmdCLeave:
3966105683dSLaurent Vivier break;
3976105683dSLaurent Vivier
3986105683dSLaurent Vivier /* mouse */
3996105683dSLaurent Vivier case barrierCmdDMouseMove:
4006105683dSLaurent Vivier qemu_input_queue_abs(NULL, INPUT_AXIS_X, msg->mousepos.x,
4016105683dSLaurent Vivier ib->x_origin, ib->width);
4026105683dSLaurent Vivier qemu_input_queue_abs(NULL, INPUT_AXIS_Y, msg->mousepos.y,
4036105683dSLaurent Vivier ib->y_origin, ib->height);
4046105683dSLaurent Vivier qemu_input_event_sync();
4056105683dSLaurent Vivier break;
4066105683dSLaurent Vivier case barrierCmdDMouseRelMove:
4076105683dSLaurent Vivier qemu_input_queue_rel(NULL, INPUT_AXIS_X, msg->mousepos.x);
4086105683dSLaurent Vivier qemu_input_queue_rel(NULL, INPUT_AXIS_Y, msg->mousepos.y);
4096105683dSLaurent Vivier qemu_input_event_sync();
4106105683dSLaurent Vivier break;
4116105683dSLaurent Vivier case barrierCmdDMouseDown:
4126105683dSLaurent Vivier qemu_input_queue_btn(NULL,
4136105683dSLaurent Vivier input_barrier_to_mouse(msg->mousebutton.buttonid),
4146105683dSLaurent Vivier true);
4156105683dSLaurent Vivier qemu_input_event_sync();
4166105683dSLaurent Vivier break;
4176105683dSLaurent Vivier case barrierCmdDMouseUp:
4186105683dSLaurent Vivier qemu_input_queue_btn(NULL,
4196105683dSLaurent Vivier input_barrier_to_mouse(msg->mousebutton.buttonid),
4206105683dSLaurent Vivier false);
4216105683dSLaurent Vivier qemu_input_event_sync();
4226105683dSLaurent Vivier break;
4236105683dSLaurent Vivier case barrierCmdDMouseWheel:
4246105683dSLaurent Vivier qemu_input_queue_btn(NULL, (msg->mousepos.y > 0) ? INPUT_BUTTON_WHEEL_UP
4256105683dSLaurent Vivier : INPUT_BUTTON_WHEEL_DOWN, true);
4266105683dSLaurent Vivier qemu_input_event_sync();
4276105683dSLaurent Vivier qemu_input_queue_btn(NULL, (msg->mousepos.y > 0) ? INPUT_BUTTON_WHEEL_UP
4286105683dSLaurent Vivier : INPUT_BUTTON_WHEEL_DOWN, false);
4296105683dSLaurent Vivier qemu_input_event_sync();
4306105683dSLaurent Vivier break;
4316105683dSLaurent Vivier
4326105683dSLaurent Vivier /* keyboard */
4336105683dSLaurent Vivier case barrierCmdDKeyDown:
4346105683dSLaurent Vivier qemu_input_event_send_key_qcode(NULL,
4356105683dSLaurent Vivier input_barrier_to_qcode(msg->key.keyid, msg->key.button),
4366105683dSLaurent Vivier true);
4376105683dSLaurent Vivier break;
4386105683dSLaurent Vivier case barrierCmdDKeyRepeat:
4396105683dSLaurent Vivier for (i = 0; i < msg->repeat.repeat; i++) {
4406105683dSLaurent Vivier qemu_input_event_send_key_qcode(NULL,
4416105683dSLaurent Vivier input_barrier_to_qcode(msg->repeat.keyid, msg->repeat.button),
4426105683dSLaurent Vivier false);
4436105683dSLaurent Vivier qemu_input_event_send_key_qcode(NULL,
4446105683dSLaurent Vivier input_barrier_to_qcode(msg->repeat.keyid, msg->repeat.button),
4456105683dSLaurent Vivier true);
4466105683dSLaurent Vivier }
4476105683dSLaurent Vivier break;
4486105683dSLaurent Vivier case barrierCmdDKeyUp:
4496105683dSLaurent Vivier qemu_input_event_send_key_qcode(NULL,
4506105683dSLaurent Vivier input_barrier_to_qcode(msg->key.keyid, msg->key.button),
4516105683dSLaurent Vivier false);
4526105683dSLaurent Vivier break;
4536105683dSLaurent Vivier default:
4546105683dSLaurent Vivier write_cmd(p, barrierCmdEUnknown, avail);
45529453426SPhilippe Mathieu-Daudé break;
4566105683dSLaurent Vivier }
4576105683dSLaurent Vivier
4586105683dSLaurent Vivier len = MAX_HELLO_LENGTH - avail - sizeof(int);
4596105683dSLaurent Vivier if (len) {
4606105683dSLaurent Vivier p = ib->buffer;
4616105683dSLaurent Vivier avail = sizeof(len);
4626105683dSLaurent Vivier write_int(p, len, avail);
4636105683dSLaurent Vivier ret = qio_channel_write(QIO_CHANNEL(ib->sioc), ib->buffer,
4646105683dSLaurent Vivier len + sizeof(len), NULL);
4656105683dSLaurent Vivier if (ret < 0) {
4666105683dSLaurent Vivier ib->ioc_tag = 0;
4676105683dSLaurent Vivier return G_SOURCE_REMOVE;
4686105683dSLaurent Vivier }
4696105683dSLaurent Vivier }
4706105683dSLaurent Vivier
4716105683dSLaurent Vivier return G_SOURCE_CONTINUE;
4726105683dSLaurent Vivier }
4736105683dSLaurent Vivier
input_barrier_event(QIOChannel * ioc G_GNUC_UNUSED,GIOCondition condition,void * opaque)4746105683dSLaurent Vivier static gboolean input_barrier_event(QIOChannel *ioc G_GNUC_UNUSED,
4756105683dSLaurent Vivier GIOCondition condition, void *opaque)
4766105683dSLaurent Vivier {
4776105683dSLaurent Vivier InputBarrier *ib = opaque;
4786105683dSLaurent Vivier int ret;
4796105683dSLaurent Vivier struct barrierMsg msg;
4806105683dSLaurent Vivier
4816105683dSLaurent Vivier ret = readcmd(ib, &msg);
4826105683dSLaurent Vivier if (ret == G_SOURCE_REMOVE) {
4836105683dSLaurent Vivier ib->ioc_tag = 0;
4846105683dSLaurent Vivier return G_SOURCE_REMOVE;
4856105683dSLaurent Vivier }
4866105683dSLaurent Vivier
4876105683dSLaurent Vivier return writecmd(ib, &msg);
4886105683dSLaurent Vivier }
4896105683dSLaurent Vivier
input_barrier_complete(UserCreatable * uc,Error ** errp)4906105683dSLaurent Vivier static void input_barrier_complete(UserCreatable *uc, Error **errp)
4916105683dSLaurent Vivier {
4926105683dSLaurent Vivier InputBarrier *ib = INPUT_BARRIER(uc);
4936105683dSLaurent Vivier Error *local_err = NULL;
4946105683dSLaurent Vivier
4956105683dSLaurent Vivier if (!ib->name) {
4966105683dSLaurent Vivier error_setg(errp, QERR_MISSING_PARAMETER, "name");
4976105683dSLaurent Vivier return;
4986105683dSLaurent Vivier }
4996105683dSLaurent Vivier
5006105683dSLaurent Vivier /*
5016105683dSLaurent Vivier * Connect to the primary
5026105683dSLaurent Vivier * Primary is the server where the keyboard and the mouse
5036105683dSLaurent Vivier * are connected and forwarded to the secondary (the client)
5046105683dSLaurent Vivier */
5056105683dSLaurent Vivier
5066105683dSLaurent Vivier ib->sioc = qio_channel_socket_new();
5076105683dSLaurent Vivier qio_channel_set_name(QIO_CHANNEL(ib->sioc), "barrier-client");
5086105683dSLaurent Vivier
5096105683dSLaurent Vivier qio_channel_socket_connect_sync(ib->sioc, &ib->saddr, &local_err);
5106105683dSLaurent Vivier if (local_err) {
5116105683dSLaurent Vivier error_propagate(errp, local_err);
5126105683dSLaurent Vivier return;
5136105683dSLaurent Vivier }
5146105683dSLaurent Vivier
5156105683dSLaurent Vivier qio_channel_set_delay(QIO_CHANNEL(ib->sioc), false);
5166105683dSLaurent Vivier
5176105683dSLaurent Vivier ib->ioc_tag = qio_channel_add_watch(QIO_CHANNEL(ib->sioc), G_IO_IN,
5186105683dSLaurent Vivier input_barrier_event, ib, NULL);
5196105683dSLaurent Vivier }
5206105683dSLaurent Vivier
input_barrier_instance_finalize(Object * obj)5216105683dSLaurent Vivier static void input_barrier_instance_finalize(Object *obj)
5226105683dSLaurent Vivier {
5236105683dSLaurent Vivier InputBarrier *ib = INPUT_BARRIER(obj);
5246105683dSLaurent Vivier
5256105683dSLaurent Vivier if (ib->ioc_tag) {
5266105683dSLaurent Vivier g_source_remove(ib->ioc_tag);
5276105683dSLaurent Vivier ib->ioc_tag = 0;
5286105683dSLaurent Vivier }
5296105683dSLaurent Vivier
5306105683dSLaurent Vivier if (ib->sioc) {
5316105683dSLaurent Vivier qio_channel_close(QIO_CHANNEL(ib->sioc), NULL);
5326105683dSLaurent Vivier object_unref(OBJECT(ib->sioc));
5336105683dSLaurent Vivier }
5346105683dSLaurent Vivier g_free(ib->name);
5356105683dSLaurent Vivier g_free(ib->saddr.u.inet.host);
5366105683dSLaurent Vivier g_free(ib->saddr.u.inet.port);
5376105683dSLaurent Vivier }
5386105683dSLaurent Vivier
input_barrier_get_name(Object * obj,Error ** errp)5396105683dSLaurent Vivier static char *input_barrier_get_name(Object *obj, Error **errp)
5406105683dSLaurent Vivier {
5416105683dSLaurent Vivier InputBarrier *ib = INPUT_BARRIER(obj);
5426105683dSLaurent Vivier
5436105683dSLaurent Vivier return g_strdup(ib->name);
5446105683dSLaurent Vivier }
5456105683dSLaurent Vivier
input_barrier_set_name(Object * obj,const char * value,Error ** errp)5466105683dSLaurent Vivier static void input_barrier_set_name(Object *obj, const char *value,
5476105683dSLaurent Vivier Error **errp)
5486105683dSLaurent Vivier {
5496105683dSLaurent Vivier InputBarrier *ib = INPUT_BARRIER(obj);
5506105683dSLaurent Vivier
5516105683dSLaurent Vivier if (ib->name) {
5526105683dSLaurent Vivier error_setg(errp, "name property already set");
5536105683dSLaurent Vivier return;
5546105683dSLaurent Vivier }
5556105683dSLaurent Vivier ib->name = g_strdup(value);
5566105683dSLaurent Vivier }
5576105683dSLaurent Vivier
input_barrier_get_server(Object * obj,Error ** errp)5586105683dSLaurent Vivier static char *input_barrier_get_server(Object *obj, Error **errp)
5596105683dSLaurent Vivier {
5606105683dSLaurent Vivier InputBarrier *ib = INPUT_BARRIER(obj);
5616105683dSLaurent Vivier
5626105683dSLaurent Vivier return g_strdup(ib->saddr.u.inet.host);
5636105683dSLaurent Vivier }
5646105683dSLaurent Vivier
input_barrier_set_server(Object * obj,const char * value,Error ** errp)5656105683dSLaurent Vivier static void input_barrier_set_server(Object *obj, const char *value,
5666105683dSLaurent Vivier Error **errp)
5676105683dSLaurent Vivier {
5686105683dSLaurent Vivier InputBarrier *ib = INPUT_BARRIER(obj);
5696105683dSLaurent Vivier
5706105683dSLaurent Vivier g_free(ib->saddr.u.inet.host);
5716105683dSLaurent Vivier ib->saddr.u.inet.host = g_strdup(value);
5726105683dSLaurent Vivier }
5736105683dSLaurent Vivier
input_barrier_get_port(Object * obj,Error ** errp)5746105683dSLaurent Vivier static char *input_barrier_get_port(Object *obj, Error **errp)
5756105683dSLaurent Vivier {
5766105683dSLaurent Vivier InputBarrier *ib = INPUT_BARRIER(obj);
5776105683dSLaurent Vivier
5786105683dSLaurent Vivier return g_strdup(ib->saddr.u.inet.port);
5796105683dSLaurent Vivier }
5806105683dSLaurent Vivier
input_barrier_set_port(Object * obj,const char * value,Error ** errp)5816105683dSLaurent Vivier static void input_barrier_set_port(Object *obj, const char *value,
5826105683dSLaurent Vivier Error **errp)
5836105683dSLaurent Vivier {
5846105683dSLaurent Vivier InputBarrier *ib = INPUT_BARRIER(obj);
5856105683dSLaurent Vivier
5866105683dSLaurent Vivier g_free(ib->saddr.u.inet.port);
5876105683dSLaurent Vivier ib->saddr.u.inet.port = g_strdup(value);
5886105683dSLaurent Vivier }
5896105683dSLaurent Vivier
input_barrier_set_x_origin(Object * obj,const char * value,Error ** errp)5906105683dSLaurent Vivier static void input_barrier_set_x_origin(Object *obj, const char *value,
5916105683dSLaurent Vivier Error **errp)
5926105683dSLaurent Vivier {
5936105683dSLaurent Vivier InputBarrier *ib = INPUT_BARRIER(obj);
5946105683dSLaurent Vivier int result, err;
5956105683dSLaurent Vivier
5966105683dSLaurent Vivier err = qemu_strtoi(value, NULL, 0, &result);
5976105683dSLaurent Vivier if (err < 0 || result < 0 || result > SHRT_MAX) {
5986105683dSLaurent Vivier error_setg(errp,
5996105683dSLaurent Vivier "x-origin property must be in the range [0..%d]", SHRT_MAX);
6006105683dSLaurent Vivier return;
6016105683dSLaurent Vivier }
6026105683dSLaurent Vivier ib->x_origin = result;
6036105683dSLaurent Vivier }
6046105683dSLaurent Vivier
input_barrier_get_x_origin(Object * obj,Error ** errp)6056105683dSLaurent Vivier static char *input_barrier_get_x_origin(Object *obj, Error **errp)
6066105683dSLaurent Vivier {
6076105683dSLaurent Vivier InputBarrier *ib = INPUT_BARRIER(obj);
6086105683dSLaurent Vivier
6096105683dSLaurent Vivier return g_strdup_printf("%d", ib->x_origin);
6106105683dSLaurent Vivier }
6116105683dSLaurent Vivier
input_barrier_set_y_origin(Object * obj,const char * value,Error ** errp)6126105683dSLaurent Vivier static void input_barrier_set_y_origin(Object *obj, const char *value,
6136105683dSLaurent Vivier Error **errp)
6146105683dSLaurent Vivier {
6156105683dSLaurent Vivier InputBarrier *ib = INPUT_BARRIER(obj);
6166105683dSLaurent Vivier int result, err;
6176105683dSLaurent Vivier
6186105683dSLaurent Vivier err = qemu_strtoi(value, NULL, 0, &result);
6196105683dSLaurent Vivier if (err < 0 || result < 0 || result > SHRT_MAX) {
6206105683dSLaurent Vivier error_setg(errp,
6216105683dSLaurent Vivier "y-origin property must be in the range [0..%d]", SHRT_MAX);
6226105683dSLaurent Vivier return;
6236105683dSLaurent Vivier }
6246105683dSLaurent Vivier ib->y_origin = result;
6256105683dSLaurent Vivier }
6266105683dSLaurent Vivier
input_barrier_get_y_origin(Object * obj,Error ** errp)6276105683dSLaurent Vivier static char *input_barrier_get_y_origin(Object *obj, Error **errp)
6286105683dSLaurent Vivier {
6296105683dSLaurent Vivier InputBarrier *ib = INPUT_BARRIER(obj);
6306105683dSLaurent Vivier
6316105683dSLaurent Vivier return g_strdup_printf("%d", ib->y_origin);
6326105683dSLaurent Vivier }
6336105683dSLaurent Vivier
input_barrier_set_width(Object * obj,const char * value,Error ** errp)6346105683dSLaurent Vivier static void input_barrier_set_width(Object *obj, const char *value,
6356105683dSLaurent Vivier Error **errp)
6366105683dSLaurent Vivier {
6376105683dSLaurent Vivier InputBarrier *ib = INPUT_BARRIER(obj);
6386105683dSLaurent Vivier int result, err;
6396105683dSLaurent Vivier
6406105683dSLaurent Vivier err = qemu_strtoi(value, NULL, 0, &result);
6416105683dSLaurent Vivier if (err < 0 || result < 0 || result > SHRT_MAX) {
6426105683dSLaurent Vivier error_setg(errp,
6436105683dSLaurent Vivier "width property must be in the range [0..%d]", SHRT_MAX);
6446105683dSLaurent Vivier return;
6456105683dSLaurent Vivier }
6466105683dSLaurent Vivier ib->width = result;
6476105683dSLaurent Vivier }
6486105683dSLaurent Vivier
input_barrier_get_width(Object * obj,Error ** errp)6496105683dSLaurent Vivier static char *input_barrier_get_width(Object *obj, Error **errp)
6506105683dSLaurent Vivier {
6516105683dSLaurent Vivier InputBarrier *ib = INPUT_BARRIER(obj);
6526105683dSLaurent Vivier
6536105683dSLaurent Vivier return g_strdup_printf("%d", ib->width);
6546105683dSLaurent Vivier }
6556105683dSLaurent Vivier
input_barrier_set_height(Object * obj,const char * value,Error ** errp)6566105683dSLaurent Vivier static void input_barrier_set_height(Object *obj, const char *value,
6576105683dSLaurent Vivier Error **errp)
6586105683dSLaurent Vivier {
6596105683dSLaurent Vivier InputBarrier *ib = INPUT_BARRIER(obj);
6606105683dSLaurent Vivier int result, err;
6616105683dSLaurent Vivier
6626105683dSLaurent Vivier err = qemu_strtoi(value, NULL, 0, &result);
6636105683dSLaurent Vivier if (err < 0 || result < 0 || result > SHRT_MAX) {
6646105683dSLaurent Vivier error_setg(errp,
6656105683dSLaurent Vivier "height property must be in the range [0..%d]", SHRT_MAX);
6666105683dSLaurent Vivier return;
6676105683dSLaurent Vivier }
6686105683dSLaurent Vivier ib->height = result;
6696105683dSLaurent Vivier }
6706105683dSLaurent Vivier
input_barrier_get_height(Object * obj,Error ** errp)6716105683dSLaurent Vivier static char *input_barrier_get_height(Object *obj, Error **errp)
6726105683dSLaurent Vivier {
6736105683dSLaurent Vivier InputBarrier *ib = INPUT_BARRIER(obj);
6746105683dSLaurent Vivier
6756105683dSLaurent Vivier return g_strdup_printf("%d", ib->height);
6766105683dSLaurent Vivier }
6776105683dSLaurent Vivier
input_barrier_instance_init(Object * obj)6786105683dSLaurent Vivier static void input_barrier_instance_init(Object *obj)
6796105683dSLaurent Vivier {
6806105683dSLaurent Vivier InputBarrier *ib = INPUT_BARRIER(obj);
6816105683dSLaurent Vivier
682707f7507SLaurent Vivier /* always use generic keymaps */
683707f7507SLaurent Vivier if (keyboard_layout && !kbd_layout) {
684707f7507SLaurent Vivier /* We use X11 key id, so use VNC name2keysym */
685707f7507SLaurent Vivier kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout,
686707f7507SLaurent Vivier &error_fatal);
687707f7507SLaurent Vivier }
688707f7507SLaurent Vivier
6896105683dSLaurent Vivier ib->saddr.type = SOCKET_ADDRESS_TYPE_INET;
6906105683dSLaurent Vivier ib->saddr.u.inet.host = g_strdup("localhost");
6916105683dSLaurent Vivier ib->saddr.u.inet.port = g_strdup("24800");
6926105683dSLaurent Vivier
6936105683dSLaurent Vivier ib->x_origin = 0;
6946105683dSLaurent Vivier ib->y_origin = 0;
6956105683dSLaurent Vivier ib->width = 1920;
6966105683dSLaurent Vivier ib->height = 1080;
6976105683dSLaurent Vivier }
6986105683dSLaurent Vivier
input_barrier_class_init(ObjectClass * oc,void * data)6996105683dSLaurent Vivier static void input_barrier_class_init(ObjectClass *oc, void *data)
7006105683dSLaurent Vivier {
7016105683dSLaurent Vivier UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
7026105683dSLaurent Vivier
7036105683dSLaurent Vivier ucc->complete = input_barrier_complete;
704d85855b8SEduardo Habkost
705d85855b8SEduardo Habkost object_class_property_add_str(oc, "name",
706d85855b8SEduardo Habkost input_barrier_get_name,
707d85855b8SEduardo Habkost input_barrier_set_name);
708d85855b8SEduardo Habkost object_class_property_add_str(oc, "server",
709d85855b8SEduardo Habkost input_barrier_get_server,
710d85855b8SEduardo Habkost input_barrier_set_server);
711d85855b8SEduardo Habkost object_class_property_add_str(oc, "port",
712d85855b8SEduardo Habkost input_barrier_get_port,
713d85855b8SEduardo Habkost input_barrier_set_port);
714d85855b8SEduardo Habkost object_class_property_add_str(oc, "x-origin",
715d85855b8SEduardo Habkost input_barrier_get_x_origin,
716d85855b8SEduardo Habkost input_barrier_set_x_origin);
717d85855b8SEduardo Habkost object_class_property_add_str(oc, "y-origin",
718d85855b8SEduardo Habkost input_barrier_get_y_origin,
719d85855b8SEduardo Habkost input_barrier_set_y_origin);
720d85855b8SEduardo Habkost object_class_property_add_str(oc, "width",
721d85855b8SEduardo Habkost input_barrier_get_width,
722d85855b8SEduardo Habkost input_barrier_set_width);
723d85855b8SEduardo Habkost object_class_property_add_str(oc, "height",
724d85855b8SEduardo Habkost input_barrier_get_height,
725d85855b8SEduardo Habkost input_barrier_set_height);
7266105683dSLaurent Vivier }
7276105683dSLaurent Vivier
7286105683dSLaurent Vivier static const TypeInfo input_barrier_info = {
7296105683dSLaurent Vivier .name = TYPE_INPUT_BARRIER,
7306105683dSLaurent Vivier .parent = TYPE_OBJECT,
7316105683dSLaurent Vivier .class_init = input_barrier_class_init,
7326105683dSLaurent Vivier .instance_size = sizeof(InputBarrier),
7336105683dSLaurent Vivier .instance_init = input_barrier_instance_init,
7346105683dSLaurent Vivier .instance_finalize = input_barrier_instance_finalize,
7356105683dSLaurent Vivier .interfaces = (InterfaceInfo[]) {
7366105683dSLaurent Vivier { TYPE_USER_CREATABLE },
7376105683dSLaurent Vivier { }
7386105683dSLaurent Vivier }
7396105683dSLaurent Vivier };
7406105683dSLaurent Vivier
register_types(void)7416105683dSLaurent Vivier static void register_types(void)
7426105683dSLaurent Vivier {
7436105683dSLaurent Vivier type_register_static(&input_barrier_info);
7446105683dSLaurent Vivier }
7456105683dSLaurent Vivier
7466105683dSLaurent Vivier type_init(register_types);
747