+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)