Skip to content

Commit

Permalink
Fix double keypresses
Browse files Browse the repository at this point in the history
  • Loading branch information
iacore committed Jun 17, 2022
1 parent 110a6a9 commit 403a952
Showing 1 changed file with 26 additions and 68 deletions.
94 changes: 26 additions & 68 deletions gui-daemon/xside.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 */
Expand All @@ -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 &&
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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)
{
Expand All @@ -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:
Expand Down

0 comments on commit 403a952

Please sign in to comment.