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-legacy.h"
28 #include <X11/Xutil.h>
29 #include <X11/extensions/XInput2.h>
30 #include <X11/XKBlib.h>
37 } AtspiLegacyKeyModifier;
39 typedef struct _AtspiDeviceLegacyPrivate AtspiDeviceLegacyPrivate;
40 struct _AtspiDeviceLegacyPrivate
42 AtspiDeviceListener *listener;
48 guint virtual_mods_enabled;
49 gboolean keyboard_grabbed;
50 unsigned int numlock_physical_mask;
53 GObjectClass *device_legacy_parent_class;
55 G_DEFINE_TYPE_WITH_CODE (AtspiDeviceLegacy, atspi_device_legacy,
57 G_ADD_PRIVATE (AtspiDeviceLegacy))
61 find_virtual_mapping (AtspiDeviceLegacy *legacy_device, gint keycode)
63 AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device);
66 for (l = priv->modifiers; l; l = l->next)
68 AtspiLegacyKeyModifier *entry = l->data;
69 if (entry->keycode == keycode)
70 return entry->modifier;
77 set_virtual_modifier (AtspiDeviceLegacy *legacy_device, gint keycode, gboolean enabled)
79 AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device);
80 guint modifier = find_virtual_mapping (legacy_device, keycode);
83 priv->virtual_mods_enabled |= modifier;
85 priv->virtual_mods_enabled &= ~modifier;
90 key_cb (AtspiDeviceEvent *event, void *user_data)
92 AtspiDeviceLegacy *legacy_device = ATSPI_DEVICE_LEGACY (user_data);
93 AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device);
94 gboolean ret = priv->keyboard_grabbed;
97 set_virtual_modifier (legacy_device, event->hw_code,
98 event->type == (AtspiEventType)ATSPI_KEY_PRESS);
100 modifiers = event->modifiers | priv->virtual_mods_enabled;
101 if (modifiers & (1 << ATSPI_MODIFIER_NUMLOCK))
102 modifiers &= ~priv->numlock_physical_mask;
104 ret |= atspi_device_notify_key (ATSPI_DEVICE (legacy_device),
105 event->type == (AtspiEventType)ATSPI_KEY_PRESS,
106 event->hw_code, event->id,
108 event->event_string);
110 g_boxed_free (ATSPI_TYPE_DEVICE_EVENT, event);
115 atspi_device_legacy_get_locked_modifiers (AtspiDevice *device)
118 AtspiDeviceLegacy *legacy_device = ATSPI_DEVICE_LEGACY (device);
119 AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device);
120 XkbStateRec state_rec;
122 memset (&state_rec, 0, sizeof (state_rec));
123 XkbGetState (priv->display, XkbUseCoreKbd, &state_rec);
124 return state_rec.locked_mods;
131 check_virtual_modifier (AtspiDeviceLegacy *legacy_device, guint modifier)
133 AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device);
136 if (modifier == (1 << ATSPI_MODIFIER_NUMLOCK))
139 for (l = priv->modifiers; l; l = l->next)
141 AtspiLegacyKeyModifier *entry = l->data;
142 if (entry->modifier == modifier)
150 get_unused_virtual_modifier (AtspiDeviceLegacy *legacy_device)
154 while (ret < 0x10000)
156 if (!check_virtual_modifier (legacy_device, ret))
165 atspi_device_legacy_map_modifier (AtspiDevice *device, gint keycode)
167 AtspiDeviceLegacy *legacy_device = ATSPI_DEVICE_LEGACY (device);
168 AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device);
170 AtspiLegacyKeyModifier *entry;
174 desc = XkbGetMap (priv->display, XkbModifierMapMask, XkbUseCoreKbd);
176 if (keycode < desc->min_key_code || keycode >= desc->max_key_code)
178 XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
179 g_warning ("Passed invalid keycode %d", keycode);
183 ret = desc->map->modmap[keycode];
184 XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
185 if (ret & (ShiftMask | ControlMask))
189 ret = find_virtual_mapping (legacy_device, keycode);
193 ret = get_unused_virtual_modifier (legacy_device);
195 entry = g_new (AtspiLegacyKeyModifier, 1);
196 entry->keycode = keycode;
197 entry->modifier = ret;
198 priv->modifiers = g_slist_append (priv->modifiers, entry);
204 atspi_device_legacy_unmap_modifier (AtspiDevice *device, gint keycode)
206 AtspiDeviceLegacy *legacy_device = ATSPI_DEVICE_LEGACY (device);
207 AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device);
210 for (l = priv->modifiers; l; l = l->next)
212 AtspiLegacyKeyModifier *entry = l->data;
213 if (entry->keycode == keycode)
215 priv->modifiers = g_slist_remove (priv->modifiers, entry);
223 atspi_device_legacy_get_modifier (AtspiDevice *device, gint keycode)
225 AtspiDeviceLegacy *legacy_device = ATSPI_DEVICE_LEGACY (device);
227 AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device);
231 desc = XkbGetMap (priv->display, XkbModifierMapMask, XkbUseCoreKbd);
233 if (keycode < desc->min_key_code || keycode >= desc->max_key_code)
235 XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
236 g_warning ("Passed invalid keycode %d", keycode);
240 ret = desc->map->modmap[keycode];
241 XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
246 return find_virtual_mapping (legacy_device, keycode);
250 atspi_device_legacy_grab_keyboard (AtspiDevice *device)
252 AtspiDeviceLegacy *legacy_device = ATSPI_DEVICE_LEGACY (device);
253 AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device);
255 priv->keyboard_grabbed = TRUE;
260 atspi_device_legacy_ungrab_keyboard (AtspiDevice *device)
262 AtspiDeviceLegacy *legacy_device = ATSPI_DEVICE_LEGACY (device);
263 AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device);
265 priv->keyboard_grabbed = FALSE;
269 atspi_device_legacy_init (AtspiDeviceLegacy *device)
271 AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (device);
274 priv->listener = atspi_device_listener_new (key_cb, device, NULL);
275 for (i = 0; i < 256; i++)
276 atspi_register_keystroke_listener (priv->listener, NULL, i, 3, ATSPI_KEYLISTENER_SYNCHRONOUS | ATSPI_KEYLISTENER_CANCONSUME, NULL);
279 priv->display=XOpenDisplay("");
281 priv->window = DefaultRootWindow(priv->display);
282 priv->numlock_physical_mask = XkbKeysymToModifiers (priv->display,
289 atspi_device_legacy_finalize (GObject *object)
291 AtspiDeviceLegacy *device = ATSPI_DEVICE_LEGACY (object);
292 AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (device);
294 g_clear_object (&priv->listener);
295 device_legacy_parent_class->finalize (object);
300 atspi_device_legacy_class_init (AtspiDeviceLegacyClass *klass)
302 GObjectClass *object_class = (GObjectClass *) klass;
303 AtspiDeviceClass *device_class = ATSPI_DEVICE_CLASS (klass);
305 device_legacy_parent_class = g_type_class_peek_parent (klass);
306 object_class->finalize = atspi_device_legacy_finalize;
307 device_class->map_modifier = atspi_device_legacy_map_modifier;
308 device_class->unmap_modifier = atspi_device_legacy_unmap_modifier;
309 device_class->get_modifier = atspi_device_legacy_get_modifier;
310 device_class->get_locked_modifiers = atspi_device_legacy_get_locked_modifiers;
311 device_class->grab_keyboard = atspi_device_legacy_grab_keyboard;
312 device_class->ungrab_keyboard = atspi_device_legacy_ungrab_keyboard;
316 * atspi_device_legacy_new:
318 * Creates a new #AtspiDeviceLegacy.
320 * Returns: (transfer full): a pointer to a newly-created #AtspiDeviceLegacy.
324 atspi_device_legacy_new ()
326 AtspiDeviceLegacy *device = g_object_new (atspi_device_legacy_get_type (), NULL);