+ if (!key_set)
+ {
+ g_print ("null key set!");
+ return TRUE;
+ }
+
+ len = g_slist_length (key_set);
+
+ if (len == 0) /* special case, means "all keys/any key" */
+ {
+#ifdef SPI_DEBUG
+ g_print ("anykey\n");
+#endif
+ return TRUE;
+ }
+
+ for (l = key_set,i = 0; l; l = g_slist_next(l),i++)
+ {
+ Accessibility_KeyDefinition *kd = l->data;
+#ifdef SPI_KEYEVENT_DEBUG
+ g_print ("key_set[%d] event = %d, code = %d; key_event %d, code %d, string %s\n",
+ i,
+ (int) kd->keysym,
+ (int) kd->keycode,
+ (int) key_event->id,
+ (int) key_event->hw_code,
+ key_event->event_string);
+#endif
+ if (kd->keysym == (dbus_uint32_t) key_event->id)
+ {
+ return TRUE;
+ }
+ if (kd->keycode == (dbus_uint32_t) key_event->hw_code)
+ {
+ return TRUE;
+ }
+ if (key_event->event_string && key_event->event_string[0] &&
+ !strcmp (kd->keystring, key_event->event_string))
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean
+spi_eventtype_seq_contains_event (dbus_uint32_t types,
+ const Accessibility_DeviceEvent *event)
+{
+ if (types == 0) /* special case, means "all events/any event" */
+ {
+ return TRUE;
+ }
+
+ return (types & (1 << event->type));
+}
+
+static gboolean
+spi_key_event_matches_listener (const Accessibility_DeviceEvent *key_event,
+ DEControllerKeyListener *listener,
+ dbus_bool_t is_system_global)
+{
+ if (((key_event->modifiers & 0xFF) == (dbus_uint16_t) (listener->mask & 0xFF)) &&
+ spi_key_set_contains_key (listener->keys, key_event) &&
+ spi_eventtype_seq_contains_event (listener->listener.types, key_event) &&
+ (is_system_global == listener->mode->global))
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+static gboolean
+spi_controller_notify_keylisteners (SpiDEController *controller,
+ Accessibility_DeviceEvent *key_event,
+ dbus_bool_t is_system_global)
+{
+ GList *l;
+ GSList *notify = NULL, *l2;
+ GList **key_listeners = &controller->key_listeners;
+ gboolean is_consumed;
+
+ if (!key_listeners)
+ {
+ return FALSE;
+ }
+
+ /* set the NUMLOCK event mask bit if appropriate: see bug #143702 */
+ if (key_event->modifiers & _numlock_physical_mask)
+ key_event->modifiers |= SPI_KEYMASK_NUMLOCK;
+
+ for (l = *key_listeners; l; l = l->next)
+ {
+ DEControllerKeyListener *key_listener = l->data;
+
+ if (spi_key_event_matches_listener (key_event, key_listener, is_system_global))
+ {
+ /* we clone (don't dup) the listener, to avoid refcount inc. */
+ notify = g_slist_prepend (notify,
+ spi_key_listener_clone (key_listener));
+ }
+ }
+
+#ifdef SPI_KEYEVENT_DEBUG
+ if (!notify)
+ {
+ g_print ("no match for event\n");
+ }
+#endif
+
+ is_consumed = FALSE;
+ for (l2 = notify; l2 && !is_consumed; l2 = l2->next)
+ {
+ DEControllerKeyListener *key_listener = l2->data;
+
+ is_consumed = Accessibility_DeviceEventListener_notifyEvent (controller->registry, &key_listener->listener, key_event) &&
+ key_listener->mode->preemptive;
+
+ spi_key_listener_clone_free (key_listener);
+ }
+
+ for (; l2; l2 = l2->next)
+ {
+ DEControllerKeyListener *key_listener = l2->data;
+ spi_key_listener_clone_free (key_listener);
+ /* clone doesn't have its own ref, so don't use spi_dec_listener_free */
+ }
+
+ g_slist_free (notify);
+
+#ifdef SPI_DEBUG
+ if (is_consumed) g_message ("consumed\n");
+#endif
+ return is_consumed;
+}
+
+static gboolean
+spi_clear_error_state (void)
+{
+ gboolean retval = spi_error_code != 0;
+ spi_error_code = 0;
+ return retval;
+}
+
+static Accessibility_DeviceEvent
+spi_keystroke_from_x_key_event (XKeyEvent *x_key_event)
+{
+ Accessibility_DeviceEvent key_event;
+ KeySym keysym;
+ const int cbuf_bytes = 20;
+ char cbuf [21];
+ int nbytes;
+
+ nbytes = XLookupString (x_key_event, cbuf, cbuf_bytes, &keysym, NULL);
+ key_event.id = (dbus_int32_t)(keysym);
+ key_event.hw_code = (dbus_int16_t) x_key_event->keycode;
+ if (((XEvent *) x_key_event)->type == KeyPress)
+ {
+ key_event.type = Accessibility_KEY_PRESSED_EVENT;
+ }
+ else
+ {
+ key_event.type = Accessibility_KEY_RELEASED_EVENT;
+ }
+ key_event.modifiers = (dbus_uint16_t)(x_key_event->state);
+ key_event.is_text = FALSE;
+ switch (keysym)
+ {
+ case ' ':
+ key_event.event_string = g_strdup ("space");
+ break;
+ case XK_Tab:
+ key_event.event_string = g_strdup ("Tab");
+ break;
+ case XK_BackSpace:
+ key_event.event_string = g_strdup ("Backspace");
+ break;
+ case XK_Return:
+ key_event.event_string = g_strdup ("Return");
+ break;
+ case XK_Home:
+ key_event.event_string = g_strdup ("Home");
+ break;
+ case XK_Page_Down:
+ key_event.event_string = g_strdup ("Page_Down");
+ break;
+ case XK_Page_Up:
+ key_event.event_string = g_strdup ("Page_Up");
+ break;
+ case XK_F1:
+ key_event.event_string = g_strdup ("F1");
+ break;
+ case XK_F2:
+ key_event.event_string = g_strdup ("F2");
+ break;
+ case XK_F3:
+ key_event.event_string = g_strdup ("F3");
+ break;
+ case XK_F4:
+ key_event.event_string = g_strdup ("F4");
+ break;
+ case XK_F5:
+ key_event.event_string = g_strdup ("F5");
+ break;
+ case XK_F6:
+ key_event.event_string = g_strdup ("F6");
+ break;
+ case XK_F7:
+ key_event.event_string = g_strdup ("F7");
+ break;
+ case XK_F8:
+ key_event.event_string = g_strdup ("F8");
+ break;
+ case XK_F9:
+ key_event.event_string = g_strdup ("F9");
+ break;
+ case XK_F10:
+ key_event.event_string = g_strdup ("F10");
+ break;
+ case XK_F11:
+ key_event.event_string = g_strdup ("F11");
+ break;
+ case XK_F12:
+ key_event.event_string = g_strdup ("F12");
+ break;
+ case XK_End:
+ key_event.event_string = g_strdup ("End");
+ break;
+ case XK_Escape:
+ key_event.event_string = g_strdup ("Escape");
+ break;
+ case XK_Up:
+ key_event.event_string = g_strdup ("Up");
+ break;
+ case XK_Down:
+ key_event.event_string = g_strdup ("Down");
+ break;
+ case XK_Left:
+ key_event.event_string = g_strdup ("Left");
+ break;
+ case XK_Right:
+ key_event.event_string = g_strdup ("Right");
+ break;
+ default:
+ if (nbytes > 0)
+ {
+ gunichar c;
+ cbuf[nbytes] = '\0'; /* OK since length is cbuf_bytes+1 */
+ key_event.event_string = g_strdup (cbuf);
+ c = keysym2ucs (keysym);
+ if (c > 0 && !g_unichar_iscntrl (c))
+ {
+ key_event.is_text = TRUE;
+ /* incorrect for some composed chars? */
+ }
+ }
+ else
+ {
+ key_event.event_string = g_strdup ("");
+ }
+ }
+
+ key_event.timestamp = (dbus_uint32_t) x_key_event->time;
+#ifdef SPI_KEYEVENT_DEBUG
+ {
+ char *pressed_str = "pressed";
+ char *released_str = "released";
+ char *state_ptr;
+
+ if (key_event.type == Accessibility_KEY_PRESSED_EVENT)
+ state_ptr = pressed_str;
+ else
+ state_ptr = released_str;
+
+ fprintf (stderr,
+ "Key %lu %s (%c), modifiers %d; string=%s [%x] %s\n",
+ (unsigned long) keysym,
+ state_ptr,
+ keysym ? (int) keysym : '*',
+ (int) x_key_event->state,
+ key_event.event_string,
+ key_event.event_string[0],
+ (key_event.is_text == TRUE) ? "(text)" : "(not text)");
+ }
+#endif
+#ifdef SPI_DEBUG
+ fprintf (stderr, "%s%c\n",
+ (x_key_event->state & Mod1Mask)?"Alt-":"",
+ ((x_key_event->state & ShiftMask)^(x_key_event->state & LockMask))?
+ g_ascii_toupper (keysym) : g_ascii_tolower (keysym));
+ fprintf (stderr, "serial: %x Time: %x\n", x_key_event->serial, x_key_event->time);
+#endif /* SPI_DEBUG */
+ return key_event;
+}
+
+static gboolean
+spi_controller_update_key_grabs (SpiDEController *controller,
+ Accessibility_DeviceEvent *recv)
+{
+ GList *l, *next;
+ gboolean update_failed = FALSE;
+ KeyCode keycode = 0;
+
+ g_return_val_if_fail (controller != NULL, FALSE);
+
+ /*
+ * masks known to work with default RH 7.1+:
+ * 0 (no mods), LockMask, Mod1Mask, Mod2Mask, ShiftMask,
+ * ShiftMask|LockMask, Mod1Mask|LockMask, Mod2Mask|LockMask,
+ * ShiftMask|Mod1Mask, ShiftMask|Mod2Mask, Mod1Mask|Mod2Mask,
+ * ShiftMask|LockMask|Mod1Mask, ShiftMask|LockMask|Mod2Mask,
+ *
+ * ControlMask grabs are broken, must be in use already
+ */
+ if (recv)
+ keycode = keycode_for_keysym (controller, recv->id, NULL);
+ for (l = controller->keygrabs_list; l; l = next)
+ {
+ gboolean do_remove;
+ gboolean re_issue_grab;
+ DEControllerGrabMask *grab_mask = l->data;
+
+ next = l->next;
+
+ re_issue_grab = recv &&
+ (recv->modifiers & grab_mask->mod_mask) &&
+ (grab_mask->key_val == keycode);
+
+#ifdef SPI_DEBUG
+ fprintf (stderr, "mask=%lx %lx (%c%c) %s\n",
+ (long int) grab_mask->key_val,
+ (long int) grab_mask->mod_mask,
+ grab_mask->pending_add ? '+' : '.',
+ grab_mask->pending_remove ? '-' : '.',
+ re_issue_grab ? "re-issue": "");
+#endif
+
+ do_remove = FALSE;
+
+ if (grab_mask->pending_add && grab_mask->pending_remove)
+ {
+ do_remove = TRUE;
+ }
+ else if (grab_mask->pending_remove)