+static DBusMessage *
+impl_deregister_keystroke_listener (DBusConnection *bus,
+ DBusMessage *message,
+ void *user_data)
+{
+ SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER(user_data);
+ DEControllerKeyListener *key_listener;
+ DBusMessageIter iter, iter_array;
+ const char *path;
+ GSList *keys = NULL;
+ dbus_int32_t mask, type;
+ DBusMessage *reply;
+
+ dbus_message_iter_init(message, &iter);
+ // TODO: verify type signature
+ dbus_message_iter_get_basic(&iter, &path);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &iter_array);
+ while (dbus_message_iter_get_arg_type(&iter_array) != DBUS_TYPE_INVALID)
+ {
+ Accessibility_KeyDefinition *kd = (Accessibility_KeyDefinition *)g_malloc(sizeof(Accessibility_KeyDefinition));
+ char *keystring;
+
+ if (!spi_dbus_message_iter_get_struct(&iter_array, DBUS_TYPE_INT32, &kd->keycode, DBUS_TYPE_INT32, &kd->keysym, DBUS_TYPE_STRING, &keystring, DBUS_TYPE_INVALID))
+ {
+ break;
+ }
+ kd->keystring = g_strdup (keystring);
+ keys = g_slist_append(keys, kd);
+ }
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_get_basic(&iter, &mask);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_get_basic(&iter, &type);
+ dbus_message_iter_next(&iter);
+ key_listener = spi_dec_key_listener_new (dbus_message_get_sender(message), path, keys, mask, type, NULL);
+#ifdef SPI_DEREGISTER_DEBUG
+ fprintf (stderr, "deregistering keystroke listener %p with maskVal %lu\n",
+ (void *) l, (unsigned long) mask->value);
+#endif
+
+ spi_deregister_controller_key_listener (controller, key_listener);
+
+ spi_dec_listener_free ((DEControllerListener *) key_listener);
+ reply = dbus_message_new_method_return (message);
+ return reply;
+}
+
+/*
+ * DBus Accessibility::DEController::deregisterDeviceEventListener
+ * method implementation
+ */
+static DBusMessage *
+impl_deregister_device_listener (DBusConnection *bus,
+ DBusMessage *message,
+ void *user_data)
+{
+ SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER(user_data);
+ DEControllerListener *listener;
+ DBusError error;
+ const char *path;
+ dbus_int32_t event_types;
+ DBusMessage *reply;
+
+ dbus_error_init(&error);
+ if (!dbus_message_get_args(message, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_UINT32, &event_types, DBUS_TYPE_INVALID))
+ {
+ return spi_dbus_general_error (message);
+ }
+ listener = spi_dec_listener_new (dbus_message_get_sender(message), path, event_types);
+ spi_controller_deregister_device_listener (
+ controller, listener);
+ reply = dbus_message_new_method_return (message);
+ return reply;
+}
+
+static unsigned int dec_xkb_get_slowkeys_delay (SpiDEController *controller)
+{
+ unsigned int retval = 0;
+ DEControllerPrivateData *priv = (DEControllerPrivateData *)
+ g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
+#ifdef HAVE_XKB
+#ifdef XKB_HAS_GET_SLOW_KEYS_DELAY
+ retval = XkbGetSlowKeysDelay (spi_get_display (),
+ XkbUseCoreKbd, &bounce_delay);
+#else
+ if (!(priv->xkb_desc == (XkbDescPtr) BadAlloc || priv->xkb_desc == NULL))
+ {
+ Status s = XkbGetControls (spi_get_display (),
+ XkbAllControlsMask, priv->xkb_desc);
+ if (s == Success)
+ {
+ if (priv->xkb_desc->ctrls->enabled_ctrls & XkbSlowKeysMask)
+ retval = priv->xkb_desc->ctrls->slow_keys_delay;
+ }
+ }
+#endif
+#endif
+#ifdef SPI_XKB_DEBUG
+ fprintf (stderr, "SlowKeys delay: %d\n", (int) retval);
+#endif
+ return retval;
+}
+
+static unsigned int dec_xkb_get_bouncekeys_delay (SpiDEController *controller)
+{
+ unsigned int retval = 0;
+ DEControllerPrivateData *priv = (DEControllerPrivateData *)
+ g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
+#ifdef HAVE_XKB
+#ifdef XKB_HAS_GET_BOUNCE_KEYS_DELAY
+ retval = XkbGetBounceKeysDelay (spi_get_display (),
+ XkbUseCoreKbd, &bounce_delay);
+#else
+ if (!(priv->xkb_desc == (XkbDescPtr) BadAlloc || priv->xkb_desc == NULL))
+ {
+ Status s = XkbGetControls (spi_get_display (),
+ XkbAllControlsMask, priv->xkb_desc);
+ if (s == Success)
+ {
+ if (priv->xkb_desc->ctrls->enabled_ctrls & XkbBounceKeysMask)
+ retval = priv->xkb_desc->ctrls->debounce_delay;
+ }
+ }
+#endif
+#endif
+#ifdef SPI_XKB_DEBUG
+ fprintf (stderr, "BounceKeys delay: %d\n", (int) retval);
+#endif
+ return retval;
+}
+
+static gboolean
+dec_synth_keycode_press (SpiDEController *controller,
+ unsigned int keycode)
+{
+ unsigned int time = CurrentTime;
+ unsigned int bounce_delay;
+ unsigned int elapsed_msec;
+ struct timeval tv;
+ DEControllerPrivateData *priv =
+ (DEControllerPrivateData *) g_object_get_qdata (G_OBJECT (controller),
+ spi_dec_private_quark);
+ if (keycode == priv->last_release_keycode)
+ {
+ bounce_delay = dec_xkb_get_bouncekeys_delay (controller);
+ if (bounce_delay)
+ {
+ gettimeofday (&tv, NULL);
+ elapsed_msec =
+ (tv.tv_sec - priv->last_release_time.tv_sec) * 1000
+ + (tv.tv_usec - priv->last_release_time.tv_usec) / 1000;
+#ifdef SPI_XKB_DEBUG
+ fprintf (stderr, "%d ms elapsed (%ld usec)\n", elapsed_msec,
+ (long) (tv.tv_usec - priv->last_release_time.tv_usec));
+#endif
+#ifdef THIS_IS_BROKEN
+ if (elapsed_msec < bounce_delay)
+ time = bounce_delay - elapsed_msec + 1;
+#else
+ time = bounce_delay + 10;
+ /* fudge for broken XTest */
+#endif
+#ifdef SPI_XKB_DEBUG
+ fprintf (stderr, "waiting %d ms\n", time);
+#endif
+ }
+ }
+ XTestFakeKeyEvent (spi_get_display (), keycode, True, time);
+ priv->last_press_keycode = keycode;
+ XFlush (spi_get_display ());
+ XSync (spi_get_display (), False);
+ gettimeofday (&priv->last_press_time, NULL);
+ return TRUE;
+}
+
+static gboolean
+dec_synth_keycode_release (SpiDEController *controller,
+ unsigned int keycode)
+{
+ unsigned int time = CurrentTime;
+ unsigned int slow_delay;
+ unsigned int elapsed_msec;
+ struct timeval tv;
+ DEControllerPrivateData *priv =
+ (DEControllerPrivateData *) g_object_get_qdata (G_OBJECT (controller),
+ spi_dec_private_quark);
+ if (keycode == priv->last_press_keycode)
+ {
+ slow_delay = dec_xkb_get_slowkeys_delay (controller);
+ if (slow_delay)
+ {
+ gettimeofday (&tv, NULL);
+ elapsed_msec =
+ (tv.tv_sec - priv->last_press_time.tv_sec) * 1000
+ + (tv.tv_usec - priv->last_press_time.tv_usec) / 1000;
+#ifdef SPI_XKB_DEBUG
+ fprintf (stderr, "%d ms elapsed (%ld usec)\n", elapsed_msec,
+ (long) (tv.tv_usec - priv->last_press_time.tv_usec));
+#endif
+#ifdef THIS_IS_BROKEN_DUNNO_WHY
+ if (elapsed_msec < slow_delay)
+ time = slow_delay - elapsed_msec + 1;
+#else
+ time = slow_delay + 10;
+ /* our XTest seems broken, we have to add slop as above */
+#endif
+#ifdef SPI_XKB_DEBUG
+ fprintf (stderr, "waiting %d ms\n", time);
+#endif
+ }
+ }
+ XTestFakeKeyEvent (spi_get_display (), keycode, False, time);
+ priv->last_release_keycode = keycode;
+ XSync (spi_get_display (), False);
+ gettimeofday (&priv->last_release_time, NULL);
+ return TRUE;
+}
+
+static unsigned
+dec_get_modifier_state (SpiDEController *controller)
+{
+ return mouse_mask_state;
+}
+
+static gboolean
+dec_lock_modifiers (SpiDEController *controller, unsigned modifiers)
+{
+ DEControllerPrivateData *priv = (DEControllerPrivateData *)
+ g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
+
+ if (priv->have_xkb) {
+ return XkbLockModifiers (spi_get_display (), XkbUseCoreKbd,
+ modifiers, modifiers);
+ } else {
+ int mod_index;
+ for (mod_index=0;mod_index<8;mod_index++)
+ if (modifiers & (1<<mod_index))
+ dec_synth_keycode_press(controller, xmkeymap->modifiermap[mod_index]);
+ return TRUE;
+ }
+}
+
+static gboolean
+dec_unlock_modifiers (SpiDEController *controller, unsigned modifiers)
+{
+ DEControllerPrivateData *priv = (DEControllerPrivateData *)
+ g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
+
+ if (priv->have_xkb) {
+ return XkbLockModifiers (spi_get_display (), XkbUseCoreKbd,
+ modifiers, 0);
+ } else {
+ int mod_index;
+ for (mod_index=0;mod_index<8;mod_index++)
+ if (modifiers & (1<<mod_index))
+ dec_synth_keycode_release(controller, xmkeymap->modifiermap[mod_index]);
+ return TRUE;
+ }
+}
+
+static KeySym
+dec_keysym_for_unichar (SpiDEController *controller, gunichar unichar)
+{
+ return ucs2keysym ((long) unichar);
+}
+
+static gboolean
+dec_synth_keysym (SpiDEController *controller, KeySym keysym)
+{
+ KeyCode key_synth_code;
+ unsigned int modifiers, synth_mods, lock_mods;
+
+ key_synth_code = keycode_for_keysym (controller, keysym, &synth_mods);
+
+ if ((key_synth_code == 0) || (synth_mods == 0xFF)) return FALSE;
+
+ /* TODO: set the modifiers accordingly! */
+ modifiers = dec_get_modifier_state (controller);
+ /* side-effect; we may unset mousebutton modifiers here! */
+
+ lock_mods = 0;
+ if (synth_mods != modifiers) {
+ lock_mods = synth_mods & ~modifiers;
+ dec_lock_modifiers (controller, lock_mods);
+ }
+ dec_synth_keycode_press (controller, key_synth_code);
+ dec_synth_keycode_release (controller, key_synth_code);
+
+ if (synth_mods != modifiers)
+ dec_unlock_modifiers (controller, lock_mods);
+ return TRUE;
+}
+
+
+static gboolean
+dec_synth_keystring (SpiDEController *controller, const char *keystring)
+{
+ /* probably we need to create and inject an XIM handler eventually. */
+ /* for now, try to match the string to existing
+ * keycode+modifier states.
+ */
+ KeySym *keysyms;
+ gint maxlen = 0;
+ gunichar unichar = 0;
+ gint i = 0;
+ gboolean retval = TRUE;
+ const gchar *c;
+
+ maxlen = strlen (keystring) + 1;
+ keysyms = g_new0 (KeySym, maxlen);
+ if (!(keystring && *keystring && g_utf8_validate (keystring, -1, &c))) {
+ retval = FALSE;
+ }
+ else {
+#ifdef SPI_DEBUG
+ fprintf (stderr, "[keystring synthesis attempted on %s]\n", keystring);
+#endif
+ while (keystring && (unichar = g_utf8_get_char (keystring))) {
+ KeySym keysym;
+ char bytes[6];
+ gint mbytes;
+
+ mbytes = g_unichar_to_utf8 (unichar, bytes);
+ bytes[mbytes] = '\0';
+#ifdef SPI_DEBUG
+ fprintf (stderr, "[unichar %s]", bytes);
+#endif
+ keysym = dec_keysym_for_unichar (controller, unichar);
+ if (keysym == NoSymbol) {
+#ifdef SPI_DEBUG
+ fprintf (stderr, "no keysym for %s", bytes);
+#endif
+ retval = FALSE;
+ break;
+ }
+ keysyms[i++] = keysym;
+ keystring = g_utf8_next_char (keystring);
+ }
+ keysyms[i++] = 0;
+ XSynchronize (spi_get_display (), TRUE);
+ for (i = 0; keysyms[i]; ++i) {
+ if (!dec_synth_keysym (controller, keysyms[i])) {
+#ifdef SPI_DEBUG
+ fprintf (stderr, "could not synthesize %c\n",
+ (int) keysyms[i]);
+#endif
+ retval = FALSE;
+ break;
+ }
+ }
+ XSynchronize (spi_get_display (), FALSE);
+ }
+ g_free (keysyms);
+
+ return retval;
+}
+
+
+/*
+ * DBus Accessibility::DEController::registerKeystrokeListener
+ * method implementation
+ */
+static DBusMessage * impl_generate_keyboard_event (DBusConnection *bus, DBusMessage *message, void *user_data)