diff options
author | Mike Gorse <mgorse@suse.com> | 2021-01-27 16:41:39 -0600 |
---|---|---|
committer | Mike Gorse <mgorse@suse.com> | 2021-01-27 16:41:39 -0600 |
commit | c6b2af03425bacfef25b08f4730d6f7628743681 (patch) | |
tree | 1d0a9c6486a1d26a9894382b809f8f219994c9e5 | |
parent | 47831726d956169369536ff610f54173fda5bc14 (diff) | |
download | at-spi2-core-c6b2af03425bacfef25b08f4730d6f7628743681.tar.gz |
Device fixes
-rw-r--r-- | atspi/atspi-device-legacy.c | 229 | ||||
-rw-r--r-- | atspi/atspi-device-x11.c | 129 | ||||
-rw-r--r-- | atspi/atspi-device.c | 3 |
3 files changed, 331 insertions, 30 deletions
diff --git a/atspi/atspi-device-legacy.c b/atspi/atspi-device-legacy.c index fbae5f03..6950bc37 100644 --- a/atspi/atspi-device-legacy.c +++ b/atspi/atspi-device-legacy.c @@ -23,10 +23,30 @@ #include "atspi-private.h" #include "atspi-device-legacy.h" +#ifdef HAVE_X11 +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/extensions/XInput2.h> +#include <X11/XKBlib.h> +#endif + +typedef struct +{ + guint keycode; + guint modifier; +} AtspiLegacyKeyModifier; + typedef struct _AtspiDeviceLegacyPrivate AtspiDeviceLegacyPrivate; struct _AtspiDeviceLegacyPrivate { AtspiDeviceListener *listener; +#ifdef HAVE_X11 + Display *display; + Window window; +#endif + GSList *modifiers; + guint virtual_mods_enabled; + gboolean keyboard_grabbed; }; GObjectClass *device_legacy_parent_class; @@ -35,12 +55,203 @@ G_DEFINE_TYPE_WITH_CODE (AtspiDeviceLegacy, atspi_device_legacy, ATSPI_TYPE_DEVICE, G_ADD_PRIVATE (AtspiDeviceLegacy)) + +static guint +find_virtual_mapping (AtspiDeviceLegacy *legacy_device, gint keycode) +{ + AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device); + GSList *l; + + for (l = priv->modifiers; l; l = l->next) + { + AtspiLegacyKeyModifier *entry = l->data; + if (entry->keycode == keycode) + return entry->modifier; + } + + return 0; +} + +static void +set_virtual_modifier (AtspiDeviceLegacy *legacy_device, gint keycode, gboolean enabled) +{ + AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device); + guint modifier = find_virtual_mapping (legacy_device, keycode); + + if (enabled) + priv->virtual_mods_enabled |= modifier; + else + priv->virtual_mods_enabled &= ~modifier; +} + + gboolean key_cb (const AtspiDeviceEvent *event, void *user_data) { - AtspiDeviceLegacy *device = ATSPI_DEVICE_LEGACY (user_data); + AtspiDeviceLegacy *legacy_device = ATSPI_DEVICE_LEGACY (user_data); + AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device); + gboolean ret = priv->keyboard_grabbed; + + set_virtual_modifier (legacy_device, event->hw_code, + event->type == (AtspiEventType)ATSPI_KEY_PRESS); + ret |= atspi_device_notify_key (ATSPI_DEVICE (legacy_device), + event->type == (AtspiEventType)ATSPI_KEY_PRESS, + event->hw_code, event->id, + event->modifiers | priv->virtual_mods_enabled, + event->event_string); + + return ret; +} + +static guint +atspi_device_legacy_get_locked_modifiers (AtspiDevice *device) +{ +#ifdef HAVE_X11 + AtspiDeviceLegacy *legacy_device = ATSPI_DEVICE_LEGACY (device); + AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device); + XkbStateRec state_rec; + + memset (&state_rec, 0, sizeof (state_rec)); + XkbGetState (priv->display, XkbUseCoreKbd, &state_rec); + return state_rec.locked_mods; +#else + return 0; +#endif +} + +static gboolean +check_virtual_modifier (AtspiDeviceLegacy *legacy_device, guint modifier) +{ + AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device); + GSList *l; - return atspi_device_notify_key (ATSPI_DEVICE (device), event->type == (AtspiEventType)ATSPI_KEY_PRESS, event->hw_code, event->id, event->modifiers, event->event_string); + for (l = priv->modifiers; l; l = l->next) + { + AtspiLegacyKeyModifier *entry = l->data; + if (entry->modifier == modifier) + return TRUE; + } + + return FALSE; +} + +static guint +get_unused_virtual_modifier (AtspiDeviceLegacy *legacy_device) +{ + guint ret = 0x1000; + + while (ret < 0x10000) + { + if (!check_virtual_modifier (legacy_device, ret)) + return ret; + ret <<= 1; + } + + return 0; +} + +static guint +atspi_device_legacy_map_modifier (AtspiDevice *device, gint keycode) +{ + AtspiDeviceLegacy *legacy_device = ATSPI_DEVICE_LEGACY (device); + AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device); + guint ret; + AtspiLegacyKeyModifier *entry; +#ifdef HAVE_X11 + XkbDescPtr desc; + + desc = XkbGetMap (priv->display, XkbModifierMapMask, XkbUseCoreKbd); + + if (keycode < desc->min_key_code || keycode >= desc->max_key_code) + { + XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE); + g_warning ("Passed invalid keycode %d", keycode); + return 0; + } + + ret = desc->map->modmap[keycode]; + XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE); + if (ret & (ShiftMask | ControlMask)) + return ret; +#endif + + ret = find_virtual_mapping (legacy_device, keycode); + if (ret) + return ret; + + ret = get_unused_virtual_modifier (legacy_device); + + entry = g_new (AtspiLegacyKeyModifier, 1); + entry->keycode = keycode; + entry->modifier = ret; + priv->modifiers = g_slist_append (priv->modifiers, entry); + + return ret; +} + +static void +atspi_device_legacy_unmap_modifier (AtspiDevice *device, gint keycode) +{ + AtspiDeviceLegacy *legacy_device = ATSPI_DEVICE_LEGACY (device); + AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device); + GSList *l; + + for (l = priv->modifiers; l; l = l->next) + { + AtspiLegacyKeyModifier *entry = l->data; + if (entry->keycode == keycode) + { + g_free (entry); + priv->modifiers = g_slist_remove (priv->modifiers, entry); + return; + } + } +} + +static guint +atspi_device_legacy_get_modifier (AtspiDevice *device, gint keycode) +{ + AtspiDeviceLegacy *legacy_device = ATSPI_DEVICE_LEGACY (device); +#ifdef HAVE_X11 + AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device); + XkbDescPtr desc; + guint ret; + + desc = XkbGetMap (priv->display, XkbModifierMapMask, XkbUseCoreKbd); + + if (keycode < desc->min_key_code || keycode >= desc->max_key_code) + { + XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE); + g_warning ("Passed invalid keycode %d", keycode); + return 0; + } + + ret = desc->map->modmap[keycode]; + XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE); + if (ret) + return ret; +#endif + + return find_virtual_mapping (legacy_device, keycode); +} + +static gboolean +atspi_device_legacy_grab_keyboard (AtspiDevice *device) +{ + AtspiDeviceLegacy *legacy_device = ATSPI_DEVICE_LEGACY (device); + AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device); + + priv->keyboard_grabbed = TRUE; + return TRUE; +} + +static void +atspi_device_legacy_ungrab_keyboard (AtspiDevice *device) +{ + AtspiDeviceLegacy *legacy_device = ATSPI_DEVICE_LEGACY (device); + AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device); + + priv->keyboard_grabbed = FALSE; } static void @@ -52,6 +263,13 @@ atspi_device_legacy_init (AtspiDeviceLegacy *device) priv->listener = atspi_device_listener_new (key_cb, device, NULL); for (i = 0; i < 256; i++) atspi_register_keystroke_listener (priv->listener, NULL, i, 3, ATSPI_KEYLISTENER_SYNCHRONOUS | ATSPI_KEYLISTENER_CANCONSUME, NULL); + +#ifdef HAVE_X11 + priv->display=XOpenDisplay(""); + if (priv->display) + priv->window = DefaultRootWindow(priv->display); +#endif + } static void @@ -69,9 +287,16 @@ static void atspi_device_legacy_class_init (AtspiDeviceLegacyClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; + AtspiDeviceClass *device_class = ATSPI_DEVICE_CLASS (klass); device_legacy_parent_class = g_type_class_peek_parent (klass); object_class->finalize = atspi_device_legacy_finalize; + device_class->map_modifier = atspi_device_legacy_map_modifier; + device_class->unmap_modifier = atspi_device_legacy_unmap_modifier; + device_class->get_modifier = atspi_device_legacy_get_modifier; + device_class->get_locked_modifiers = atspi_device_legacy_get_locked_modifiers; + device_class->grab_keyboard = atspi_device_legacy_grab_keyboard; + device_class->ungrab_keyboard = atspi_device_legacy_ungrab_keyboard; } /** diff --git a/atspi/atspi-device-x11.c b/atspi/atspi-device-x11.c index adc600be..e8f21995 100644 --- a/atspi/atspi-device-x11.c +++ b/atspi/atspi-device-x11.c @@ -29,7 +29,7 @@ #include <X11/XKBlib.h> -#define ATSPI_VIRTUAL_MODIFIER_MASK 0xffff0000 +#define ATSPI_VIRTUAL_MODIFIER_MASK 0x0000f000 typedef struct _AtspiDeviceX11Private AtspiDeviceX11Private; struct _AtspiDeviceX11Private @@ -39,9 +39,11 @@ struct _AtspiDeviceX11Private GSource *source; int xi_opcode; int device_id; + int device_id_alt; GSList *modifiers; GSList *key_grabs; guint virtual_mods_enabled; + gboolean keyboard_grabbed; }; GObjectClass *device_x11_parent_class; @@ -149,6 +151,11 @@ static gboolean grab_should_be_enabled (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab) { AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + + /* If the whole keyboard is grabbed, then all keys are grabbed elsewhere */ + if (priv->keyboard_grabbed) + return FALSE; + guint virtual_mods_used = grab->kd->modifiers & ATSPI_VIRTUAL_MODIFIER_MASK; return ((priv->virtual_mods_enabled & virtual_mods_used) == virtual_mods_used); } @@ -169,16 +176,14 @@ grab_has_active_duplicate (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab) } static void -enable_key_grab (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab) +grab_key (AtspiDeviceX11 *x11_device, int keycode, int modmask) { AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); XIGrabModifiers xi_modifiers; XIEventMask eventmask; unsigned char mask[XIMaskLen (XI_LASTEVENT)] = { 0 }; - g_return_if_fail (priv->display != NULL); - - xi_modifiers.modifiers = grab->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK; + xi_modifiers.modifiers = modmask; xi_modifiers.status = 0; eventmask.deviceid = XIAllDevices; @@ -188,17 +193,38 @@ enable_key_grab (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab) XISetMask (mask, XI_KeyPress); XISetMask (mask, XI_KeyRelease); + XIGrabKeycode (priv->display, XIAllMasterDevices, keycode, priv->window, XIGrabModeSync, XIGrabModeAsync, False, &eventmask, 1, &xi_modifiers); +} + +static void +enable_key_grab (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab) +{ + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + + g_return_if_fail (priv->display != NULL); + if (!grab_has_active_duplicate (x11_device, grab)) - XIGrabKeycode (priv->display, XIAllMasterDevices, grab->kd->keycode, priv->window, XIGrabModeSync, XIGrabModeAsync, False, &eventmask, 1, &xi_modifiers); + grab_key (x11_device, grab->kd->keycode, grab->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK); grab->enabled = TRUE; } static void -disable_key_grab (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab) +ungrab_key (AtspiDeviceX11 *x11_device, int keycode, int modmask) { AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); XIGrabModifiers xi_modifiers; + xi_modifiers.modifiers = modmask; + xi_modifiers.status = 0; + + XIUngrabKeycode (priv->display, XIAllMasterDevices, keycode, priv->window, sizeof(xi_modifiers), &xi_modifiers); +} + +static void +disable_key_grab (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab) +{ + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + g_return_if_fail (priv->display != NULL); if (!grab->enabled) @@ -209,10 +235,24 @@ disable_key_grab (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab) if (grab_has_active_duplicate (x11_device, grab)) return; - xi_modifiers.modifiers = grab->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK; - xi_modifiers.status = 0; + ungrab_key (x11_device, grab->kd->keycode, grab->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK); +} + +static void +refresh_key_grabs (AtspiDeviceX11 *x11_device) +{ + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + GSList *l; - XIUngrabKeycode (priv->display, XIAllMasterDevices, grab->kd->keycode, priv->window, sizeof(xi_modifiers), &xi_modifiers); + for (l = priv->key_grabs; l; l = l->next) + { + AtspiX11KeyGrab *grab = l->data; + gboolean new_enabled = grab_should_be_enabled (x11_device, grab); + if (new_enabled && !grab->enabled) + enable_key_grab (x11_device, grab); + else if (grab->enabled && !new_enabled) + disable_key_grab (x11_device, grab); + } } static void @@ -220,7 +260,6 @@ set_virtual_modifier (AtspiDeviceX11 *x11_device, gint keycode, gboolean enabled { AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); guint modifier = find_virtual_mapping (x11_device, keycode); - GSList *l; if (!modifier) return; @@ -238,15 +277,7 @@ set_virtual_modifier (AtspiDeviceX11 *x11_device, gint keycode, gboolean enabled priv->virtual_mods_enabled &= ~modifier; } - for (l = priv->key_grabs; l; l = l->next) - { - AtspiX11KeyGrab *grab = l->data; - gboolean new_enabled = grab_should_be_enabled (x11_device, grab); - if (new_enabled && !grab->enabled) - enable_key_grab (x11_device, grab); - else if (grab->enabled && !new_enabled) - disable_key_grab (x11_device, grab); - } + refresh_key_grabs (x11_device); } static gboolean @@ -270,7 +301,7 @@ do_event_dispatch (gpointer user_data) case KeyPress: case KeyRelease: XLookupString(&xevent.xkey, text, sizeof (text), &keysym, &status); - atspi_device_notify_key (ATSPI_DEVICE (device), (xevent.type == KeyPress), xevent.xkey.keycode, keysym, xevent.xkey.state & priv->virtual_mods_enabled, text); + atspi_device_notify_key (ATSPI_DEVICE (device), (xevent.type == KeyPress), xevent.xkey.keycode, keysym, xevent.xkey.state | priv->virtual_mods_enabled, text); break; case GenericEvent: if (xevent.xcookie.extension == priv->xi_opcode) @@ -286,11 +317,18 @@ do_event_dispatch (gpointer user_data) XLookupString((XKeyEvent *)&keyevent, text, sizeof (text), &keysym, &status); if (text[0] < ' ') text[0] = '\0'; + /* The deviceid can change. Would be nice to find a better way of + handling this */ + if (priv->device_id && priv->device_id_alt && xiDevEv->deviceid != priv->device_id && xiDevEv->deviceid != priv->device_id_alt) + priv->device_id = priv->device_id_alt = 0; + else if (priv->device_id && !priv->device_id_alt && xiDevEv->deviceid != priv->device_id) + priv->device_id_alt = xiDevEv->deviceid; if (!priv->device_id) priv->device_id = xiDevEv->deviceid; set_virtual_modifier (device, xiRawEv->detail, xevent.xcookie.evtype == XI_KeyPress); if (xiDevEv->deviceid == priv->device_id) atspi_device_notify_key (ATSPI_DEVICE (device), (xevent.xcookie.evtype == XI_KeyPress), xiRawEv->detail, keysym, keyevent.xkey.state, text); + /* otherwise it's probably a duplicate event from a key grab */ XFreeEventData (priv->display, &xevent.xcookie); break; } @@ -371,9 +409,9 @@ check_virtual_modifier (AtspiDeviceX11 *x11_device, guint modifier) static guint get_unused_virtual_modifier (AtspiDeviceX11 *x11_device) { - guint ret = 0x10000; + guint ret = 0x1000; - while (ret) + while (ret < 0x10000) { if (!check_virtual_modifier (x11_device, ret)) return ret; @@ -578,16 +616,41 @@ atspi_device_x11_get_locked_modifiers (AtspiDevice *device) return state_rec.locked_mods; } +static void +get_keycode_range (AtspiDeviceX11 *x11_device, int *min, int *max) +{ + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + XkbDescPtr desc; + + desc = XkbGetMap (priv->display, XkbModifierMapMask, XkbUseCoreKbd); + *min = desc->min_key_code; + *max = desc->max_key_code; + XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE); +} + static gboolean atspi_device_x11_grab_keyboard (AtspiDevice *device) { AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device); AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); - int result; + int min, max; + gint i; g_return_val_if_fail (priv->display != NULL, FALSE); - result = XGrabKeyboard (priv->display, priv->window, TRUE, GrabModeAsync, GrabModeSync, CurrentTime); - return (result == 0); +#if 0 + /* THis seems like the right thing to do, but it fails for me */ + return (XGrabKeyboard (priv->display, priv->window, TRUE, GrabModeAsync, GrabModeSync, CurrentTime)) == 0; +#else + if (priv->keyboard_grabbed) + return TRUE; + priv->keyboard_grabbed = TRUE; + refresh_key_grabs (x11_device); + + get_keycode_range (x11_device, &min, &max); + for (i = min; i < max; i++) + grab_key (x11_device, i, 0); + return TRUE; +#endif } static void @@ -595,9 +658,23 @@ atspi_device_x11_ungrab_keyboard (AtspiDevice *device) { AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device); AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + int min, max; + gint i; g_return_if_fail (priv->display != NULL); +#if 0 XUngrabKeyboard (priv->display, CurrentTime); +#else + if (!priv->keyboard_grabbed) + return; + priv->keyboard_grabbed = FALSE; + + get_keycode_range (x11_device, &min, &max); + for (i = min; i < max; i++) + ungrab_key (x11_device, i, 0); + + refresh_key_grabs (x11_device); +#endif } static void diff --git a/atspi/atspi-device.c b/atspi/atspi-device.c index abf6138d..5f62dc3c 100644 --- a/atspi/atspi-device.c +++ b/atspi/atspi-device.c @@ -99,9 +99,8 @@ atspi_device_class_init (AtspiDeviceClass *klass) AtspiDevice * atspi_device_new () { - //if (!g_getenv ("WAYLAND_DISPLAY") && !g_getenv ("ATSPI_USE_LEGACY_DEVICE")) #ifdef HAVE_X11 - if (!g_getenv ("ATSPI_USE_LEGACY_DEVICE")) + if (!g_getenv ("WAYLAND_DISPLAY") && !g_getenv ("ATSPI_USE_LEGACY_DEVICE")) return ATSPI_DEVICE (atspi_device_x11_new ()); #endif |