From 58f0bbb10b60c4749844794d700abf2061edf275 Mon Sep 17 00:00:00 2001 From: Alexandre Bique Date: Tue, 21 Jul 2009 14:30:00 +0000 Subject: [PATCH] Updated the linux keyboard and mouse driver to be able to switch with Alt+Tab when you have the mouse but not the keyboard. --- master/dom0-driver | 397 ++++++++++++++++++++++----------------------- 1 file changed, 196 insertions(+), 201 deletions(-) diff --git a/master/dom0-driver b/master/dom0-driver index f79bb8b..bcd84f4 100644 --- a/master/dom0-driver +++ b/master/dom0-driver @@ -24,10 +24,10 @@ index 14b42f3..97214c0 100644 #endif diff --git a/dom0_driver.c b/dom0_driver.c new file mode 100644 -index 0000000..fdd24ab +index 0000000..bdfe37c --- /dev/null +++ b/dom0_driver.c -@@ -0,0 +1,697 @@ +@@ -0,0 +1,718 @@ +/* + * QEMU dom0_driver + * @@ -271,6 +271,19 @@ index 0000000..fdd24ab + } +} + ++static void dom0_driver_detect_alt_tab(void *opaque) ++{ ++ struct dom0_driver_xs_info mouse_info; ++ ++ dom0_driver_read_xs_info(&mouse_info, DOM0_MOUSE); ++ ++ printf("Got alt-tab !!!! domid: %d, mouse.domid: %d\n", domid, mouse_info.domid); ++ if (domid != mouse_info.domid) ++ return; ++ kbd_put_keycode(KEY_LEFTALT); ++ kbd_put_keycode(KEY_TAB); ++} ++ +static void dom0_driver_detect_secure_auth(void* opaque) +{ + struct stat s; @@ -688,6 +701,14 @@ index 0000000..fdd24ab + binds[2] = KEY_BACKSPACE; + binds[3] = -1; + dom0_driver_handler->add_binding(binds, dom0_driver_detect_secure_auth, NULL); ++ ++#if 0 ++ binds[0] = KEY_LEFTALT; ++ binds[1] = KEY_TAB; ++ binds[2] = -1; ++ binds[3] = -1; ++ dom0_driver_handler->add_binding(binds, dom0_driver_detect_alt_tab, NULL); ++#endif +} + +static int dom0_driver_dummy_enter_leave(void) @@ -727,10 +748,10 @@ index 0000000..fdd24ab +} diff --git a/hid-linux.c b/hid-linux.c new file mode 100644 -index 0000000..59dfec8 +index 0000000..00790b5 --- /dev/null +++ b/hid-linux.c -@@ -0,0 +1,527 @@ +@@ -0,0 +1,501 @@ +/* + * QEMU hid-linux /dev/input driver + * @@ -779,31 +800,32 @@ index 0000000..59dfec8 +#define HID_LINUX_XS_PATH "/local/domain/0/hid_linux" +#define ABS(x) ((x) > 0 ? (x) : -(x)) +#define EVENT_PATH "/dev/input/event" -+#define HID_LINUX_MAX_DEV 16 ++#define HID_LINUX_MAX_DEV 32 + +#define DEBUG_HID_LINUX + +#ifdef DEBUG_HID_LINUX -+# define DEBUG(_format_, args...) \ -+ do \ -+{ \ -+ char *__str = get_time(); \ -+ fprintf(stderr, "[%s] hid-linux(%d):%d: " _format_, (__str), domid, __LINE__, ## args);\ -+ free(__str);\ -+} \ -+while (0); ++# define DEBUG(_format_, args...) \ ++ do \ ++ { \ ++ char *__str = get_time(); \ ++ fprintf(stderr, "[%s] hid-linux(%d):%d: " _format_, \ ++ (__str), domid, __LINE__, ## args); \ ++ free(__str); \ ++ } \ ++ while (0); +#else +# define DEBUG(_format_, args...) (void)0 +#endif + +static struct hid_linux_driver +{ -+ int keyboard_fds[HID_LINUX_MAX_DEV / 2]; -+ int mouse_fds[HID_LINUX_MAX_DEV / 2]; -+ char *controller_paths[HID_LINUX_MAX_DEV]; ++ int evdev_fds[HID_LINUX_MAX_DEV]; + int mouse_button_state; + int key_status[256]; + void (*secure_key)(int ascii); ++ int has_keyboard; ++ int has_mouse; +} hid_linux_driver; + +struct hid_linux_binding @@ -863,6 +885,23 @@ index 0000000..59dfec8 + return ret; +} + ++static void hid_linux_xs_read_int(const char *key, int *value) ++{ ++ char *path = NULL; ++ char *ret; ++ ++ if (asprintf(&path, HID_LINUX_XS_PATH"/%s", key) == -1) ++ return NULL; ++ ret = xenstore_read(path); ++ free(path); ++ ++ if (!ret) ++ return; ++ ++ *value = strtol(ret, NULL, 10); ++ free(ret); ++} ++ +void hid_linux_add_binding(const int *tab, void (*cb)(void*), void *payload) +{ + int i = 0, j = 0; @@ -942,18 +981,26 @@ index 0000000..59dfec8 + kbd_put_keycode(keycode & 0x7f); +} + -+ -+ +static void hid_linux_key_event(int code, uint32_t keycode) +{ + if (code == 1) + if (hid_linux_detect_binding()) + return; -+ hid_linux_key_inject(code, keycode); ++ ++ if (hid_linux_driver.has_keyboard || // We have the keyboard ++ (hid_linux_driver.has_mouse && // We have the mouse and track Alt... ++ (hid_linux_driver.key_status[KEY_LEFTALT] || keycode == KEY_LEFTALT))) ++ hid_linux_key_inject(code, keycode); +} + -+static void hid_linux_read(void *opaque) ++static void hid_linux_keyboard_read(void *opaque) +{ ++ if (hid_linux_driver.secure_key && hid_linux_driver.has_keyboard) ++ { ++ hid_linux_driver.secure_key(opaque); ++ return; ++ } ++ + struct input_event event[5]; + int i = 0; + int read_sz = 0; @@ -962,82 +1009,95 @@ index 0000000..59dfec8 + read_sz = read(fd, event, sizeof (event)); + for (i = 0; i < read_sz / (sizeof (struct input_event)); i++) + { -+ if (event[i].type == EV_KEY) -+ { -+ if (event[i].code >= BTN_MOUSE) -+ { -+ /* Mouse Key */ -+ int type = 0; -+ -+ switch(event[i].code) -+ { -+ case BTN_LEFT: type = MOUSE_EVENT_LBUTTON; break; -+ case BTN_RIGHT: type = MOUSE_EVENT_RBUTTON; break; -+ case BTN_MIDDLE: type = MOUSE_EVENT_MBUTTON; break; -+ } -+ -+ if (event[i].value) -+ hid_linux_driver.mouse_button_state |= type; -+ else -+ hid_linux_driver.mouse_button_state &= ~type; -+ kbd_mouse_event(0, 0, 0, hid_linux_driver.mouse_button_state); -+ } -+ else -+ { ++ if (event[i].type == EV_KEY && ++ event[i].code < BTN_MOUSE) ++ { + hid_linux_driver.key_status[event[i].code] = event[i].value; + hid_linux_key_event(event[i].value, event[i].code); -+ } + } ++ } ++} + -+ if (event[i].type == EV_REL || event[i].type == EV_ABS) -+ { -+ /* Mouse motion */ -+ int x = 0, y = 0, z = 0; -+ -+ if (event[i].type == EV_REL) -+ switch (event[i].code) -+ { -+ case REL_X : x = event[i].value; break; -+ case REL_Y : y = event[i].value; break; -+ case REL_WHEEL : z = -event[i].value; break; -+ } -+ if (event[i].type == EV_ABS) -+ { -+ static int last_x = 1, last_y = 1; -+ int px = 0, py = 0, l = 50; -+ double div = 1; -+ char *str = NULL; -+ -+ str = hid_linux_xs_read("touchpad-limit"); -+ if (str) -+ l = strtol(str, NULL, 10); -+ str = hid_linux_xs_read("touchpad-div"); -+ if (str) -+ div = strtol(str, NULL, 10) / 1000.; -+ -+ switch (event[i].code) -+ { -+ case ABS_X : x = event[i].value; break; -+ case ABS_Y : y = event[i].value; break; -+ } -+ -+ if (x) -+ { -+ px = x - last_x; -+ last_x = x; -+ } -+ if (y) -+ { -+ py = y - last_y; -+ last_y = y; -+ } -+ -+ x = (ABS(px) < l ? px : 0) / div; -+ y = (ABS(py) < l ? py : 0) / div; -+ } ++static void hid_linux_mouse_click(struct input_event *event) ++{ ++ int type = 0; + -+ kbd_mouse_event(x, y, z, hid_linux_driver.mouse_button_state); -+ } ++ switch(event->code) ++ { ++ case BTN_LEFT: type = MOUSE_EVENT_LBUTTON; break; ++ case BTN_RIGHT: type = MOUSE_EVENT_RBUTTON; break; ++ case BTN_MIDDLE: type = MOUSE_EVENT_MBUTTON; break; ++ } ++ ++ if (event->value) ++ hid_linux_driver.mouse_button_state |= type; ++ else ++ hid_linux_driver.mouse_button_state &= ~type; ++ kbd_mouse_event(0, 0, 0, hid_linux_driver.mouse_button_state); ++} ++ ++static void hid_linux_mouse_motion(struct input_event *event) ++{ ++ int x = 0, y = 0, z = 0; ++ ++ if (event->type == EV_REL) ++ switch (event->code) ++ { ++ case REL_X : x = event->value; break; ++ case REL_Y : y = event->value; break; ++ case REL_WHEEL : z = -event->value; break; ++ } ++ else if (event->type == EV_ABS) ++ { ++ static int last_x = 1, last_y = 1; ++ int px = 0, py = 0, l = 50; ++ double div = 1; ++ char *str = NULL; ++ ++ hid_linux_xs_read_int("touchpad-limit", &l); ++ hid_linux_xs_read_int("touchpad-div", &div); ++ div /= 1000.; ++ ++ switch (event->code) ++ { ++ case ABS_X : x = event->value; break; ++ case ABS_Y : y = event->value; break; ++ } ++ ++ if (x) ++ { ++ px = x - last_x; ++ last_x = x; ++ } ++ if (y) ++ { ++ py = y - last_y; ++ last_y = y; ++ } ++ ++ x = (ABS(px) < l ? px : 0) / div; ++ y = (ABS(py) < l ? py : 0) / div; ++ } ++ ++ kbd_mouse_event(x, y, z, hid_linux_driver.mouse_button_state); ++} ++ ++static void hid_linux_mouse_read(void *opaque) ++{ ++ struct input_event event[5]; ++ int i = 0; ++ int read_sz = 0; ++ int fd = *(int *)opaque; ++ ++ read_sz = read(fd, event, sizeof (event)); ++ for (i = 0; i < read_sz / (sizeof (struct input_event)); i++) ++ { ++ if (event[i].type == EV_KEY && ++ event[i].code >= BTN_MOUSE && hid_linux_driver.has_mouse) ++ hid_linux_mouse_click(event + i); ++ else if ((event[i].type == EV_REL || event[i].type == EV_ABS) && ++ hid_linux_driver.has_mouse) ++ hid_linux_mouse_motion(event + i); + } +} + @@ -1053,8 +1113,6 @@ index 0000000..59dfec8 + } +} + -+ -+ +static void hid_linux_redirect_fds(int *fd, IOHandler *cb) +{ + assert(fd != NULL); @@ -1082,61 +1140,21 @@ index 0000000..59dfec8 + hid_linux_driver.secure_key(keycode2ascii(event[i].code)); +} + -+ +void hid_linux_secure_keyboard(void (*cb)(int ascii)) +{ + hid_linux_driver.secure_key = cb; -+ if (cb) -+ hid_linux_redirect_fds(hid_linux_driver.keyboard_fds, -+ hid_linux_secure_read); -+ else -+ hid_linux_redirect_fds(hid_linux_driver.keyboard_fds, -+ hid_linux_read); -+} -+ -+static int hid_linux_grab_devices(int grab, int *fd) -+{ -+ int rc = 0; -+ int try = 10; -+ -+ assert(fd != NULL && *fd != -1); -+ for (; *fd != -1; fd++) -+ { -+ while (try--) -+ { -+ if ((rc = ioctl(*fd, EVIOCGRAB, grab)) == -1) -+ { -+ char *er; -+ -+ if (errno == EBUSY) -+ continue; -+ er = strerror(errno); -+ DEBUG("ioctl(%d, EVOCGRAB) failed, %s\n", *fd, er); -+ return 0; -+ } -+ else -+ break; -+ } -+ assert(try); -+ -+ DEBUG("ioctl(%d, EVOCGRAB) succed\n", *fd); -+ -+ if (grab) -+ qemu_set_fd_handler(*fd, hid_linux_read, NULL, fd); -+ else -+ qemu_set_fd_handler(*fd, NULL, NULL, fd); -+ } -+ return 1; +} + +int hid_linux_grab_keyboard(int grab) +{ -+ return hid_linux_grab_devices(grab, hid_linux_driver.keyboard_fds); ++ hid_linux_driver.has_keyboard = grab; ++ return 1; +} + +int hid_linux_grab_mouse(int grab) +{ -+ return hid_linux_grab_devices(grab, hid_linux_driver.mouse_fds); ++ hid_linux_driver.has_mouse = grab; ++ return 1; +} + +static int hid_linux_open_timeout(const char *path, int flags) @@ -1162,107 +1180,84 @@ index 0000000..59dfec8 + return 1; +} + -+void hid_linux_probe(int grab) ++void hid_linux_probe(int grab __attribute__((unused))) +{ -+ int i = 0, j = 0, c = 0; -+ int fd = -1; -+ int keyboard = 0, mouse = 0; -+ char path[strlen(EVENT_PATH) + 3]; -+ char name[128]; -+ int *controllers; -+ struct input_id id; -+ struct stat st; -+ -+ while (1) ++ for (int i = 0; i < HID_LINUX_MAX_DEV; i++) + { -+ if (fd != -1) -+ close(fd); ++ int fd; ++ char path[sizeof (EVENT_PATH) + 3]; ++ char name[128]; ++ struct input_id id; ++ struct stat st; + -+ sprintf(path, "%s%i", EVENT_PATH, i++); ++ if (hid_linux_driver.evdev_fds[i] >= 0) ++ continue; + ++ snprintf(path, sizeof (path), "%s%i", EVENT_PATH, i + 1); + if (stat(path, &st) == -1) -+ break; -+ -+ for ( c = 0; c < HID_LINUX_MAX_DEV && hid_linux_driver.controller_paths[c]; c++) -+ if (!strcmp(hid_linux_driver.controller_paths[c], path)) -+ break; -+ assert(c != HID_LINUX_MAX_DEV); -+ if (hid_linux_driver.controller_paths[c]) + continue; + + if ((fd = open(path, O_RDONLY)) == -1) -+ break; ++ continue; + -+ if (ioctl(fd, EVIOCGNAME(128), name) == -1) ++ if (ioctl(fd, EVIOCGNAME(sizeof (name)), name) == -1) + { + DEBUG("Input get name failed on %s\n", path); -+ break; ++ close(fd); ++ continue; + } + + if (ioctl(fd, EVIOCGID, &id) == -1) + { + DEBUG("Input get id failed on %s\n", path); ++ close(fd); + continue; + } + + /* Only get devices on usb and i8042 */ + if (id.bustype != BUS_I8042 && id.bustype != BUS_USB) ++ { ++ close(fd); + continue; ++ } ++ ++ hid_linux_driver.evdev_fds[i] = fd; + + if (strcasestr(name, "keyboard")) + { + DEBUG("Add %s %s as a keyboard, fd=%d, bus=%d\n", path, name, fd, id.bustype); -+ controllers = hid_linux_driver.keyboard_fds; ++ qemu_set_fd_handler(fd, hid_linux_keyboard_read, NULL, ++ hid_linux_driver.evdev_fds + i); + } + else + { + DEBUG("Add %s %s as a mouse, fd=%d, bus=%d\n", path, name, fd, id.bustype); -+ controllers = hid_linux_driver.mouse_fds; ++ qemu_set_fd_handler(fd, hid_linux_mouse_read, NULL, ++ hid_linux_driver.evdev_fds + i); + } -+ -+ for ( j = 0; j < (HID_LINUX_MAX_DEV / 2) && controllers[j] != -1; j++) -+ ; -+ assert(j != (HID_LINUX_MAX_DEV / 2)); -+ -+ controllers[j] = fd; -+ controllers[j + 1] = -1; -+ -+ if (grab) -+ { -+ if (!hid_linux_grab_devices(1, controllers + j)) -+ { -+ DEBUG("Grabing failed, try next time...\n"); -+ controllers[j] = -1; -+ break; -+ } -+ } -+ -+ hid_linux_driver.controller_paths[c] = strdup(path); -+ hid_linux_driver.controller_paths[c + 1] = NULL; -+ -+ fd = -1; + } -+ if (fd != -1) -+ close(fd); +} + +void hid_linux_init(void) +{ -+ hid_linux_driver.keyboard_fds[0] = -1; -+ hid_linux_driver.mouse_fds[0] = -1; -+ hid_linux_driver.controller_paths[0] = NULL; ++ for (int *fd = hid_linux_driver.evdev_fds; ++ fd != hid_linux_driver.evdev_fds + HID_LINUX_MAX_DEV; ++ fd++) ++ *fd = -1; + ++#if 0 + while (hid_linux_driver.keyboard_fds[0] == -1) + { + hid_linux_probe(0); + usleep(100000); /* 10 ms */ + } ++#endif /* 0 */ +} diff --git a/qemu-xen.h b/qemu-xen.h -index 0cc5dd8..2646ec7 100644 +index 7883718..afe8f22 100644 --- a/qemu-xen.h +++ b/qemu-xen.h -@@ -107,7 +107,13 @@ int xenstore_write(const char *path, const char *val); +@@ -109,7 +109,13 @@ int xenstore_write(const char *path, const char *val); void xenstore_dm_finished_startup(void); @@ -1278,7 +1273,7 @@ index 0cc5dd8..2646ec7 100644 * not be trusted by qemu code. For variables containing xenstore * paths, `danger' can mean that both the path refers to a diff --git a/vl.c b/vl.c -index e519705..0ffe1ec 100644 +index 1738aa5..45e03c1 100644 --- a/vl.c +++ b/vl.c @@ -234,6 +234,7 @@ CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES]; @@ -1310,7 +1305,7 @@ index e519705..0ffe1ec 100644 /***********************************************************/ /* x86 ISA bus support */ -@@ -4277,6 +4292,7 @@ enum { +@@ -4289,6 +4304,7 @@ enum { QEMU_OPTION_acpi, QEMU_OPTION_vcpus, QEMU_OPTION_vga_passthrough, @@ -1318,7 +1313,7 @@ index e519705..0ffe1ec 100644 /* Debug/Expert options: */ QEMU_OPTION_serial, -@@ -4451,6 +4467,7 @@ static const QEMUOption qemu_options[] = { +@@ -4463,6 +4479,7 @@ static const QEMUOption qemu_options[] = { { "vncunused", 0, QEMU_OPTION_vncunused }, { "vcpus", HAS_ARG, QEMU_OPTION_vcpus }, { "vga-passthrough", 0, QEMU_OPTION_vga_passthrough }, @@ -1326,7 +1321,7 @@ index e519705..0ffe1ec 100644 #if defined(CONFIG_XEN) && !defined(CONFIG_DM) { "xen-domid", HAS_ARG, QEMU_OPTION_xen_domid }, { "xen-create", 0, QEMU_OPTION_xen_create }, -@@ -5287,6 +5304,9 @@ int main(int argc, char **argv, char **envp) +@@ -5299,6 +5316,9 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_vga_passthrough: vga_passthrough = 1; break; @@ -1336,7 +1331,7 @@ index e519705..0ffe1ec 100644 case QEMU_OPTION_direct_pci: direct_pci = optarg; break; -@@ -6053,6 +6073,9 @@ int main(int argc, char **argv, char **envp) +@@ -6065,6 +6085,9 @@ int main(int argc, char **argv, char **envp) close(fd); } @@ -1345,9 +1340,9 @@ index e519705..0ffe1ec 100644 + xenstore_dm_finished_startup(); - main_loop(); + #ifndef CONFIG_STUBDOM diff --git a/xen-hooks.mak b/xen-hooks.mak -index d171928..15ba4d1 100644 +index 3b60724..8dc3885 100644 --- a/xen-hooks.mak +++ b/xen-hooks.mak @@ -37,6 +37,8 @@ OBJS += helper2.o @@ -1360,10 +1355,10 @@ index d171928..15ba4d1 100644 CONFIG_AUDIO=1 diff --git a/xenstore.c b/xenstore.c -index 01afcf0..20ca8cf 100644 +index 3cd2ba6..17136a3 100644 --- a/xenstore.c +++ b/xenstore.c -@@ -1727,3 +1727,63 @@ void xenstore_dm_finished_startup(void) +@@ -1741,3 +1741,63 @@ void xenstore_dm_finished_startup(void) free(buf); free(path); } -- 2.39.5