So basically this remove the need for us to use synergy, how do we apply the patch to an existing config using libvirt?
2015-12-14 15:18 GMT+01:00 Gerd Hoffmann <kra...@redhat.com>: > This patch adds support for reading input events directly from linux > evdev devices and forward them to the guest. Unlike virtio-input-host > which simply passes on all events to the guest without looking at them > this will interpret the events and feed them into the qemu input > subsystem. > > Therefore this is limited to what the qemu input subsystem and the > emulated input devices are able to handle. Also there is no support for > absolute coordinates (tablet/touchscreen). So we are talking here about > basic mouse and keyboard support. > > The advantage is that it'll work without virtio-input drivers in the > guest, the events are delivered to the usual ps/2 or usb input devices > (depending on what the machine happens to have). And for keyboards > qemu is able to switch the keyboard between guest and host on hotkey. > The hotkey is hard-coded for now (both control keys), initialy the > guest owns the keyboard. > > Probably most useful when assigning vga devices with vfio and using a > physical monitor instead of vnc/spice/gtk as guest display. > > Usage: Add '-input-linux /dev/input/event<nr>' to the qemu command > line. Note that udev has rules which populate /dev/input/by-{id,path} > with static names, which might be more convinient to use. > > Signed-off-by: Gerd Hoffmann <kra...@redhat.com> > --- > include/ui/input.h | 2 + > qemu-options.hx | 9 +++ > ui/Makefile.objs | 1 + > ui/input-linux.c | 233 > +++++++++++++++++++++++++++++++++++++++++++++++++++++ > vl.c | 11 +++ > 5 files changed, 256 insertions(+) > create mode 100644 ui/input-linux.c > > diff --git a/include/ui/input.h b/include/ui/input.h > index d7afd80..443742e 100644 > --- a/include/ui/input.h > +++ b/include/ui/input.h > @@ -68,4 +68,6 @@ void qemu_input_check_mode_change(void); > void qemu_add_mouse_mode_change_notifier(Notifier *notify); > void qemu_remove_mouse_mode_change_notifier(Notifier *notify); > > +int input_linux_init(void *opaque, QemuOpts *opts, Error **errp); > + > #endif /* INPUT_H */ > diff --git a/qemu-options.hx b/qemu-options.hx > index 0eea4ee..a2d7338 100644 > --- a/qemu-options.hx > +++ b/qemu-options.hx > @@ -1165,6 +1165,15 @@ STEXI > Set the initial graphical resolution and depth (PPC, SPARC only). > ETEXI > > +DEF("input-linux", 1, QEMU_OPTION_input_linux, > + "-input-linux <evdev>\n" > + " Use input device.\n", QEMU_ARCH_ALL) > +STEXI > +@item -input-linux @var{dev} > +@findex -input-linux > +Use input device. > +ETEXI > + > DEF("vnc", HAS_ARG, QEMU_OPTION_vnc , > "-vnc display start a VNC server on display\n", QEMU_ARCH_ALL) > STEXI > diff --git a/ui/Makefile.objs b/ui/Makefile.objs > index 728393c..dc936f1 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 > +common-obj-$(CONFIG_LINUX) += input-linux.o > common-obj-$(CONFIG_SPICE) += spice-core.o spice-input.o spice-display.o > common-obj-$(CONFIG_SDL) += sdl.mo x_keymap.o > common-obj-$(CONFIG_COCOA) += cocoa.o > diff --git a/ui/input-linux.c b/ui/input-linux.c > new file mode 100644 > index 0000000..fdedf0b > --- /dev/null > +++ b/ui/input-linux.c > @@ -0,0 +1,233 @@ > +/* > + * This work is licensed under the terms of the GNU GPL, version 2 or > + * (at your option) any later version. See the COPYING file in the > + * top-level directory. > + */ > + > +#include "qemu-common.h" > +#include "qemu/config-file.h" > +#include "qemu/sockets.h" > +#include "sysemu/sysemu.h" > +#include "ui/input.h" > + > +#include <sys/ioctl.h> > +#include "standard-headers/linux/input.h" > + > +typedef struct InputLinux InputLinux; > + > +struct InputLinux { > + const char *evdev; > + int fd; > + bool grab_request; > + bool grab_active; > + bool keydown[KEY_CNT]; > + int keycount; > + int wheel; > +}; > + > +static void input_linux_toggle_grab(InputLinux *il) > +{ > + intptr_t request = !il->grab_active; > + int rc; > + > + rc = ioctl(il->fd, EVIOCGRAB, request); > + if (rc < 0) { > + return; > + } > + il->grab_active = !il->grab_active; > +} > + > +static void input_linux_event_keyboard(void *opaque) > +{ > + InputLinux *il = opaque; > + struct input_event event; > + int rc; > + > + for (;;) { > + rc = read(il->fd, &event, sizeof(event)); > + if (rc != sizeof(event)) { > + break; > + } > + > + switch (event.type) { > + case EV_KEY: > + if (event.value > 1) { > + /* > + * ignore autorepeat + unknown key events > + * 0 == up, 1 == down, 2 == autorepeat, other == undefined > + */ > + continue; > + } > + /* keep track of key state */ > + if (!il->keydown[event.code] && event.value) { > + il->keydown[event.code] = true; > + il->keycount++; > + } > + if (il->keydown[event.code] && !event.value) { > + il->keydown[event.code] = false; > + il->keycount--; > + } > + > + /* send event to guest when grab is active */ > + if (il->grab_active) { > + int qcode = qemu_input_linux_to_qcode(event.code); > + qemu_input_event_send_key_qcode(NULL, qcode, event.value); > + } > + > + /* hotkey -> record switch request ... */ > + if (il->keydown[KEY_LEFTCTRL] && > + il->keydown[KEY_RIGHTCTRL]) { > + il->grab_request = true; > + } > + > + /* > + * ... and do the switch when all keys are lifted, so we > + * confuse neither guest nor host with keys which seem to > + * be stuck due to missing key-up events. > + */ > + if (il->grab_request && !il->keycount) { > + il->grab_request = false; > + input_linux_toggle_grab(il); > + } > + break; > + } > + } > +} > + > +static void input_linux_event_mouse_button(int button) > +{ > + qemu_input_queue_btn(NULL, button, true); > + qemu_input_event_sync(); > + qemu_input_queue_btn(NULL, button, false); > + qemu_input_event_sync(); > +} > + > +static void input_linux_event_mouse(void *opaque) > +{ > + InputLinux *il = opaque; > + struct input_event event; > + int rc; > + > + for (;;) { > + rc = read(il->fd, &event, sizeof(event)); > + if (rc != sizeof(event)) { > + break; > + } > + > + switch (event.type) { > + case EV_KEY: > + switch (event.code) { > + case BTN_LEFT: > + qemu_input_queue_btn(NULL, INPUT_BUTTON_LEFT, > event.value); > + break; > + case BTN_RIGHT: > + qemu_input_queue_btn(NULL, INPUT_BUTTON_RIGHT, > event.value); > + break; > + case BTN_MIDDLE: > + qemu_input_queue_btn(NULL, INPUT_BUTTON_MIDDLE, > event.value); > + break; > + case BTN_GEAR_UP: > + qemu_input_queue_btn(NULL, INPUT_BUTTON_WHEEL_UP, > event.value); > + break; > + case BTN_GEAR_DOWN: > + qemu_input_queue_btn(NULL, INPUT_BUTTON_WHEEL_DOWN, > + event.value); > + break; > + }; > + break; > + case EV_REL: > + switch (event.code) { > + case REL_X: > + qemu_input_queue_rel(NULL, INPUT_AXIS_X, event.value); > + break; > + case REL_Y: > + qemu_input_queue_rel(NULL, INPUT_AXIS_Y, event.value); > + break; > + case REL_WHEEL: > + il->wheel = event.value; > + break; > + } > + break; > + case EV_SYN: > + qemu_input_event_sync(); > + if (il->wheel != 0) { > + input_linux_event_mouse_button((il->wheel > 0) > + ? INPUT_BUTTON_WHEEL_UP > + : INPUT_BUTTON_WHEEL_DOWN); > + il->wheel = 0; > + } > + break; > + } > + } > +} > + > +int input_linux_init(void *opaque, QemuOpts *opts, Error **errp) > +{ > + InputLinux *il = g_new0(InputLinux, 1); > + uint32_t evtmap; > + int rc, ver; > + > + il->evdev = qemu_opt_get(opts, "evdev"); > + if (!il->evdev) { > + error_setg(errp, "no input device specified"); > + goto err_free; > + } > + > + il->fd = open(il->evdev, O_RDWR); > + if (il->fd < 0) { > + error_setg_file_open(errp, errno, il->evdev); > + goto err_free; > + } > + qemu_set_nonblock(il->fd); > + > + rc = ioctl(il->fd, EVIOCGVERSION, &ver); > + if (rc < 0) { > + error_setg(errp, "%s: is not an evdev device", il->evdev); > + goto err_close; > + } > + > + rc = ioctl(il->fd, EVIOCGBIT(0, sizeof(evtmap)), &evtmap); > + > + if (evtmap & (1 << EV_REL)) { > + /* has relative axis -> assume mouse */ > + qemu_set_fd_handler(il->fd, input_linux_event_mouse, NULL, il); > + } else if (evtmap & (1 << EV_ABS)) { > + /* has absolute axis -> not supported */ > + error_setg(errp, "tablet/touchscreen not supported"); > + goto err_close; > + } else if (evtmap & (1 << EV_KEY)) { > + /* has keys/buttons (and no axis) -> assume keyboard */ > + qemu_set_fd_handler(il->fd, input_linux_event_keyboard, NULL, il); > + } else { > + /* Huh? What is this? */ > + error_setg(errp, "unknown kind of input device"); > + goto err_close; > + } > + input_linux_toggle_grab(il); > + return 0; > + > +err_close: > + close(il->fd); > +err_free: > + g_free(il); > + return -1; > +} > + > +static QemuOptsList qemu_input_linux_opts = { > + .name = "input-linux", > + .head = QTAILQ_HEAD_INITIALIZER(qemu_input_linux_opts.head), > + .implied_opt_name = "evdev", > + .desc = { > + { > + .name = "evdev", > + .type = QEMU_OPT_STRING, > + }, > + { /* end of list */ } > + }, > +}; > + > +static void input_linux_register_config(void) > +{ > + qemu_add_opts(&qemu_input_linux_opts); > +} > +machine_init(input_linux_register_config); > diff --git a/vl.c b/vl.c > index 4211ff1..993ee44 100644 > --- a/vl.c > +++ b/vl.c > @@ -78,6 +78,7 @@ int main(int argc, char **argv) > #include "net/slirp.h" > #include "monitor/monitor.h" > #include "ui/console.h" > +#include "ui/input.h" > #include "sysemu/sysemu.h" > #include "sysemu/numa.h" > #include "exec/gdbstub.h" > @@ -3742,6 +3743,12 @@ int main(int argc, char **argv, char **envp) > #endif > break; > } > + case QEMU_OPTION_input_linux: > + if > (!qemu_opts_parse_noisily(qemu_find_opts("input-linux"), > + optarg, true)) { > + exit(1); > + } > + break; > case QEMU_OPTION_no_acpi: > acpi_enabled = 0; > break; > @@ -4622,6 +4629,10 @@ int main(int argc, char **argv, char **envp) > qemu_spice_display_init(); > } > #endif > +#ifdef CONFIG_LINUX > + qemu_opts_foreach(qemu_find_opts("input-linux"), > + input_linux_init, NULL, &error_fatal); > +#endif > > if (foreach_device_config(DEV_GDB, gdbserver_start) < 0) { > exit(1); > -- > 1.8.3.1 > > _______________________________________________ > vfio-users mailing list > vfio-us...@redhat.com > https://www.redhat.com/mailman/listinfo/vfio-users >