2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5 * Copyright 2020 SUSE LLC.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
23 #include "atspi-private.h"
24 #include "atspi-device-x11.h"
27 #include <X11/Xutil.h>
28 #include <X11/extensions/XInput2.h>
29 #include <X11/XKBlib.h>
32 #define ATSPI_VIRTUAL_MODIFIER_MASK 0x0000f000
34 typedef struct _AtspiDeviceX11Private AtspiDeviceX11Private;
35 struct _AtspiDeviceX11Private
45 guint virtual_mods_enabled;
46 gboolean keyboard_grabbed;
47 unsigned int numlock_physical_mask;
50 GObjectClass *device_x11_parent_class;
52 typedef struct _DisplaySource
57 GPollFD event_poll_fd;
64 } AtspiX11KeyModifier;
68 AtspiKeyDefinition *kd;
73 event_prepare (GSource *source, gint *timeout)
75 Display *display = ((DisplaySource *)source)->display;
79 retval = XPending (display);
85 event_check (GSource *source)
87 DisplaySource *display_source = (DisplaySource*)source;
90 if (display_source->event_poll_fd.revents & G_IO_IN)
91 retval = XPending (display_source->display);
99 xi2keyevent (XIDeviceEvent *xievent, XEvent *xkeyevent)
101 memset (xkeyevent, 0, sizeof (*xkeyevent));
103 switch (xievent->evtype)
106 xkeyevent->type = KeyPress;
109 xkeyevent->type = KeyRelease;
114 xkeyevent->xkey.serial = xievent->serial;
115 xkeyevent->xkey.send_event = xievent->send_event;
116 xkeyevent->xkey.display = xievent->display;
117 xkeyevent->xkey.window = xievent->event;
118 xkeyevent->xkey.root = xievent->root;
119 xkeyevent->xkey.subwindow = xievent->child;
120 xkeyevent->xkey.time = xievent->time;
121 xkeyevent->xkey.x = xievent->event_x;
122 xkeyevent->xkey.y = xievent->event_y;
123 xkeyevent->xkey.x_root = xievent->root_x;
124 xkeyevent->xkey.y_root = xievent->root_y;
125 xkeyevent->xkey.state = xievent->mods.effective;
126 xkeyevent->xkey.keycode = xievent->detail;
127 xkeyevent->xkey.same_screen = 1;
130 G_DEFINE_TYPE_WITH_CODE (AtspiDeviceX11, atspi_device_x11,
132 G_ADD_PRIVATE (AtspiDeviceX11))
136 find_virtual_mapping (AtspiDeviceX11 *x11_device, gint keycode)
138 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
141 for (l = priv->modifiers; l; l = l->next)
143 AtspiX11KeyModifier *entry = l->data;
144 if (entry->keycode == keycode)
145 return entry->modifier;
152 grab_should_be_enabled (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab)
154 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
156 /* If the whole keyboard is grabbed, then all keys are grabbed elsewhere */
157 if (priv->keyboard_grabbed)
160 guint virtual_mods_used = grab->kd->modifiers & ATSPI_VIRTUAL_MODIFIER_MASK;
161 return ((priv->virtual_mods_enabled & virtual_mods_used) == virtual_mods_used);
165 grab_has_active_duplicate (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab)
167 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
170 for (l = priv->key_grabs; l; l = l->next)
172 AtspiX11KeyGrab *other = l->data;
173 if (other != grab && other->enabled && other->kd->keycode == grab->kd->keycode && (other->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK) == (grab->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK))
180 grab_key_aux (AtspiDeviceX11 *x11_device, int keycode, int modmask)
182 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
183 XIGrabModifiers xi_modifiers;
184 XIEventMask eventmask;
185 unsigned char mask[XIMaskLen (XI_LASTEVENT)] = { 0 };
187 xi_modifiers.modifiers = modmask;
188 xi_modifiers.status = 0;
190 eventmask.deviceid = XIAllDevices;
191 eventmask.mask_len = sizeof(mask);
192 eventmask.mask = mask;
194 XISetMask (mask, XI_KeyPress);
195 XISetMask (mask, XI_KeyRelease);
197 XIGrabKeycode (priv->display, XIAllMasterDevices, keycode, priv->window, XIGrabModeSync, XIGrabModeAsync, False, &eventmask, 1, &xi_modifiers);
201 grab_key (AtspiDeviceX11 *x11_device, int keycode, int modmask)
203 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
205 grab_key_aux (x11_device, keycode, modmask);
206 if (!(modmask & LockMask))
207 grab_key_aux (x11_device, keycode, modmask | LockMask);
208 if (!(modmask & priv->numlock_physical_mask))
210 grab_key_aux (x11_device, keycode, modmask | priv->numlock_physical_mask);
211 if (!(modmask & LockMask))
212 grab_key_aux (x11_device, keycode, modmask | LockMask | priv->numlock_physical_mask);
217 enable_key_grab (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab)
219 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
221 g_return_if_fail (priv->display != NULL);
223 if (!grab_has_active_duplicate (x11_device, grab))
224 grab_key (x11_device, grab->kd->keycode, grab->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK);
225 grab->enabled = TRUE;
229 ungrab_key_aux (AtspiDeviceX11 *x11_device, int keycode, int modmask)
231 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
232 XIGrabModifiers xi_modifiers;
234 xi_modifiers.modifiers = modmask;
235 xi_modifiers.status = 0;
237 XIUngrabKeycode (priv->display, XIAllMasterDevices, keycode, priv->window, sizeof(xi_modifiers), &xi_modifiers);
241 ungrab_key (AtspiDeviceX11 *x11_device, int keycode, int modmask)
243 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
245 ungrab_key_aux (x11_device, keycode, modmask);
246 if (!(modmask & LockMask))
247 ungrab_key_aux (x11_device, keycode, modmask | LockMask);
248 if (!(modmask & priv->numlock_physical_mask))
250 ungrab_key_aux (x11_device, keycode, modmask | priv->numlock_physical_mask);
251 if (!(modmask & LockMask))
252 ungrab_key_aux (x11_device, keycode, modmask | LockMask | priv->numlock_physical_mask);
257 disable_key_grab (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab)
259 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
261 g_return_if_fail (priv->display != NULL);
266 grab->enabled = FALSE;
268 if (grab_has_active_duplicate (x11_device, grab))
271 ungrab_key (x11_device, grab->kd->keycode, grab->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK);
275 refresh_key_grabs (AtspiDeviceX11 *x11_device)
277 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
280 for (l = priv->key_grabs; l; l = l->next)
282 AtspiX11KeyGrab *grab = l->data;
283 gboolean new_enabled = grab_should_be_enabled (x11_device, grab);
284 if (new_enabled && !grab->enabled)
285 enable_key_grab (x11_device, grab);
286 else if (grab->enabled && !new_enabled)
287 disable_key_grab (x11_device, grab);
292 set_virtual_modifier (AtspiDeviceX11 *x11_device, gint keycode, gboolean enabled)
294 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
295 guint modifier = find_virtual_mapping (x11_device, keycode);
302 if (priv->virtual_mods_enabled & modifier)
304 priv->virtual_mods_enabled |= modifier;
308 if (!(priv->virtual_mods_enabled & modifier))
310 priv->virtual_mods_enabled &= ~modifier;
313 refresh_key_grabs (x11_device);
317 do_event_dispatch (gpointer user_data)
319 AtspiDeviceX11 *device = user_data;
320 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (device);
321 Display *display = priv->display;
325 XComposeStatus status;
328 while (XPending (display))
330 XNextEvent (display, &xevent);
337 XLookupString(&xevent.xkey, text, sizeof (text), &keysym, &status);
338 modifiers = xevent.xkey.state | priv->virtual_mods_enabled;
339 if (modifiers & priv->numlock_physical_mask)
341 modifiers |= (1 << ATSPI_MODIFIER_NUMLOCK);
342 modifiers &= ~priv->numlock_physical_mask;
344 atspi_device_notify_key (ATSPI_DEVICE (device), (xevent.type == KeyPress), xevent.xkey.keycode, keysym, modifiers, text);
347 if (xevent.xcookie.extension == priv->xi_opcode)
349 XGetEventData(priv->display, &xevent.xcookie);
350 XIRawEvent *xiRawEv = (XIRawEvent *) xevent.xcookie.data;
351 XIDeviceEvent *xiDevEv = (XIDeviceEvent *) xevent.xcookie.data;
352 switch (xevent.xcookie.evtype)
356 xi2keyevent (xiDevEv, &keyevent);
357 XLookupString((XKeyEvent *)&keyevent, text, sizeof (text), &keysym, &status);
360 /* The deviceid can change. Would be nice to find a better way of
362 if (priv->device_id && priv->device_id_alt && xiDevEv->deviceid != priv->device_id && xiDevEv->deviceid != priv->device_id_alt)
363 priv->device_id = priv->device_id_alt = 0;
364 else if (priv->device_id && !priv->device_id_alt && xiDevEv->deviceid != priv->device_id)
365 priv->device_id_alt = xiDevEv->deviceid;
366 if (!priv->device_id)
367 priv->device_id = xiDevEv->deviceid;
368 set_virtual_modifier (device, xiRawEv->detail, xevent.xcookie.evtype == XI_KeyPress);
369 modifiers = keyevent.xkey.state | priv->virtual_mods_enabled;
370 if (modifiers & priv->numlock_physical_mask)
371 modifiers |= (1 << ATSPI_MODIFIER_NUMLOCK);
372 if (xiDevEv->deviceid == priv->device_id)
373 atspi_device_notify_key (ATSPI_DEVICE (device), (xevent.xcookie.evtype == XI_KeyPress), xiRawEv->detail, keysym, modifiers, text);
374 /* otherwise it's probably a duplicate event from a key grab */
375 XFreeEventData (priv->display, &xevent.xcookie);
380 if (XFilterEvent (&xevent, None))
388 event_dispatch (GSource *source, GSourceFunc callback, gpointer user_data)
391 callback (user_data);
392 return G_SOURCE_CONTINUE;
395 static GSourceFuncs event_funcs = {
403 display_source_new (Display *display)
405 GSource *source = g_source_new (&event_funcs, sizeof (DisplaySource));
406 DisplaySource *display_source = (DisplaySource *) source;
407 g_source_set_name (source, "[at-spi2-core] display_source_funcs");
409 display_source->display = display;
415 create_event_source (AtspiDeviceX11 *device)
417 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (device);
418 DisplaySource *display_source;
420 int connection_number = ConnectionNumber (priv->display);
422 priv->source = display_source_new (priv->display);
423 display_source = (DisplaySource *)priv->source;
425 g_source_set_priority (priv->source, G_PRIORITY_DEFAULT);
427 display_source->event_poll_fd.fd = connection_number;
428 display_source->event_poll_fd.events = G_IO_IN;
430 g_source_add_poll (priv->source, &display_source->event_poll_fd);
431 g_source_set_can_recurse (priv->source, TRUE);
432 g_source_set_callback (priv->source, do_event_dispatch, device, NULL);
433 g_source_attach (priv->source, NULL);
437 check_virtual_modifier (AtspiDeviceX11 *x11_device, guint modifier)
439 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
442 if (modifier == (1 << ATSPI_MODIFIER_NUMLOCK))
445 for (l = priv->modifiers; l; l = l->next)
447 AtspiX11KeyModifier *entry = l->data;
448 if (entry->modifier == modifier)
456 get_unused_virtual_modifier (AtspiDeviceX11 *x11_device)
460 while (ret < 0x10000)
462 if (!check_virtual_modifier (x11_device, ret))
471 atspi_device_x11_map_modifier (AtspiDevice *device, gint keycode)
473 AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
474 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
477 AtspiX11KeyModifier *entry;
479 desc = XkbGetMap (priv->display, XkbModifierMapMask, XkbUseCoreKbd);
481 if (keycode < desc->min_key_code || keycode >= desc->max_key_code)
483 XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
484 g_warning ("Passed invalid keycode %d", keycode);
488 ret = desc->map->modmap[keycode];
489 XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
490 if (ret & (ShiftMask | ControlMask))
493 ret = find_virtual_mapping (x11_device, keycode);
497 ret = get_unused_virtual_modifier (x11_device);
499 entry = g_new (AtspiX11KeyModifier, 1);
500 entry->keycode = keycode;
501 entry->modifier = ret;
502 priv->modifiers = g_slist_append (priv->modifiers, entry);
508 atspi_device_x11_unmap_modifier (AtspiDevice *device, gint keycode)
510 AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
511 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
514 for (l = priv->modifiers; l; l = l->next)
516 AtspiX11KeyModifier *entry = l->data;
517 if (entry->keycode == keycode)
519 priv->modifiers = g_slist_remove (priv->modifiers, entry);
527 atspi_device_x11_get_modifier (AtspiDevice *device, gint keycode)
529 AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
530 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
534 desc = XkbGetMap (priv->display, XkbModifierMapMask, XkbUseCoreKbd);
536 if (keycode < desc->min_key_code || keycode >= desc->max_key_code)
538 XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
539 g_warning ("Passed invalid keycode %d", keycode);
543 ret = desc->map->modmap[keycode];
544 XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
548 return find_virtual_mapping (x11_device, keycode);
552 atspi_device_x11_init (AtspiDeviceX11 *device)
554 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (device);
555 int first_event, first_error;
557 priv->display=XOpenDisplay("");
558 g_return_if_fail (priv->display != NULL);
559 priv->window = DefaultRootWindow(priv->display);
561 if (XQueryExtension(priv->display, "XInputExtension", &priv->xi_opcode, &first_event, &first_error))
565 if (XIQueryVersion(priv->display, &major, &minor) != BadRequest)
567 XIEventMask eventmask;
568 unsigned char mask[XIMaskLen (XI_LASTEVENT)] = { 0 };
570 eventmask.deviceid = XIAllDevices;
571 eventmask.mask_len = sizeof(mask);
572 eventmask.mask = mask;
574 XISetMask (mask, XI_KeyPress);
575 XISetMask (mask, XI_KeyRelease);
576 XISetMask (mask, XI_ButtonPress);
577 XISetMask (mask, XI_ButtonRelease);
578 XISetMask (mask, XI_Motion);
579 XISelectEvents (priv->display, priv->window, &eventmask, 1);
580 create_event_source (device);
584 priv->numlock_physical_mask = XkbKeysymToModifiers (priv->display,
589 atspi_device_x11_finalize (GObject *object)
591 AtspiDeviceX11 *device = ATSPI_DEVICE_X11 (object);
592 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (device);
595 for (l = priv->key_grabs; l; l = l->next)
597 AtspiX11KeyGrab *grab = l->data;
598 disable_key_grab (device, grab);
599 g_boxed_free (ATSPI_TYPE_KEY_DEFINITION, grab->kd);
602 g_slist_free (priv->key_grabs);
603 priv->key_grabs = NULL;
605 g_slist_free_full (priv->modifiers, g_free);
606 priv->modifiers = NULL;
610 g_source_destroy ((GSource *) priv->source);
611 g_source_unref ((GSource *) priv->source);
615 device_x11_parent_class->finalize (object);
620 atspi_device_x11_add_key_grab (AtspiDevice *device, AtspiKeyDefinition *kd)
622 AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
623 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
624 AtspiX11KeyGrab *grab;
626 grab = g_new (AtspiX11KeyGrab, 1);
627 grab->kd = g_boxed_copy (ATSPI_TYPE_KEY_DEFINITION, kd);
628 grab->enabled = FALSE;
629 priv->key_grabs = g_slist_append (priv->key_grabs, grab);
630 if (grab_should_be_enabled (x11_device, grab))
631 enable_key_grab (x11_device, grab);
635 atspi_device_x11_remove_key_grab (AtspiDevice *device, guint id)
637 AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
638 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
639 AtspiKeyDefinition *kd;
642 kd = atspi_device_get_grab_by_id (device, id);
644 for (l = priv->key_grabs; l; l = g_slist_next (l))
646 AtspiX11KeyGrab *other = l->data;
647 if (other->kd->keycode == kd->keycode && other->kd->modifiers == kd->modifiers)
649 disable_key_grab (x11_device, other);
650 priv->key_grabs = g_slist_remove (priv->key_grabs, other);
657 atspi_device_x11_get_locked_modifiers (AtspiDevice *device)
659 AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
660 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
661 XkbStateRec state_rec;
663 memset (&state_rec, 0, sizeof (state_rec));
664 XkbGetState (priv->display, XkbUseCoreKbd, &state_rec);
665 return state_rec.locked_mods;
669 get_keycode_range (AtspiDeviceX11 *x11_device, int *min, int *max)
671 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
674 desc = XkbGetMap (priv->display, XkbModifierMapMask, XkbUseCoreKbd);
675 *min = desc->min_key_code;
676 *max = desc->max_key_code;
677 XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
681 atspi_device_x11_grab_keyboard (AtspiDevice *device)
683 AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
684 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
688 g_return_val_if_fail (priv->display != NULL, FALSE);
690 /* THis seems like the right thing to do, but it fails for me */
691 return (XGrabKeyboard (priv->display, priv->window, TRUE, GrabModeAsync, GrabModeSync, CurrentTime)) == 0;
693 if (priv->keyboard_grabbed)
695 priv->keyboard_grabbed = TRUE;
696 refresh_key_grabs (x11_device);
698 get_keycode_range (x11_device, &min, &max);
699 for (i = min; i < max; i++)
700 grab_key (x11_device, i, 0);
706 atspi_device_x11_ungrab_keyboard (AtspiDevice *device)
708 AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
709 AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
713 g_return_if_fail (priv->display != NULL);
715 XUngrabKeyboard (priv->display, CurrentTime);
717 if (!priv->keyboard_grabbed)
719 priv->keyboard_grabbed = FALSE;
721 get_keycode_range (x11_device, &min, &max);
722 for (i = min; i < max; i++)
723 ungrab_key (x11_device, i, 0);
725 refresh_key_grabs (x11_device);
730 atspi_device_x11_class_init (AtspiDeviceX11Class *klass)
732 AtspiDeviceClass *device_class = ATSPI_DEVICE_CLASS (klass);
733 GObjectClass *object_class = (GObjectClass *) klass;
735 device_x11_parent_class = g_type_class_peek_parent (klass);
736 device_class->add_key_grab = atspi_device_x11_add_key_grab;
737 device_class->map_modifier = atspi_device_x11_map_modifier;
738 device_class->unmap_modifier = atspi_device_x11_unmap_modifier;
739 device_class->get_modifier = atspi_device_x11_get_modifier;
740 device_class->remove_key_grab = atspi_device_x11_remove_key_grab;
741 device_class->get_locked_modifiers = atspi_device_x11_get_locked_modifiers;
742 device_class->grab_keyboard = atspi_device_x11_grab_keyboard;
743 device_class->ungrab_keyboard = atspi_device_x11_ungrab_keyboard;
744 object_class->finalize = atspi_device_x11_finalize;
748 * atspi_device_x11_new:
750 * Creates a new #AtspiDeviceX11.
752 * Returns: (transfer full): a pointer to a newly-created #AtspiDeviceX11.
756 atspi_device_x11_new ()
758 AtspiDeviceX11 *device = g_object_new (atspi_device_x11_get_type (), NULL);