1 /* AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5 * Copyright 2001, 2003 Sun Microsystems Inc.,
6 * Copyright 2001, 2002 Ximian, Inc.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
24 /* deviceeventcontroller.c: implement the DeviceEventController interface */
30 #undef SPI_KEYEVENT_DEBUG
36 #include <bonobo/bonobo-exception.h>
39 #include <X11/extensions/XTest.h>
40 #include <X11/XKBlib.h>
43 #include <X11/keysymdef.h>
46 #include <X11/Xproto.h>
48 #include <X11/extensions/Xevie.h>
49 #endif /* HAVE_XEVIE */
52 #include <gdk/gdkx.h> /* TODO: hide dependency (wrap in single porting file) */
53 #include <gdk/gdkkeysyms.h>
54 #include <gdk/gdkwindow.h>
56 #include "../libspi/spi-private.h"
57 #include "deviceeventcontroller.h"
59 KeySym ucs2keysym (long ucs);
61 #define CHECK_RELEASE_DELAY 20
62 #define BIT(c, x) (c[x/8]&(1<<(x%8)))
63 static guint check_release_handler = 0;
64 static Accessibility_DeviceEvent pressed_event;
65 static SpiDEController *saved_controller;
66 static void wait_for_release_event (XEvent *event, SpiDEController *controller);
68 /* Our parent Gtk object type */
69 #define PARENT_TYPE BONOBO_TYPE_OBJECT
71 /* A pointer to our parent object class */
72 static GObjectClass *spi_device_event_controller_parent_class;
73 static int spi_error_code = 0;
74 static GdkPoint last_mouse_pos_static = {0, 0};
75 static GdkPoint *last_mouse_pos = &last_mouse_pos_static;
76 static unsigned int mouse_mask_state = 0;
77 static unsigned int mouse_button_mask =
78 Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask;
79 static unsigned int key_modifier_mask =
80 Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask | ShiftMask | LockMask | ControlMask | SPI_KEYMASK_NUMLOCK;
81 static unsigned int _numlock_physical_mask = Mod2Mask; /* a guess, will be reset */
83 static GQuark spi_dec_private_quark = 0;
85 int (*x_default_error_handler) (Display *display, XErrorEvent *error_event);
89 SPI_DEVICE_TYPE_MOUSE,
90 SPI_DEVICE_TYPE_LAST_DEFINED
91 } SpiDeviceTypeCategory;
95 guint pending_add : 1;
96 guint pending_remove : 1;
98 Accessibility_ControllerEventMask mod_mask;
99 CORBA_unsigned_long key_val; /* KeyCode */
100 } DEControllerGrabMask;
104 SpiDeviceTypeCategory type;
105 Accessibility_EventTypeSeq *typeseq;
106 } DEControllerListener;
109 DEControllerListener listener;
111 Accessibility_KeySet *keys;
112 Accessibility_ControllerEventMask mask;
113 Accessibility_EventListenerMode *mode;
114 } DEControllerKeyListener;
117 unsigned int last_press_keycode;
118 unsigned int last_release_keycode;
119 struct timeval last_press_time;
120 struct timeval last_release_time;
122 int xkb_major_extension_opcode;
123 int xkb_base_event_code;
124 int xkb_base_error_code;
125 unsigned int xkb_latch_mask;
126 unsigned int pending_xkb_mod_relatch_mask;
128 KeyCode reserved_keycode;
129 KeySym reserved_keysym;
130 guint reserved_reset_timeout;
131 } DEControllerPrivateData;
133 static void spi_controller_register_with_devices (SpiDEController *controller);
134 static gboolean spi_controller_update_key_grabs (SpiDEController *controller,
135 Accessibility_DeviceEvent *recv);
136 static gboolean spi_controller_register_device_listener (SpiDEController *controller,
137 DEControllerListener *l,
138 CORBA_Environment *ev);
139 static gboolean spi_device_event_controller_forward_key_event (SpiDEController *controller,
140 const XEvent *event);
141 static void spi_deregister_controller_device_listener (SpiDEController *controller,
142 DEControllerListener *listener,
143 CORBA_Environment *ev);
144 static void spi_deregister_controller_key_listener (SpiDEController *controller,
145 DEControllerKeyListener *key_listener,
146 CORBA_Environment *ev);
147 static gboolean spi_controller_notify_mouselisteners (SpiDEController *controller,
148 const Accessibility_DeviceEvent *event,
149 CORBA_Environment *ev);
151 static gboolean spi_eventtype_seq_contains_event (Accessibility_EventTypeSeq *type_seq,
152 const Accessibility_DeviceEvent *event);
153 static gboolean spi_clear_error_state (void);
154 static gboolean spi_dec_poll_mouse_moved (gpointer data);
155 static gboolean spi_dec_poll_mouse_moving (gpointer data);
156 static gboolean spi_dec_poll_mouse_idle (gpointer data);
158 #define spi_get_display() GDK_DISPLAY()
160 /* Private methods */
163 keysym_mod_mask (KeySym keysym, KeyCode keycode)
165 /* we really should use XKB and look directly at the keymap */
166 /* this is very inelegant */
167 Display *display = spi_get_display ();
168 unsigned int mods_rtn = 0;
169 unsigned int retval = 0;
172 if (XkbLookupKeySym (display, keycode, 0, &mods_rtn, &sym_rtn) &&
173 (sym_rtn == keysym)) {
176 else if (XkbLookupKeySym (display, keycode, ShiftMask, &mods_rtn, &sym_rtn) &&
177 (sym_rtn == keysym)) {
180 else if (XkbLookupKeySym (display, keycode, Mod2Mask, &mods_rtn, &sym_rtn) &&
181 (sym_rtn == keysym)) {
184 else if (XkbLookupKeySym (display, keycode, Mod3Mask, &mods_rtn, &sym_rtn) &&
185 (sym_rtn == keysym)) {
188 else if (XkbLookupKeySym (display, keycode,
189 ShiftMask | Mod2Mask, &mods_rtn, &sym_rtn) &&
190 (sym_rtn == keysym)) {
191 retval = (Mod2Mask | ShiftMask);
193 else if (XkbLookupKeySym (display, keycode,
194 ShiftMask | Mod3Mask, &mods_rtn, &sym_rtn) &&
195 (sym_rtn == keysym)) {
196 retval = (Mod3Mask | ShiftMask);
198 else if (XkbLookupKeySym (display, keycode,
199 ShiftMask | Mod4Mask, &mods_rtn, &sym_rtn) &&
200 (sym_rtn == keysym)) {
201 retval = (Mod4Mask | ShiftMask);
209 spi_dec_replace_map_keysym (DEControllerPrivateData *priv, KeyCode keycode, KeySym keysym)
212 Display *dpy = spi_get_display ();
214 if (!(desc = XkbGetMap (dpy, XkbAllMapComponentsMask, XkbUseCoreKbd)))
216 fprintf (stderr, "ERROR getting map\n");
220 if (desc && desc->map)
222 gint offset = desc->map->key_sym_map[keycode].offset;
223 long old_sym = desc->map->syms[offset];
224 desc->map->syms[offset] = keysym;
228 fprintf (stderr, "Error changing key map: empty server structure\n");
230 XkbSetMap (dpy, XkbAllMapComponentsMask, desc);
232 * FIXME: the use of XkbChangeMap, and the reuse of the priv->xkb_desc structure,
233 * would be far preferable.
234 * HOWEVER it does not seem to work using XFree 4.3.
236 /* XkbChangeMap (dpy, priv->xkb_desc, priv->changes); */
239 XkbFreeKeyboard (desc, 0, TRUE);
248 spi_dec_reset_reserved (gpointer data)
250 DEControllerPrivateData *priv = data;
251 spi_dec_replace_map_keysym (priv, priv->reserved_keycode, priv->reserved_keysym);
252 priv->reserved_reset_timeout = 0;
257 keycode_for_keysym (SpiDEController *controller, long keysym, unsigned int *modmask)
260 keycode = XKeysymToKeycode (spi_get_display (), (KeySym) keysym);
263 DEControllerPrivateData *priv = (DEControllerPrivateData *)
264 g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
265 /* if there's no keycode available, fix it */
266 if (spi_dec_replace_map_keysym (priv, priv->reserved_keycode, keysym))
268 keycode = priv->reserved_keycode;
270 * queue a timer to restore the old keycode. Ugly, but required
271 * due to races / asynchronous X delivery.
272 * Long-term fix is to extend the X keymap here instead of replace entries.
274 priv->reserved_reset_timeout = g_timeout_add (500, spi_dec_reset_reserved, priv);
280 *modmask = keysym_mod_mask (keysym, keycode);
284 static DEControllerGrabMask *
285 spi_grab_mask_clone (DEControllerGrabMask *grab_mask)
287 DEControllerGrabMask *clone = g_new (DEControllerGrabMask, 1);
289 memcpy (clone, grab_mask, sizeof (DEControllerGrabMask));
291 clone->ref_count = 1;
292 clone->pending_add = TRUE;
293 clone->pending_remove = FALSE;
299 spi_grab_mask_free (DEControllerGrabMask *grab_mask)
305 spi_grab_mask_compare_values (gconstpointer p1, gconstpointer p2)
307 DEControllerGrabMask *l1 = (DEControllerGrabMask *) p1;
308 DEControllerGrabMask *l2 = (DEControllerGrabMask *) p2;
316 return ((l1->mod_mask != l2->mod_mask) || (l1->key_val != l2->key_val));
321 spi_dec_set_unlatch_pending (SpiDEController *controller, unsigned mask)
323 DEControllerPrivateData *priv =
324 g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
326 if (priv->xkb_latch_mask) fprintf (stderr, "unlatch pending! %x\n",
327 priv->xkb_latch_mask);
329 priv->pending_xkb_mod_relatch_mask |= priv->xkb_latch_mask;
333 spi_dec_clear_unlatch_pending (SpiDEController *controller)
335 DEControllerPrivateData *priv =
336 g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
337 priv->xkb_latch_mask = 0;
341 spi_dec_button_update_and_emit (SpiDEController *controller,
344 CORBA_Environment ev;
345 Accessibility_Event e;
346 Accessibility_DeviceEvent mouse_e;
347 gchar event_name[24];
348 gboolean is_consumed = FALSE;
350 if ((mask_return & mouse_button_mask) !=
351 (mouse_mask_state & mouse_button_mask))
353 int button_number = 0;
354 gboolean is_down = False;
356 if (!(mask_return & Button1Mask) &&
357 (mouse_mask_state & Button1Mask))
359 mouse_mask_state &= ~Button1Mask;
362 else if ((mask_return & Button1Mask) &&
363 !(mouse_mask_state & Button1Mask))
365 mouse_mask_state |= Button1Mask;
369 else if (!(mask_return & Button2Mask) &&
370 (mouse_mask_state & Button2Mask))
372 mouse_mask_state &= ~Button2Mask;
375 else if ((mask_return & Button2Mask) &&
376 !(mouse_mask_state & Button2Mask))
378 mouse_mask_state |= Button2Mask;
382 else if (!(mask_return & Button3Mask) &&
383 (mouse_mask_state & Button3Mask))
385 mouse_mask_state &= ~Button3Mask;
388 else if ((mask_return & Button3Mask) &&
389 !(mouse_mask_state & Button3Mask))
391 mouse_mask_state |= Button3Mask;
395 else if (!(mask_return & Button4Mask) &&
396 (mouse_mask_state & Button4Mask))
398 mouse_mask_state &= ~Button4Mask;
401 else if ((mask_return & Button4Mask) &&
402 !(mouse_mask_state & Button4Mask))
404 mouse_mask_state |= Button4Mask;
408 else if (!(mask_return & Button5Mask) &&
409 (mouse_mask_state & Button5Mask))
411 mouse_mask_state &= ~Button5Mask;
414 else if ((mask_return & Button5Mask) &&
415 !(mouse_mask_state & Button5Mask))
417 mouse_mask_state |= Button5Mask;
423 fprintf (stderr, "Button %d %s\n",
424 button_number, (is_down) ? "Pressed" : "Released");
426 snprintf (event_name, 22, "mouse:button:%d%c", button_number,
427 (is_down) ? 'p' : 'r');
428 /* TODO: FIXME distinguish between physical and
431 mouse_e.type = (is_down) ?
432 Accessibility_BUTTON_PRESSED_EVENT :
433 Accessibility_BUTTON_RELEASED_EVENT;
434 mouse_e.id = button_number;
435 mouse_e.hw_code = button_number;
436 mouse_e.modifiers = (CORBA_unsigned_short) mouse_mask_state;
437 mouse_e.timestamp = 0;
438 mouse_e.event_string = "";
439 mouse_e.is_text = CORBA_FALSE;
441 spi_controller_notify_mouselisteners (controller,
445 e.source = BONOBO_OBJREF (controller->registry->desktop);
446 e.detail1 = last_mouse_pos->x;
447 e.detail2 = last_mouse_pos->y;
448 spi_init_any_nil (&e.any_data);
449 CORBA_exception_init (&ev);
452 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry),
457 spi_dec_set_unlatch_pending (controller, mask_return);
469 spi_dec_mouse_check (SpiDEController *controller,
470 int *x, int *y, gboolean *moved)
472 Accessibility_Event e;
473 CORBA_Environment ev;
474 int win_x_return,win_y_return;
475 unsigned int mask_return;
476 Window root_return, child_return;
477 Display *display = spi_get_display ();
480 XQueryPointer(display, DefaultRootWindow (display),
481 &root_return, &child_return,
483 &win_x_return, &win_y_return, &mask_return);
485 * Since many clients grab the pointer, and X goes an automatic
486 * pointer grab on mouse-down, we often must detect mouse button events
487 * by polling rather than via a button grab.
488 * The while loop (rather than if) is used since it's possible that
489 * multiple buttons have changed state since we last checked.
491 if (mask_return != mouse_mask_state)
493 while (spi_dec_button_update_and_emit (controller, mask_return));
496 if (*x != last_mouse_pos->x || *y != last_mouse_pos->y)
498 e.type = "mouse:abs";
499 e.source = BONOBO_OBJREF (controller->registry->desktop);
502 spi_init_any_nil (&e.any_data);
503 CORBA_exception_init (&ev);
504 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry),
507 e.type = "mouse:rel";
508 e.source = BONOBO_OBJREF (controller->registry->desktop);
509 e.detail1 = *x - last_mouse_pos->x;
510 e.detail2 = *y - last_mouse_pos->y;
511 spi_init_any_nil (&e.any_data);
512 CORBA_exception_init (&ev);
513 last_mouse_pos->x = *x;
514 last_mouse_pos->y = *y;
515 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry),
529 spi_dec_emit_modifier_event (SpiDEController *controller, guint prev_mask,
532 Accessibility_Event e;
533 CORBA_Environment ev;
536 fprintf (stderr, "MODIFIER CHANGE EVENT! %x to %x\n",
537 prev_mask, current_mask);
540 /* set bits for the virtual modifiers like NUMLOCK */
541 if (prev_mask & _numlock_physical_mask)
542 prev_mask |= SPI_KEYMASK_NUMLOCK;
543 if (current_mask & _numlock_physical_mask)
544 current_mask |= SPI_KEYMASK_NUMLOCK;
546 e.type = "keyboard:modifiers";
547 e.source = BONOBO_OBJREF (controller->registry->desktop);
548 e.detail1 = prev_mask & key_modifier_mask;
549 e.detail2 = current_mask & key_modifier_mask;
550 spi_init_any_nil (&e.any_data);
551 CORBA_exception_init (&ev);
552 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry),
558 spi_dec_poll_mouse_moved (gpointer data)
560 SpiRegistry *registry = SPI_REGISTRY (data);
561 SpiDEController *controller = registry->de_controller;
566 mask_return = spi_dec_mouse_check (controller, &x, &y, &moved);
568 if ((mask_return & key_modifier_mask) !=
569 (mouse_mask_state & key_modifier_mask))
571 spi_dec_emit_modifier_event (controller, mouse_mask_state, mask_return);
572 mouse_mask_state = mask_return;
579 spi_dec_poll_mouse_idle (gpointer data)
581 if (! spi_dec_poll_mouse_moved (data))
585 g_timeout_add (20, spi_dec_poll_mouse_moving, data);
591 spi_dec_poll_mouse_moving (gpointer data)
593 if (spi_dec_poll_mouse_moved (data))
597 g_timeout_add (100, spi_dec_poll_mouse_idle, data);
602 #ifdef WE_NEED_UGRAB_MOUSE
604 spi_dec_ungrab_mouse (gpointer data)
606 Display *display = spi_get_display ();
609 XUngrabButton (spi_get_display (), AnyButton, AnyModifier,
610 XDefaultRootWindow (spi_get_display ()));
617 spi_dec_init_mouse_listener (SpiRegistry *registry)
619 Display *display = spi_get_display ();
620 g_timeout_add (100, spi_dec_poll_mouse_idle, registry);
624 if (XGrabButton (display, AnyButton, AnyModifier,
625 gdk_x11_get_default_root_xwindow (),
626 True, ButtonPressMask | ButtonReleaseMask,
627 GrabModeSync, GrabModeAsync, None, None) != Success) {
629 fprintf (stderr, "WARNING: could not grab mouse buttons!\n");
633 XSync (display, False);
635 fprintf (stderr, "mouse buttons grabbed\n");
641 * Eventually we can use this to make the marshalling of mask types
642 * more sane, but for now we just use this to detect
643 * the use of 'virtual' masks such as numlock and convert them to
644 * system-specific mask values (i.e. ModMask).
647 static Accessibility_ControllerEventMask
648 spi_dec_translate_mask (Accessibility_ControllerEventMask mask)
650 Accessibility_ControllerEventMask tmp_mask;
651 gboolean has_numlock;
653 has_numlock = (mask & SPI_KEYMASK_NUMLOCK);
657 tmp_mask = mask ^ SPI_KEYMASK_NUMLOCK;
658 tmp_mask |= _numlock_physical_mask;
664 static DEControllerKeyListener *
665 spi_dec_key_listener_new (CORBA_Object l,
666 const Accessibility_KeySet *keys,
667 const Accessibility_ControllerEventMask mask,
668 const Accessibility_EventTypeSeq *typeseq,
669 const Accessibility_EventListenerMode *mode,
670 CORBA_Environment *ev)
672 DEControllerKeyListener *key_listener = g_new0 (DEControllerKeyListener, 1);
673 key_listener->listener.object = bonobo_object_dup_ref (l, ev);
674 key_listener->listener.type = SPI_DEVICE_TYPE_KBD;
675 key_listener->keys = ORBit_copy_value (keys, TC_Accessibility_KeySet);
676 key_listener->mask = spi_dec_translate_mask (mask);
677 key_listener->listener.typeseq = ORBit_copy_value (typeseq, TC_Accessibility_EventTypeSeq);
679 key_listener->mode = ORBit_copy_value (mode, TC_Accessibility_EventListenerMode);
681 key_listener->mode = NULL;
684 g_print ("new listener, with mask %x, is_global %d, keys %p (%d)\n",
685 (unsigned int) key_listener->mask,
686 (int) (mode ? mode->global : 0),
687 (void *) key_listener->keys,
688 (int) (key_listener->keys ? key_listener->keys->_length : 0));
694 static DEControllerListener *
695 spi_dec_listener_new (CORBA_Object l,
696 const Accessibility_EventTypeSeq *typeseq,
697 CORBA_Environment *ev)
699 DEControllerListener *listener = g_new0 (DEControllerListener, 1);
700 listener->object = bonobo_object_dup_ref (l, ev);
701 listener->type = SPI_DEVICE_TYPE_MOUSE;
702 listener->typeseq = ORBit_copy_value (typeseq, TC_Accessibility_EventTypeSeq);
706 static DEControllerListener *
707 spi_listener_clone (DEControllerListener *listener, CORBA_Environment *ev)
709 DEControllerListener *clone = g_new0 (DEControllerListener, 1);
711 CORBA_Object_duplicate (listener->object, ev);
712 clone->type = listener->type;
713 clone->typeseq = ORBit_copy_value (listener->typeseq, TC_Accessibility_EventTypeSeq);
717 static DEControllerKeyListener *
718 spi_key_listener_clone (DEControllerKeyListener *key_listener, CORBA_Environment *ev)
720 DEControllerKeyListener *clone = g_new0 (DEControllerKeyListener, 1);
721 clone->listener.object =
722 CORBA_Object_duplicate (key_listener->listener.object, ev);
723 clone->listener.type = SPI_DEVICE_TYPE_KBD;
724 clone->keys = ORBit_copy_value (key_listener->keys, TC_Accessibility_KeySet);
725 clone->mask = key_listener->mask;
726 clone->listener.typeseq = ORBit_copy_value (key_listener->listener.typeseq, TC_Accessibility_EventTypeSeq);
727 if (key_listener->mode)
728 clone->mode = ORBit_copy_value (key_listener->mode, TC_Accessibility_EventListenerMode);
735 spi_key_listener_data_free (DEControllerKeyListener *key_listener, CORBA_Environment *ev)
737 CORBA_free (key_listener->listener.typeseq);
738 CORBA_free (key_listener->keys);
739 g_free (key_listener);
743 spi_key_listener_clone_free (DEControllerKeyListener *clone, CORBA_Environment *ev)
745 CORBA_Object_release (clone->listener.object, ev);
746 spi_key_listener_data_free (clone, ev);
750 spi_listener_clone_free (DEControllerListener *clone, CORBA_Environment *ev)
752 CORBA_Object_release (clone->object, ev);
753 CORBA_free (clone->typeseq);
758 spi_dec_listener_free (DEControllerListener *listener,
759 CORBA_Environment *ev)
761 bonobo_object_release_unref (listener->object, ev);
762 if (listener->type == SPI_DEVICE_TYPE_KBD)
763 spi_key_listener_data_free ((DEControllerKeyListener *) listener, ev);
767 _register_keygrab (SpiDEController *controller,
768 DEControllerGrabMask *grab_mask)
772 l = g_list_find_custom (controller->keygrabs_list, grab_mask,
773 spi_grab_mask_compare_values);
776 DEControllerGrabMask *cur_mask = l->data;
778 cur_mask->ref_count++;
779 if (cur_mask->pending_remove)
781 cur_mask->pending_remove = FALSE;
786 controller->keygrabs_list =
787 g_list_prepend (controller->keygrabs_list,
788 spi_grab_mask_clone (grab_mask));
793 _deregister_keygrab (SpiDEController *controller,
794 DEControllerGrabMask *grab_mask)
798 l = g_list_find_custom (controller->keygrabs_list, grab_mask,
799 spi_grab_mask_compare_values);
803 DEControllerGrabMask *cur_mask = l->data;
805 cur_mask->ref_count--;
806 if (cur_mask->ref_count <= 0)
808 cur_mask->pending_remove = TRUE;
813 DBG (1, g_warning ("De-registering non-existant grab"));
818 handle_keygrab (SpiDEController *controller,
819 DEControllerKeyListener *key_listener,
820 void (*process_cb) (SpiDEController *controller,
821 DEControllerGrabMask *grab_mask))
823 DEControllerGrabMask grab_mask = { 0 };
825 grab_mask.mod_mask = key_listener->mask;
826 if (key_listener->keys->_length == 0) /* special case means AnyKey/AllKeys */
828 grab_mask.key_val = AnyKey;
830 fprintf (stderr, "AnyKey grab!");
832 process_cb (controller, &grab_mask);
838 for (i = 0; i < key_listener->keys->_length; ++i)
840 Accessibility_KeyDefinition keydef = key_listener->keys->_buffer[i];
841 long int key_val = keydef.keysym;
842 /* X Grabs require keycodes, not keysyms */
843 if (keydef.keystring && keydef.keystring[0])
845 key_val = XStringToKeysym(keydef.keystring);
849 key_val = XKeysymToKeycode (spi_get_display (), (KeySym) key_val);
853 key_val = keydef.keycode;
855 grab_mask.key_val = key_val;
856 process_cb (controller, &grab_mask);
862 spi_controller_register_global_keygrabs (SpiDEController *controller,
863 DEControllerKeyListener *key_listener)
865 handle_keygrab (controller, key_listener, _register_keygrab);
866 if (controller->xevie_display == NULL)
867 return spi_controller_update_key_grabs (controller, NULL);
873 spi_controller_deregister_global_keygrabs (SpiDEController *controller,
874 DEControllerKeyListener *key_listener)
876 handle_keygrab (controller, key_listener, _deregister_keygrab);
877 if (controller->xevie_display == NULL)
878 spi_controller_update_key_grabs (controller, NULL);
882 spi_controller_register_device_listener (SpiDEController *controller,
883 DEControllerListener *listener,
884 CORBA_Environment *ev)
886 DEControllerKeyListener *key_listener;
888 switch (listener->type) {
889 case SPI_DEVICE_TYPE_KBD:
890 key_listener = (DEControllerKeyListener *) listener;
892 controller->key_listeners = g_list_prepend (controller->key_listeners,
894 if (key_listener->mode->global)
896 return spi_controller_register_global_keygrabs (controller, key_listener);
901 case SPI_DEVICE_TYPE_MOUSE:
902 controller->mouse_listeners = g_list_prepend (controller->mouse_listeners, listener);
905 DBG (1, g_warning ("listener registration for unknown device type.\n"));
912 spi_controller_notify_mouselisteners (SpiDEController *controller,
913 const Accessibility_DeviceEvent *event,
914 CORBA_Environment *ev)
917 GSList *notify = NULL, *l2;
918 GList **listeners = &controller->mouse_listeners;
919 gboolean is_consumed;
920 gboolean found = FALSE;
927 for (l = *listeners; l; l = l->next)
929 DEControllerListener *listener = l->data;
931 if (spi_eventtype_seq_contains_event (listener->typeseq, event))
933 Accessibility_DeviceEventListener ls = listener->object;
935 if (ls != CORBA_OBJECT_NIL)
937 /* we clone (don't dup) the listener, to avoid refcount inc. */
938 notify = g_slist_prepend (notify,
939 spi_listener_clone (listener, ev));
945 #ifdef SPI_KEYEVENT_DEBUG
948 g_print ("no match for event\n");
953 for (l2 = notify; l2 && !is_consumed; l2 = l2->next)
955 DEControllerListener *listener = l2->data;
956 Accessibility_DeviceEventListener ls = listener->object;
958 CORBA_exception_init (ev);
959 is_consumed = Accessibility_DeviceEventListener_notifyEvent (ls, event, ev);
963 DBG (2, g_warning ("error notifying listener, removing it\n"));
964 spi_deregister_controller_device_listener (controller, listener,
966 CORBA_exception_free (ev);
969 spi_listener_clone_free ((DEControllerListener *) l2->data, ev);
972 for (; l2; l2 = l2->next)
974 DEControllerListener *listener = l2->data;
975 spi_listener_clone_free (listener, ev);
976 /* clone doesn't have its own ref, so don't use spi_device_listener_free */
979 g_slist_free (notify);
982 if (is_consumed) g_message ("consumed\n");
988 spi_device_event_controller_forward_mouse_event (SpiDEController *controller,
991 Accessibility_Event e;
992 Accessibility_DeviceEvent mouse_e;
993 CORBA_Environment ev;
994 gchar event_name[24];
995 gboolean is_consumed = FALSE;
996 gboolean xkb_mod_unlatch_occurred;
997 XButtonEvent *xbutton_event = (XButtonEvent *) xevent;
999 int button = xbutton_event->button;
1001 unsigned int mouse_button_state = xbutton_event->state;
1006 mouse_button_state |= Button1Mask;
1009 mouse_button_state |= Button2Mask;
1012 mouse_button_state |= Button3Mask;
1015 mouse_button_state |= Button4Mask;
1018 mouse_button_state |= Button5Mask;
1022 last_mouse_pos->x = ((XButtonEvent *) xevent)->x_root;
1023 last_mouse_pos->y = ((XButtonEvent *) xevent)->y_root;
1026 fprintf (stderr, "mouse button %d %s (%x)\n",
1027 xbutton_event->button,
1028 (xevent->type == ButtonPress) ? "Press" : "Release",
1029 mouse_button_state);
1031 snprintf (event_name, 22, "mouse:button:%d%c", button,
1032 (xevent->type == ButtonPress) ? 'p' : 'r');
1034 /* TODO: FIXME distinguish between physical and logical buttons */
1035 mouse_e.type = (xevent->type == ButtonPress) ?
1036 Accessibility_BUTTON_PRESSED_EVENT :
1037 Accessibility_BUTTON_RELEASED_EVENT;
1038 mouse_e.id = button;
1039 mouse_e.hw_code = button;
1040 mouse_e.modifiers = (CORBA_unsigned_short) xbutton_event->state;
1041 mouse_e.timestamp = (CORBA_unsigned_long) xbutton_event->time;
1042 mouse_e.event_string = "";
1043 mouse_e.is_text = CORBA_FALSE;
1044 if ((mouse_button_state & mouse_button_mask) !=
1045 (mouse_mask_state & mouse_button_mask))
1047 if ((mouse_mask_state & key_modifier_mask) !=
1048 (mouse_button_state & key_modifier_mask))
1049 spi_dec_emit_modifier_event (controller,
1050 mouse_mask_state, mouse_button_state);
1051 mouse_mask_state = mouse_button_state;
1053 spi_controller_notify_mouselisteners (controller, &mouse_e, &ev);
1054 e.type = CORBA_string_dup (event_name);
1055 e.source = BONOBO_OBJREF (controller->registry->desktop);
1056 e.detail1 = last_mouse_pos->x;
1057 e.detail2 = last_mouse_pos->y;
1058 spi_init_any_nil (&e.any_data);
1059 CORBA_exception_init (&ev);
1061 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry),
1066 xkb_mod_unlatch_occurred = (xevent->type == ButtonPress ||
1067 xevent->type == ButtonRelease);
1069 /* if client wants to consume this event, and XKB latch state was
1070 * unset by this button event, we reset it
1072 if (is_consumed && xkb_mod_unlatch_occurred)
1073 spi_dec_set_unlatch_pending (controller, mouse_mask_state);
1075 XAllowEvents (spi_get_display (),
1076 (is_consumed) ? SyncPointer : ReplayPointer,
1080 static GdkFilterReturn
1081 global_filter_fn (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
1083 XEvent *xevent = gdk_xevent;
1084 SpiDEController *controller;
1085 DEControllerPrivateData *priv;
1086 Display *display = spi_get_display ();
1087 controller = SPI_DEVICE_EVENT_CONTROLLER (data);
1088 priv = (DEControllerPrivateData *)
1089 g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
1091 if (xevent->type == KeyPress || xevent->type == KeyRelease)
1093 if (controller->xevie_display == NULL)
1095 gboolean is_consumed;
1098 spi_device_event_controller_forward_key_event (controller, xevent);
1105 n_events = XPending (display);
1107 #ifdef SPI_KEYEVENT_DEBUG
1108 g_print ("Number of events pending: %d\n", n_events);
1110 for (i = 0; i < n_events; i++)
1112 XNextEvent (display, &next_event);
1113 if (next_event.type != KeyPress &&
1114 next_event.type != KeyRelease)
1115 g_warning ("Unexpected event type %d in queue", next_event.type);
1118 XAllowEvents (display, AsyncKeyboard, CurrentTime);
1120 XUngrabKeyboard (display, CurrentTime);
1124 if (xevent->type == KeyPress)
1125 wait_for_release_event (xevent, controller);
1126 XAllowEvents (display, ReplayKeyboard, CurrentTime);
1130 return GDK_FILTER_CONTINUE;
1132 if (xevent->type == ButtonPress || xevent->type == ButtonRelease)
1134 spi_device_event_controller_forward_mouse_event (controller, xevent);
1136 if (xevent->type == priv->xkb_base_event_code)
1138 XkbAnyEvent * xkb_ev = (XkbAnyEvent *) xevent;
1139 /* ugly but probably necessary...*/
1140 XSynchronize (display, TRUE);
1142 if (xkb_ev->xkb_type == XkbStateNotify)
1144 XkbStateNotifyEvent *xkb_snev =
1145 (XkbStateNotifyEvent *) xkb_ev;
1146 /* check the mouse, to catch mouse events grabbed by
1147 * another client; in case we should revert this XKB delatch
1149 if (!priv->pending_xkb_mod_relatch_mask)
1153 spi_dec_mouse_check (controller, &x, &y, &moved);
1155 /* we check again, since the previous call may have
1156 changed this flag */
1157 if (priv->pending_xkb_mod_relatch_mask)
1159 unsigned int feedback_mask;
1160 #ifdef SPI_XKB_DEBUG
1161 fprintf (stderr, "relatching %x\n",
1162 priv->pending_xkb_mod_relatch_mask);
1164 /* temporarily turn off the latch bell, if it's on */
1165 XkbGetControls (display,
1166 XkbAccessXFeedbackMask,
1168 feedback_mask = priv->xkb_desc->ctrls->ax_options;
1169 if (feedback_mask & XkbAX_StickyKeysFBMask)
1171 XkbControlsChangesRec changes = {XkbAccessXFeedbackMask,
1173 priv->xkb_desc->ctrls->ax_options
1174 &= ~(XkbAX_StickyKeysFBMask);
1175 XkbChangeControls (display, priv->xkb_desc, &changes);
1177 /* TODO: account for lock as well as latch */
1178 XkbLatchModifiers (display,
1180 priv->pending_xkb_mod_relatch_mask,
1181 priv->pending_xkb_mod_relatch_mask);
1182 if (feedback_mask & XkbAX_StickyKeysFBMask)
1184 XkbControlsChangesRec changes = {XkbAccessXFeedbackMask,
1186 priv->xkb_desc->ctrls->ax_options = feedback_mask;
1187 XkbChangeControls (display, priv->xkb_desc, &changes);
1189 #ifdef SPI_XKB_DEBUG
1190 fprintf (stderr, "relatched %x\n",
1191 priv->pending_xkb_mod_relatch_mask);
1193 priv->pending_xkb_mod_relatch_mask = 0;
1197 priv->xkb_latch_mask = xkb_snev->latched_mods;
1201 DBG (2, g_warning ("XKB event %d\n", xkb_ev->xkb_type));
1202 XSynchronize (display, FALSE);
1205 return GDK_FILTER_CONTINUE;
1209 _spi_controller_device_error_handler (Display *display, XErrorEvent *error)
1211 if (error->error_code == BadAccess)
1213 g_message ("Could not complete key grab: grab already in use.\n");
1214 spi_error_code = BadAccess;
1219 return (*x_default_error_handler) (display, error);
1224 spi_controller_register_with_devices (SpiDEController *controller)
1226 DEControllerPrivateData *priv = (DEControllerPrivateData *)
1227 g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
1228 /* FIXME: should check for extension first! */
1229 XTestGrabControl (spi_get_display (), True);
1231 /* calls to device-specific implementations and routines go here */
1232 /* register with: keyboard hardware code handler */
1233 /* register with: (translated) keystroke handler */
1235 priv->have_xkb = XkbQueryExtension (spi_get_display (),
1236 &priv->xkb_major_extension_opcode,
1237 &priv->xkb_base_event_code,
1238 &priv->xkb_base_error_code, NULL, NULL);
1242 guint64 reserved = 0;
1243 priv->xkb_desc = XkbGetMap (spi_get_display (), XkbKeySymsMask, XkbUseCoreKbd);
1244 XkbSelectEvents (spi_get_display (),
1246 XkbStateNotifyMask, XkbStateNotifyMask);
1247 _numlock_physical_mask = XkbKeysymToModifiers (spi_get_display (),
1249 for (i = priv->xkb_desc->max_key_code; i >= priv->xkb_desc->min_key_code; --i)
1251 if (priv->xkb_desc->map->key_sym_map[i].kt_index[0] == XkbOneLevelIndex)
1253 if (XKeycodeToKeysym (spi_get_display (), i, 0) != 0)
1255 /* don't use this one if there's a grab client! */
1256 gdk_error_trap_push ();
1257 XGrabKey (spi_get_display (), i, 0,
1258 gdk_x11_get_default_root_xwindow (),
1260 GrabModeSync, GrabModeSync);
1261 XSync (spi_get_display (), TRUE);
1262 XUngrabKey (spi_get_display (), i, 0,
1263 gdk_x11_get_default_root_xwindow ());
1264 if (!gdk_error_trap_pop ())
1274 priv->reserved_keycode = reserved;
1275 priv->reserved_keysym = XKeycodeToKeysym (spi_get_display (), reserved, 0);
1279 priv->reserved_keycode = XKeysymToKeycode (spi_get_display (), XK_numbersign);
1280 priv->reserved_keysym = XK_numbersign;
1282 #ifdef SPI_RESERVED_DEBUG
1284 sym = XKeycodeToKeysym (spi_get_display (), reserved, 0);
1285 fprintf (stderr, "%x\n", sym);
1286 fprintf (stderr, "setting the reserved keycode to %d (%s)\n",
1288 XKeysymToString (XKeycodeToKeysym (spi_get_display (),
1293 gdk_window_add_filter (NULL, global_filter_fn, controller);
1295 gdk_window_set_events (gdk_get_default_root_window (),
1296 GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
1298 x_default_error_handler = XSetErrorHandler (_spi_controller_device_error_handler);
1302 spi_key_set_contains_key (Accessibility_KeySet *key_set,
1303 const Accessibility_DeviceEvent *key_event)
1310 g_print ("null key set!");
1314 len = key_set->_length;
1316 if (len == 0) /* special case, means "all keys/any key" */
1318 g_print ("anykey\n");
1322 for (i = 0; i < len; ++i)
1324 #ifdef SPI_KEYEVENT_DEBUG
1325 g_print ("key_set[%d] event = %d, code = %d; key_event %d, code %d, string %s\n",
1327 (int)key_set->_buffer[i].keysym,
1328 (int) key_set->_buffer[i].keycode,
1329 (int) key_event->id,
1330 (int) key_event->hw_code,
1331 key_event->event_string);
1333 if (key_set->_buffer[i].keysym == (CORBA_long) key_event->id)
1337 if (key_set->_buffer[i].keycode == (CORBA_long) key_event->hw_code)
1341 if (key_event->event_string && key_event->event_string[0] &&
1342 !strcmp (key_set->_buffer[i].keystring, key_event->event_string))
1352 spi_eventtype_seq_contains_event (Accessibility_EventTypeSeq *type_seq,
1353 const Accessibility_DeviceEvent *event)
1361 g_print ("null type seq!");
1365 len = type_seq->_length;
1367 if (len == 0) /* special case, means "all events/any event" */
1372 for (i = 0; i < len; ++i)
1375 g_print ("type_seq[%d] = %d; event type = %d\n", i,
1376 (int) type_seq->_buffer[i], (int) event->type);
1378 if (type_seq->_buffer[i] == (CORBA_long) event->type)
1388 spi_key_event_matches_listener (const Accessibility_DeviceEvent *key_event,
1389 DEControllerKeyListener *listener,
1390 CORBA_boolean is_system_global)
1392 if ((key_event->modifiers == (CORBA_unsigned_short) (listener->mask & 0xFF)) &&
1393 spi_key_set_contains_key (listener->keys, key_event) &&
1394 spi_eventtype_seq_contains_event (listener->listener.typeseq, key_event) &&
1395 (is_system_global == listener->mode->global))
1406 spi_controller_notify_keylisteners (SpiDEController *controller,
1407 const Accessibility_DeviceEvent *key_event,
1408 CORBA_boolean is_system_global,
1409 CORBA_Environment *ev)
1412 GSList *notify = NULL, *l2;
1413 GList **key_listeners = &controller->key_listeners;
1414 gboolean is_consumed;
1421 for (l = *key_listeners; l; l = l->next)
1423 DEControllerKeyListener *key_listener = l->data;
1425 if (spi_key_event_matches_listener (key_event, key_listener, is_system_global))
1427 Accessibility_DeviceEventListener ls = key_listener->listener.object;
1429 if (ls != CORBA_OBJECT_NIL)
1431 /* we clone (don't dup) the listener, to avoid refcount inc. */
1432 notify = g_slist_prepend (notify,
1433 spi_key_listener_clone (key_listener, ev));
1438 #ifdef SPI_KEYEVENT_DEBUG
1441 g_print ("no match for event\n");
1445 is_consumed = FALSE;
1446 for (l2 = notify; l2 && !is_consumed; l2 = l2->next)
1448 DEControllerKeyListener *key_listener = l2->data;
1449 Accessibility_DeviceEventListener ls = key_listener->listener.object;
1451 is_consumed = Accessibility_DeviceEventListener_notifyEvent (ls, key_event, ev);
1455 is_consumed = FALSE;
1456 spi_deregister_controller_key_listener (controller, key_listener,
1458 CORBA_exception_free (ev);
1461 spi_key_listener_clone_free (key_listener, ev);
1464 for (; l2; l2 = l2->next)
1466 DEControllerKeyListener *key_listener = l2->data;
1467 spi_key_listener_clone_free (key_listener, ev);
1468 /* clone doesn't have its own ref, so don't use spi_dec_listener_free */
1471 g_slist_free (notify);
1474 if (is_consumed) g_message ("consumed\n");
1480 spi_clear_error_state ()
1482 gboolean retval = spi_error_code != 0;
1487 static Accessibility_DeviceEvent
1488 spi_keystroke_from_x_key_event (XKeyEvent *x_key_event)
1490 Accessibility_DeviceEvent key_event;
1492 const int cbuf_bytes = 20;
1496 nbytes = XLookupString (x_key_event, cbuf, cbuf_bytes, &keysym, NULL);
1497 key_event.id = (CORBA_long)(keysym);
1498 key_event.hw_code = (CORBA_short) x_key_event->keycode;
1499 if (((XEvent *) x_key_event)->type == KeyPress)
1501 key_event.type = Accessibility_KEY_PRESSED_EVENT;
1505 key_event.type = Accessibility_KEY_RELEASED_EVENT;
1507 key_event.modifiers = (CORBA_unsigned_short)(x_key_event->state);
1508 key_event.is_text = CORBA_FALSE;
1512 key_event.event_string = CORBA_string_dup ("space");
1515 key_event.event_string = CORBA_string_dup ("Tab");
1518 key_event.event_string = CORBA_string_dup ("Backspace");
1521 key_event.event_string = CORBA_string_dup ("Return");
1524 key_event.event_string = CORBA_string_dup ("Home");
1527 key_event.event_string = CORBA_string_dup ("Page_Down");
1530 key_event.event_string = CORBA_string_dup ("Page_Up");
1533 key_event.event_string = CORBA_string_dup ("F1");
1536 key_event.event_string = CORBA_string_dup ("F2");
1539 key_event.event_string = CORBA_string_dup ("F3");
1542 key_event.event_string = CORBA_string_dup ("F4");
1545 key_event.event_string = CORBA_string_dup ("F5");
1548 key_event.event_string = CORBA_string_dup ("F6");
1551 key_event.event_string = CORBA_string_dup ("F7");
1554 key_event.event_string = CORBA_string_dup ("F8");
1557 key_event.event_string = CORBA_string_dup ("F9");
1560 key_event.event_string = CORBA_string_dup ("F10");
1563 key_event.event_string = CORBA_string_dup ("F11");
1566 key_event.event_string = CORBA_string_dup ("F12");
1569 key_event.event_string = CORBA_string_dup ("End");
1572 key_event.event_string = CORBA_string_dup ("Escape");
1575 key_event.event_string = CORBA_string_dup ("Up");
1578 key_event.event_string = CORBA_string_dup ("Down");
1581 key_event.event_string = CORBA_string_dup ("Left");
1584 key_event.event_string = CORBA_string_dup ("Right");
1590 cbuf[nbytes] = '\0'; /* OK since length is cbuf_bytes+1 */
1591 key_event.event_string = CORBA_string_dup (cbuf);
1592 c = g_utf8_get_char_validated (cbuf, nbytes);
1593 if ((c > 0) && g_unichar_isprint (c))
1595 key_event.is_text = CORBA_TRUE;
1596 /* incorrect for some composed chars? */
1601 key_event.event_string = CORBA_string_dup ("");
1605 key_event.timestamp = (CORBA_unsigned_long) x_key_event->time;
1606 #ifdef SPI_KEYEVENT_DEBUG
1608 char *pressed_str = "pressed";
1609 char *released_str = "released";
1612 if (key_event.type == Accessibility_KEY_PRESSED_EVENT)
1613 state_ptr = pressed_str;
1615 state_ptr = released_str;
1618 "Key %lu %s (%c), modifiers %d; string=%s [%x] %s\n",
1619 (unsigned long) keysym,
1621 keysym ? (int) keysym : '*',
1622 (int) x_key_event->state,
1623 key_event.event_string,
1624 key_event.event_string[0],
1625 (key_event.is_text == CORBA_TRUE) ? "(text)" : "(not text)");
1629 fprintf (stderr, "%s%c\n",
1630 (x_key_event->state & Mod1Mask)?"Alt-":"",
1631 ((x_key_event->state & ShiftMask)^(x_key_event->state & LockMask))?
1632 g_ascii_toupper (keysym) : g_ascii_tolower (keysym));
1633 fprintf (stderr, "serial: %x Time: %x\n", x_key_event->serial, x_key_event->time);
1634 #endif /* SPI_DEBUG */
1639 spi_controller_update_key_grabs (SpiDEController *controller,
1640 Accessibility_DeviceEvent *recv)
1643 gboolean update_failed = FALSE;
1646 g_return_val_if_fail (controller != NULL, FALSE);
1649 * masks known to work with default RH 7.1+:
1650 * 0 (no mods), LockMask, Mod1Mask, Mod2Mask, ShiftMask,
1651 * ShiftMask|LockMask, Mod1Mask|LockMask, Mod2Mask|LockMask,
1652 * ShiftMask|Mod1Mask, ShiftMask|Mod2Mask, Mod1Mask|Mod2Mask,
1653 * ShiftMask|LockMask|Mod1Mask, ShiftMask|LockMask|Mod2Mask,
1655 * ControlMask grabs are broken, must be in use already
1658 keycode = keycode_for_keysym (controller, recv->id, NULL);
1659 for (l = controller->keygrabs_list; l; l = next)
1662 gboolean re_issue_grab;
1663 DEControllerGrabMask *grab_mask = l->data;
1667 re_issue_grab = recv &&
1668 (recv->modifiers & grab_mask->mod_mask) &&
1669 (grab_mask->key_val == keycode);
1672 fprintf (stderr, "mask=%lx %lx (%c%c) %s\n",
1673 (long int) grab_mask->key_val,
1674 (long int) grab_mask->mod_mask,
1675 grab_mask->pending_add ? '+' : '.',
1676 grab_mask->pending_remove ? '-' : '.',
1677 re_issue_grab ? "re-issue": "");
1682 if (grab_mask->pending_add && grab_mask->pending_remove)
1686 else if (grab_mask->pending_remove)
1689 fprintf (stderr, "ungrabbing, mask=%x\n", grab_mask->mod_mask);
1691 XUngrabKey (spi_get_display (),
1693 grab_mask->mod_mask,
1694 gdk_x11_get_default_root_xwindow ());
1698 else if (grab_mask->pending_add || re_issue_grab)
1702 fprintf (stderr, "grab %d with mask %x\n", grab_mask->key_val, grab_mask->mod_mask);
1704 XGrabKey (spi_get_display (),
1706 grab_mask->mod_mask,
1707 gdk_x11_get_default_root_xwindow (),
1711 XSync (spi_get_display (), False);
1712 update_failed = spi_clear_error_state ();
1713 if (update_failed) {
1714 while (grab_mask->ref_count > 0) --grab_mask->ref_count;
1719 grab_mask->pending_add = FALSE;
1720 grab_mask->pending_remove = FALSE;
1724 g_assert (grab_mask->ref_count <= 0);
1726 controller->keygrabs_list = g_list_delete_link (
1727 controller->keygrabs_list, l);
1729 spi_grab_mask_free (grab_mask);
1734 return ! update_failed;
1738 * Implemented GObject::finalize
1741 spi_device_event_controller_object_finalize (GObject *object)
1743 SpiDEController *controller;
1744 DEControllerPrivateData *private;
1745 controller = SPI_DEVICE_EVENT_CONTROLLER (object);
1748 fprintf(stderr, "spi_device_event_controller_object_finalize called\n");
1750 /* disconnect any special listeners, get rid of outstanding keygrabs */
1751 XUngrabKey (spi_get_display (), AnyKey, AnyModifier, DefaultRootWindow (spi_get_display ()));
1754 if (controller->xevie_display != NULL)
1756 XevieEnd(controller->xevie_display);
1757 #ifdef SPI_KEYEVENT_DEBUG
1758 printf("XevieEnd(dpy) finished \n");
1763 private = g_object_get_data (G_OBJECT (controller), "spi-dec-private");
1764 if (private->xkb_desc)
1765 XkbFreeKeyboard (private->xkb_desc, 0, True);
1767 spi_device_event_controller_parent_class->finalize (object);
1771 * CORBA Accessibility::DEController::registerKeystrokeListener
1772 * method implementation
1774 static CORBA_boolean
1775 impl_register_keystroke_listener (PortableServer_Servant servant,
1776 const Accessibility_DeviceEventListener l,
1777 const Accessibility_KeySet *keys,
1778 const Accessibility_ControllerEventMask mask,
1779 const Accessibility_EventTypeSeq *type,
1780 const Accessibility_EventListenerMode *mode,
1781 CORBA_Environment *ev)
1783 SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1784 bonobo_object_from_servant (servant));
1785 DEControllerKeyListener *dec_listener;
1787 fprintf (stderr, "registering keystroke listener %p with maskVal %lu\n",
1788 (void *) l, (unsigned long) mask);
1790 dec_listener = spi_dec_key_listener_new (l, keys, mask, type, mode, ev);
1791 return spi_controller_register_device_listener (
1792 controller, (DEControllerListener *) dec_listener, ev);
1797 * CORBA Accessibility::DEController::registerDeviceEventListener
1798 * method implementation
1800 static CORBA_boolean
1801 impl_register_device_listener (PortableServer_Servant servant,
1802 const Accessibility_DeviceEventListener l,
1803 const Accessibility_EventTypeSeq *event_types,
1804 CORBA_Environment *ev)
1806 SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1807 bonobo_object_from_servant (servant));
1808 DEControllerListener *dec_listener;
1810 dec_listener = spi_dec_listener_new (l, event_types, ev);
1811 return spi_controller_register_device_listener (
1812 controller, (DEControllerListener *) dec_listener, ev);
1816 CORBA_Environment *ev;
1817 DEControllerListener *listener;
1818 } RemoveListenerClosure;
1820 static SpiReEntrantContinue
1821 remove_listener_cb (GList * const *list,
1824 DEControllerListener *listener = (*list)->data;
1825 RemoveListenerClosure *ctx = user_data;
1827 if (CORBA_Object_is_equivalent (ctx->listener->object,
1828 listener->object, ctx->ev))
1830 spi_re_entrant_list_delete_link (list);
1831 spi_dec_listener_free (listener, ctx->ev);
1834 return SPI_RE_ENTRANT_CONTINUE;
1837 static SpiReEntrantContinue
1838 copy_key_listener_cb (GList * const *list,
1841 DEControllerKeyListener *key_listener = (*list)->data;
1842 RemoveListenerClosure *ctx = user_data;
1844 if (CORBA_Object_is_equivalent (ctx->listener->object,
1845 key_listener->listener.object, ctx->ev))
1847 /* TODO: FIXME aggregate keys in case the listener is registered twice */
1848 DEControllerKeyListener *ctx_key_listener =
1849 (DEControllerKeyListener *) ctx->listener;
1850 CORBA_free (ctx_key_listener->keys);
1851 ctx_key_listener->keys = ORBit_copy_value (key_listener->keys, TC_Accessibility_KeySet);
1854 return SPI_RE_ENTRANT_CONTINUE;
1858 spi_deregister_controller_device_listener (SpiDEController *controller,
1859 DEControllerListener *listener,
1860 CORBA_Environment *ev)
1862 RemoveListenerClosure ctx;
1865 ctx.listener = listener;
1867 spi_re_entrant_list_foreach (&controller->mouse_listeners,
1868 remove_listener_cb, &ctx);
1872 spi_deregister_controller_key_listener (SpiDEController *controller,
1873 DEControllerKeyListener *key_listener,
1874 CORBA_Environment *ev)
1876 RemoveListenerClosure ctx;
1879 ctx.listener = (DEControllerListener *) key_listener;
1881 /* special case, copy keyset from existing controller list entry */
1882 if (key_listener->keys->_length == 0)
1884 spi_re_entrant_list_foreach (&controller->key_listeners,
1885 copy_key_listener_cb, &ctx);
1888 spi_controller_deregister_global_keygrabs (controller, key_listener);
1890 spi_re_entrant_list_foreach (&controller->key_listeners,
1891 remove_listener_cb, &ctx);
1896 * CORBA Accessibility::DEController::deregisterKeystrokeListener
1897 * method implementation
1900 impl_deregister_keystroke_listener (PortableServer_Servant servant,
1901 const Accessibility_DeviceEventListener l,
1902 const Accessibility_KeySet *keys,
1903 const Accessibility_ControllerEventMask mask,
1904 const Accessibility_EventTypeSeq *type,
1905 CORBA_Environment *ev)
1907 DEControllerKeyListener *key_listener;
1908 SpiDEController *controller;
1910 controller = SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
1912 key_listener = spi_dec_key_listener_new (l, keys, mask, type, NULL, ev);
1914 #ifdef SPI_DEREGISTER_DEBUG
1915 fprintf (stderr, "deregistering keystroke listener %p with maskVal %lu\n",
1916 (void *) l, (unsigned long) mask->value);
1919 spi_deregister_controller_key_listener (controller, key_listener, ev);
1921 spi_dec_listener_free ((DEControllerListener *) key_listener, ev);
1925 * CORBA Accessibility::DEController::deregisterDeviceEventListener
1926 * method implementation
1929 impl_deregister_device_listener (PortableServer_Servant servant,
1930 const Accessibility_DeviceEventListener l,
1931 const Accessibility_EventTypeSeq *event_types,
1932 CORBA_Environment *ev)
1934 SpiDEController *controller;
1935 DEControllerListener *listener =
1936 spi_dec_listener_new (l, event_types, ev);
1938 controller = SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
1940 spi_deregister_controller_device_listener (controller, listener, ev);
1942 spi_dec_listener_free (listener, ev);
1945 static unsigned int dec_xkb_get_slowkeys_delay (SpiDEController *controller)
1947 unsigned int retval = 0;
1948 DEControllerPrivateData *priv = (DEControllerPrivateData *)
1949 g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
1951 #ifdef XKB_HAS_GET_SLOW_KEYS_DELAY
1952 retval = XkbGetSlowKeysDelay (spi_get_display (),
1953 XkbUseCoreKbd, &bounce_delay);
1955 if (!(priv->xkb_desc == (XkbDescPtr) BadAlloc || priv->xkb_desc == NULL))
1957 Status s = XkbGetControls (spi_get_display (),
1958 XkbAllControlsMask, priv->xkb_desc);
1961 if (priv->xkb_desc->ctrls->enabled_ctrls & XkbSlowKeysMask)
1962 retval = priv->xkb_desc->ctrls->slow_keys_delay;
1967 #ifdef SPI_XKB_DEBUG
1968 fprintf (stderr, "SlowKeys delay: %d\n", (int) retval);
1973 static unsigned int dec_xkb_get_bouncekeys_delay (SpiDEController *controller)
1975 unsigned int retval = 0;
1976 DEControllerPrivateData *priv = (DEControllerPrivateData *)
1977 g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
1979 #ifdef XKB_HAS_GET_BOUNCE_KEYS_DELAY
1980 retval = XkbGetBounceKeysDelay (spi_get_display (),
1981 XkbUseCoreKbd, &bounce_delay);
1983 if (!(priv->xkb_desc == (XkbDescPtr) BadAlloc || priv->xkb_desc == NULL))
1985 Status s = XkbGetControls (spi_get_display (),
1986 XkbAllControlsMask, priv->xkb_desc);
1989 if (priv->xkb_desc->ctrls->enabled_ctrls & XkbBounceKeysMask)
1990 retval = priv->xkb_desc->ctrls->debounce_delay;
1995 #ifdef SPI_XKB_DEBUG
1996 fprintf (stderr, "BounceKeys delay: %d\n", (int) retval);
2002 dec_synth_keycode_press (SpiDEController *controller,
2003 unsigned int keycode)
2005 unsigned int time = CurrentTime;
2006 unsigned int bounce_delay;
2007 unsigned int elapsed_msec;
2009 DEControllerPrivateData *priv =
2010 (DEControllerPrivateData *) g_object_get_qdata (G_OBJECT (controller),
2011 spi_dec_private_quark);
2012 if (keycode == priv->last_release_keycode)
2014 bounce_delay = dec_xkb_get_bouncekeys_delay (controller);
2017 gettimeofday (&tv, NULL);
2019 (tv.tv_sec - priv->last_release_time.tv_sec) * 1000
2020 + (tv.tv_usec - priv->last_release_time.tv_usec) / 1000;
2021 #ifdef SPI_XKB_DEBUG
2022 fprintf (stderr, "%d ms elapsed (%ld usec)\n", elapsed_msec,
2023 (long) (tv.tv_usec - priv->last_release_time.tv_usec));
2025 #ifdef THIS_IS_BROKEN
2026 if (elapsed_msec < bounce_delay)
2027 time = bounce_delay - elapsed_msec + 1;
2029 time = bounce_delay + 10;
2030 /* fudge for broken XTest */
2032 #ifdef SPI_XKB_DEBUG
2033 fprintf (stderr, "waiting %d ms\n", time);
2037 XTestFakeKeyEvent (spi_get_display (), keycode, True, time);
2038 priv->last_press_keycode = keycode;
2039 XFlush (spi_get_display ());
2040 XSync (spi_get_display (), False);
2041 gettimeofday (&priv->last_press_time, NULL);
2046 dec_synth_keycode_release (SpiDEController *controller,
2047 unsigned int keycode)
2049 unsigned int time = CurrentTime;
2050 unsigned int slow_delay;
2051 unsigned int elapsed_msec;
2053 DEControllerPrivateData *priv =
2054 (DEControllerPrivateData *) g_object_get_qdata (G_OBJECT (controller),
2055 spi_dec_private_quark);
2056 if (keycode == priv->last_press_keycode)
2058 slow_delay = dec_xkb_get_slowkeys_delay (controller);
2061 gettimeofday (&tv, NULL);
2063 (tv.tv_sec - priv->last_press_time.tv_sec) * 1000
2064 + (tv.tv_usec - priv->last_press_time.tv_usec) / 1000;
2065 #ifdef SPI_XKB_DEBUG
2066 fprintf (stderr, "%d ms elapsed (%ld usec)\n", elapsed_msec,
2067 (long) (tv.tv_usec - priv->last_press_time.tv_usec));
2069 #ifdef THIS_IS_BROKEN_DUNNO_WHY
2070 if (elapsed_msec < slow_delay)
2071 time = slow_delay - elapsed_msec + 1;
2073 time = slow_delay + 10;
2074 /* our XTest seems broken, we have to add slop as above */
2076 #ifdef SPI_XKB_DEBUG
2077 fprintf (stderr, "waiting %d ms\n", time);
2081 XTestFakeKeyEvent (spi_get_display (), keycode, False, time);
2082 priv->last_release_keycode = keycode;
2083 XSync (spi_get_display (), False);
2084 gettimeofday (&priv->last_release_time, NULL);
2089 dec_get_modifier_state (SpiDEController *controller)
2091 return mouse_mask_state;
2095 dec_lock_modifiers (SpiDEController *controller, unsigned modifiers)
2097 return XkbLockModifiers (spi_get_display (), XkbUseCoreKbd,
2098 modifiers, modifiers);
2102 dec_unlock_modifiers (SpiDEController *controller, unsigned modifiers)
2104 return XkbLockModifiers (spi_get_display (), XkbUseCoreKbd,
2109 dec_keysym_for_unichar (SpiDEController *controller, gunichar unichar)
2111 return ucs2keysym ((long) unichar);
2115 dec_synth_keysym (SpiDEController *controller, KeySym keysym)
2117 KeyCode key_synth_code;
2118 unsigned int modifiers, synth_mods, lock_mods;
2120 key_synth_code = keycode_for_keysym (controller, keysym, &synth_mods);
2122 if ((key_synth_code == 0) || (synth_mods == 0xFF)) return FALSE;
2124 /* TODO: set the modifiers accordingly! */
2125 modifiers = dec_get_modifier_state (controller);
2126 /* side-effect; we may unset mousebutton modifiers here! */
2129 if (synth_mods != modifiers) {
2130 lock_mods = synth_mods & ~modifiers;
2131 dec_lock_modifiers (controller, lock_mods);
2133 dec_synth_keycode_press (controller, key_synth_code);
2134 dec_synth_keycode_release (controller, key_synth_code);
2136 if (synth_mods != modifiers)
2137 dec_unlock_modifiers (controller, lock_mods);
2143 dec_synth_keystring (SpiDEController *controller, const CORBA_char *keystring)
2145 /* probably we need to create and inject an XIM handler eventually. */
2146 /* for now, try to match the string to existing
2147 * keycode+modifier states.
2151 gunichar unichar = 0;
2153 gboolean retval = TRUE;
2156 maxlen = strlen (keystring);
2157 keysyms = g_new0 (KeySym, maxlen);
2158 if (!(keystring && *keystring && g_utf8_validate (keystring, -1, &c))) {
2163 fprintf (stderr, "[keystring synthesis attempted on %s]\n", keystring);
2165 while (keystring && (unichar = g_utf8_get_char (keystring))) {
2170 mbytes = g_unichar_to_utf8 (unichar, bytes);
2171 bytes[mbytes] = '\0';
2173 fprintf (stderr, "[unichar %s]", bytes);
2175 keysym = dec_keysym_for_unichar (controller, unichar);
2176 if (keysym == NoSymbol) {
2178 fprintf (stderr, "no keysym for %s", bytes);
2183 keysyms[i++] = keysym;
2184 keystring = g_utf8_next_char (keystring);
2187 XSynchronize (spi_get_display (), TRUE);
2188 for (i = 0; keysyms[i]; ++i) {
2189 if (!dec_synth_keysym (controller, keysyms[i])) {
2191 fprintf (stderr, "could not synthesize %c\n",
2198 XSynchronize (spi_get_display (), FALSE);
2207 * CORBA Accessibility::DEController::registerKeystrokeListener
2208 * method implementation
2211 impl_generate_keyboard_event (PortableServer_Servant servant,
2212 const CORBA_long keycode,
2213 const CORBA_char *keystring,
2214 const Accessibility_KeySynthType synth_type,
2215 CORBA_Environment *ev)
2217 SpiDEController *controller =
2218 SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
2219 long key_synth_code;
2224 fprintf (stderr, "synthesizing keystroke %ld, type %d\n",
2225 (long) keycode, (int) synth_type);
2227 /* TODO: hide/wrap/remove X dependency */
2230 * TODO: when initializing, query for XTest extension before using,
2231 * and fall back to XSendEvent() if XTest is not available.
2234 gdk_error_trap_push ();
2235 key_synth_code = keycode;
2239 case Accessibility_KEY_PRESS:
2240 dec_synth_keycode_press (controller, keycode);
2242 case Accessibility_KEY_PRESSRELEASE:
2243 dec_synth_keycode_press (controller, keycode);
2244 case Accessibility_KEY_RELEASE:
2245 dec_synth_keycode_release (controller, keycode);
2247 case Accessibility_KEY_SYM:
2248 #ifdef SPI_XKB_DEBUG
2249 fprintf (stderr, "KeySym synthesis\n");
2252 * note: we are using long for 'keycode'
2253 * in our arg list; it can contain either
2254 * a keycode or a keysym.
2256 dec_synth_keysym (controller, (KeySym) keycode);
2258 case Accessibility_KEY_STRING:
2259 if (!dec_synth_keystring (controller, keystring))
2260 fprintf (stderr, "Keystring synthesis failure, string=%s\n",
2264 if (err = gdk_error_trap_pop ())
2266 DBG (-1, g_warning ("Error [%d] emitting keystroke", err));
2268 if (synth_type == Accessibility_KEY_SYM) {
2272 keysym = XkbKeycodeToKeysym (spi_get_display (), keycode, 0, 0);
2274 if (XkbKeysymToModifiers (spi_get_display (), keysym) == 0)
2276 spi_dec_clear_unlatch_pending (controller);
2280 /* Accessibility::DEController::generateMouseEvent */
2282 impl_generate_mouse_event (PortableServer_Servant servant,
2285 const CORBA_char *eventName,
2286 CORBA_Environment *ev)
2289 gboolean error = FALSE;
2290 Display *display = spi_get_display ();
2292 fprintf (stderr, "generating mouse %s event at %ld, %ld\n",
2293 eventName, (long int) x, (long int) y);
2295 switch (eventName[0])
2298 switch (eventName[1])
2300 /* TODO: check number of buttons before parsing */
2321 if (x != -1 && y != -1)
2323 XTestFakeMotionEvent (display, DefaultScreen (display),
2326 XTestFakeButtonEvent (display, button, !(eventName[2] == 'r'), 0);
2327 if (eventName[2] == 'c')
2328 XTestFakeButtonEvent (display, button, FALSE, 1);
2329 else if (eventName[2] == 'd')
2331 XTestFakeButtonEvent (display, button, FALSE, 1);
2332 XTestFakeButtonEvent (display, button, TRUE, 2);
2333 XTestFakeButtonEvent (display, button, FALSE, 3);
2337 case 'r': /* relative motion */
2338 XTestFakeRelativeMotionEvent (display, x, y, 0);
2340 case 'a': /* absolute motion */
2341 XTestFakeMotionEvent (display, DefaultScreen (display),
2347 /* Accessibility::DEController::notifyListenersSync */
2348 static CORBA_boolean
2349 impl_notify_listeners_sync (PortableServer_Servant servant,
2350 const Accessibility_DeviceEvent *event,
2351 CORBA_Environment *ev)
2353 SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
2354 bonobo_object_from_servant (servant));
2356 g_print ("notifylistening listeners synchronously: controller %p, event id %d\n",
2357 controller, (int) event->id);
2359 return spi_controller_notify_keylisteners (controller, event, CORBA_FALSE, ev) ?
2360 CORBA_TRUE : CORBA_FALSE;
2363 /* Accessibility::DEController::notifyListenersAsync */
2365 impl_notify_listeners_async (PortableServer_Servant servant,
2366 const Accessibility_DeviceEvent *event,
2367 CORBA_Environment *ev)
2369 SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
2370 bonobo_object_from_servant (servant));
2372 fprintf (stderr, "notifying listeners asynchronously\n");
2374 spi_controller_notify_keylisteners (controller, event, CORBA_FALSE, ev);
2378 spi_device_event_controller_class_init (SpiDEControllerClass *klass)
2380 GObjectClass * object_class = (GObjectClass *) klass;
2381 POA_Accessibility_DeviceEventController__epv *epv = &klass->epv;
2383 spi_device_event_controller_parent_class = g_type_class_peek_parent (klass);
2385 object_class->finalize = spi_device_event_controller_object_finalize;
2387 epv->registerKeystrokeListener = impl_register_keystroke_listener;
2388 epv->deregisterKeystrokeListener = impl_deregister_keystroke_listener;
2389 epv->registerDeviceEventListener = impl_register_device_listener;
2390 epv->deregisterDeviceEventListener = impl_deregister_device_listener;
2391 epv->generateKeyboardEvent = impl_generate_keyboard_event;
2392 epv->generateMouseEvent = impl_generate_mouse_event;
2393 epv->notifyListenersSync = impl_notify_listeners_sync;
2394 epv->notifyListenersAsync = impl_notify_listeners_async;
2396 if (!spi_dec_private_quark)
2397 spi_dec_private_quark = g_quark_from_static_string ("spi-dec-private");
2401 Bool isEvent(dpy,event,arg)
2410 handle_io (GIOChannel *source,
2411 GIOCondition condition,
2414 SpiDEController *controller = (SpiDEController *) data;
2415 gboolean is_consumed = FALSE;
2418 while (XCheckIfEvent(controller->xevie_display, &ev, isEvent, NULL))
2420 if (ev.type == KeyPress || ev.type == KeyRelease)
2421 is_consumed = spi_device_event_controller_forward_key_event (controller, &ev);
2424 XevieSendEvent(controller->xevie_display, &ev, XEVIE_UNMODIFIED);
2429 #endif /* HAVE_XEVIE */
2432 spi_device_event_controller_init (SpiDEController *device_event_controller)
2437 #endif /* HAVE_XEVIE */
2439 DEControllerPrivateData *private;
2440 device_event_controller->key_listeners = NULL;
2441 device_event_controller->mouse_listeners = NULL;
2442 device_event_controller->keygrabs_list = NULL;
2443 device_event_controller->xevie_display = NULL;
2446 device_event_controller->xevie_display = XOpenDisplay(NULL);
2448 if (XevieStart(device_event_controller->xevie_display) == TRUE)
2450 #ifdef SPI_KEYEVENT_DEBUG
2451 fprintf (stderr, "XevieStart() success \n");
2453 XevieSelectInput(device_event_controller->xevie_display, KeyPressMask | KeyReleaseMask);
2455 fd = ConnectionNumber(device_event_controller->xevie_display);
2456 ioc = g_io_channel_unix_new (fd);
2457 g_io_add_watch (ioc, G_IO_IN | G_IO_HUP, handle_io, device_event_controller);
2458 g_io_channel_unref (ioc);
2462 device_event_controller->xevie_display = NULL;
2463 #ifdef SPI_KEYEVENT_DEBUG
2464 fprintf (stderr, "XevieStart() failed, only one client is allowed to do event int exception\n");
2467 #endif /* HAVE_XEVIE */
2469 private = g_new0 (DEControllerPrivateData, 1);
2470 gettimeofday (&private->last_press_time, NULL);
2471 gettimeofday (&private->last_release_time, NULL);
2472 g_object_set_qdata (G_OBJECT (device_event_controller),
2473 spi_dec_private_quark,
2475 spi_controller_register_with_devices (device_event_controller);
2479 spi_device_event_controller_forward_key_event (SpiDEController *controller,
2480 const XEvent *event)
2482 CORBA_Environment ev;
2483 Accessibility_DeviceEvent key_event;
2485 g_assert (event->type == KeyPress || event->type == KeyRelease);
2487 CORBA_exception_init (&ev);
2489 key_event = spi_keystroke_from_x_key_event ((XKeyEvent *) event);
2491 if (controller->xevie_display == NULL)
2492 spi_controller_update_key_grabs (controller, &key_event);
2494 /* relay to listeners, and decide whether to consume it or not */
2495 return spi_controller_notify_keylisteners (controller, &key_event, CORBA_TRUE, &ev);
2499 spi_device_event_controller_new (SpiRegistry *registry)
2501 SpiDEController *retval = g_object_new (
2502 SPI_DEVICE_EVENT_CONTROLLER_TYPE, NULL);
2504 retval->registry = SPI_REGISTRY (bonobo_object_ref (
2505 BONOBO_OBJECT (registry)));
2507 spi_dec_init_mouse_listener (registry);
2508 /* TODO: kill mouse listener on finalize */
2513 is_key_released (KeyCode code)
2519 XQueryKeymap (spi_get_display (), keys);
2520 down = BIT (keys, code);
2525 check_release (gpointer data)
2528 Accessibility_DeviceEvent *event = (Accessibility_DeviceEvent *)data;
2529 KeyCode code = event->hw_code;
2530 CORBA_Environment ev;
2532 released = is_key_released (code);
2536 check_release_handler = 0;
2537 event->type = Accessibility_KEY_RELEASED_EVENT;
2538 ev._major = CORBA_NO_EXCEPTION;
2539 spi_controller_notify_keylisteners (saved_controller, event, CORBA_TRUE, &ev);
2541 return (released == 0);
2544 static void wait_for_release_event (XEvent *event,
2545 SpiDEController *controller)
2547 pressed_event = spi_keystroke_from_x_key_event ((XKeyEvent *) event);
2548 saved_controller = controller;
2549 check_release_handler = g_timeout_add (CHECK_RELEASE_DELAY, check_release, &pressed_event);
2552 BONOBO_TYPE_FUNC_FULL (SpiDEController,
2553 Accessibility_DeviceEventController,
2555 spi_device_event_controller)