From 403a952545ed20d1ad4879a318278adfef5f76eb Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Sun, 13 Mar 2022 13:34:04 +0100 Subject: [PATCH] Fix double keypresses --- gui-daemon/xside.c | 94 +++++++++++++--------------------------------- 1 file changed, 26 insertions(+), 68 deletions(-) diff --git a/gui-daemon/xside.c b/gui-daemon/xside.c index 5d35039c..18eca19f 100644 --- a/gui-daemon/xside.c +++ b/gui-daemon/xside.c @@ -383,14 +383,19 @@ static Window mkwindow(Ghandles * g, struct windowdata *vm_window) // select xinput events XIEventMask xi_mask; - xi_mask.deviceid = XIAllDevices; + xi_mask.deviceid = XIAllMasterDevices; // https://stackoverflow.com/questions/44095001/getting-double-rawkeypress-events-using-xinput2 xi_mask.mask_len = XIMaskLen(XI_LASTEVENT); - xi_mask.mask = calloc(xi_mask.mask_len, sizeof(char)); + if (!(xi_mask.mask = calloc(xi_mask.mask_len, sizeof(char)))) { + fputs("Out of memory!\n", stderr); + exit(1); + } XISetMask(xi_mask.mask, XI_KeyPress); XISetMask(xi_mask.mask, XI_KeyRelease); XISetMask(xi_mask.mask, XI_FocusIn); XISetMask(xi_mask.mask, XI_FocusOut); XISelectEvents(g->display, child_win, &xi_mask, 1); + free(xi_mask.mask); + XSync(g->display, False); XSetWMProtocols(g->display, child_win, &g->wmDeleteMessage, 1); @@ -664,6 +669,7 @@ static void mkghandles(Ghandles * g) fprintf(stderr, "MIT-SHM X extension missing!\n"); if (!XQueryExtension(g->display, "XInputExtension", &g->xi_opcode, &ev_base, &err_base)) { fprintf(stderr, "X Input extension not available. Key press events not available. Upgrade your X11 server now.\n"); + exit(1); } /* get the work area */ XSelectInput(g->display, g->root_win, PropertyChangeMask); @@ -1355,7 +1361,10 @@ static void process_xievent_keypress(Ghandles * g, const XIDeviceEvent * ev) struct msg_hdr hdr; struct msg_keypress k; CHECK_NONMANAGED_WINDOW(g, ev->event); + // yes, ev->event is the window number update_wm_user_time(g, ev->event, ev->time); + if (ev->flags & XIKeyRepeat) + return; // don't send key repeat events if (is_special_keypress(g, ev, vm_window->remote_winid)) return; k.type = ev->evtype; // ev->type is always Generic Event @@ -1888,6 +1897,16 @@ static void handle_configure_from_vm(Ghandles * g, struct windowdata *vm_window) } } +static void send_keymap_notify(Ghandles * g) +{ + struct msg_hdr hdr; + char keys[32]; + XQueryKeymap(g->display, keys); + hdr.type = MSG_KEYMAP_NOTIFY; + hdr.window = 0; + write_message(g->vchan, hdr, keys); +} + /* handle local Xserver event: EnterNotify, LeaveNotify * send it to VM, but alwo we use it to fix docked * window position */ @@ -1898,11 +1917,7 @@ static void process_xevent_crossing(Ghandles * g, const XCrossingEvent * ev) CHECK_NONMANAGED_WINDOW(g, ev->window); if (ev->type == EnterNotify) { - char keys[32]; - XQueryKeymap(g->display, keys); - hdr.type = MSG_KEYMAP_NOTIFY; - hdr.window = 0; - write_message(g->vchan, hdr, keys); + send_keymap_notify(g); } /* move tray to correct position in VM */ if (vm_window->is_docked && @@ -1948,13 +1963,10 @@ static void process_xievent_focus(Ghandles * g, const XILeaveEvent * ev) struct msg_hdr hdr; struct msg_focus k; CHECK_NONMANAGED_WINDOW(g, ev->event); + update_wm_user_time(g, ev->event, ev->time); if (ev->type == XI_FocusIn) { - char keys[32]; - XQueryKeymap(g->display, keys); - hdr.type = MSG_KEYMAP_NOTIFY; - hdr.window = 0; - write_message(g->vchan, hdr, keys); + send_keymap_notify(g); } hdr.type = MSG_FOCUS; hdr.window = vm_window->remote_winid; @@ -2309,11 +2321,7 @@ static void process_xevent_xembed(Ghandles * g, const XClientMessageEvent * ev) } else if (ev->data.l[1] == XEMBED_FOCUS_IN) { struct msg_hdr hdr; struct msg_focus k; - char keys[32]; - XQueryKeymap(g->display, keys); - hdr.type = MSG_KEYMAP_NOTIFY; - hdr.window = 0; - write_message(g->vchan, hdr, keys); + send_keymap_notify(g); hdr.type = MSG_FOCUS; hdr.window = vm_window->remote_winid; k.type = FocusIn; @@ -2324,54 +2332,6 @@ static void process_xevent_xembed(Ghandles * g, const XClientMessageEvent * ev) } -// reference code for handling xi2 events -// static void process_xievent(Ghandles * g, XIDeviceEvent event) { -// switch (event.evtype) -// { -// case XI_RawButtonPress: -// case XI_RawButtonRelease: -// case XI_RawMotion: -// case XI_RawKeyPress: -// case XI_RawKeyRelease: -// break; -// case XI_KeyPress: -// case XI_KeyRelease: -// printf(" flags: %s\n", (event->flags & XIKeyRepeat) ? "repeat" : ""); -// // TODO: handle events -// break; -// case XI_ButtonPress: -// case XI_ButtonRelease: -// case XI_Motion: -// printf(" flags: %s\n", (event->flags & XIPointerEmulated) ? "emulated" : ""); -// // TODO: handle events -// break; -// } -// } - -// static XKeyEvent xkeyevent_from_xinput_event(const XIDeviceEvent* xi_event) { -// XKeyEvent fake_event; -// switch (xi_event->evtype) { -// case XI_KeyPress: fake_event.type = KeyPress; break; -// case XI_KeyRelease: fake_event.type = KeyRelease; break; -// default: assert(false); // stop immediately -// } -// fake_event.serial = xi_event->serial; -// fake_event.send_event = false; -// fake_event.display = xi_event->display; -// fake_event.window = xi_event->event; -// fake_event.root = xi_event->root; -// fake_event.subwindow = xi_event->child; // from Manual page XKeyEvent(3) -// fake_event.time = xi_event->time; -// fake_event.x = xi_event->event_x; -// fake_event.y = xi_event->event_y; -// fake_event.x_root = xi_event->root_x; -// fake_event.y_root = xi_event->root_y; -// fake_event.state = xi_event->mods.effective; -// fake_event.keycode = xi_event->detail; -// fake_event.same_screen = true; // don't know how to fill this -// return fake_event; -// } - /* dispatch local Xserver event */ static void process_xevent(Ghandles * g) { @@ -2383,13 +2343,11 @@ static void process_xevent(Ghandles * g) cookie->extension == g->xi_opcode) { XIEvent* xi_event = cookie->data; // from test_xi2.c in xinput cli utility - XIDeviceEvent * xi_device = (XIDeviceEvent *)xi_event; switch (xi_event->evtype) { // ideally raw input events are better, but I'm relying on X server's built-in event filtering and routing feature here case XI_KeyPress: case XI_KeyRelease: - if (xi_device && (xi_device->flags & XIKeyRepeat)) break; // don't send key repeat events - process_xievent_keypress(g, xi_device); + process_xievent_keypress(g, (XIDeviceEvent *)xi_event); break; case XI_FocusIn: case XI_FocusOut: