summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Gorse <mgorse@suse.com>2021-01-27 16:41:39 -0600
committerMike Gorse <mgorse@suse.com>2021-01-27 16:41:39 -0600
commitc6b2af03425bacfef25b08f4730d6f7628743681 (patch)
tree1d0a9c6486a1d26a9894382b809f8f219994c9e5
parent47831726d956169369536ff610f54173fda5bc14 (diff)
downloadat-spi2-core-c6b2af03425bacfef25b08f4730d6f7628743681.tar.gz
Device fixes
-rw-r--r--atspi/atspi-device-legacy.c229
-rw-r--r--atspi/atspi-device-x11.c129
-rw-r--r--atspi/atspi-device.c3
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