2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5 * Copyright 2001 Sun Microsystems Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
23 /* deviceeventcontroler.c: implement the DeviceEventController interface */
32 #include <bonobo/bonobo-exception.h>
35 #include <X11/extensions/XTest.h>
37 #include <X11/keysymdef.h>
39 #include <gdk/gdkx.h> /* TODO: hide dependency (wrap in single porting file) */
40 #include <gdk/gdkkeysyms.h>
41 #include <gdk/gdkwindow.h>
43 #include "../libspi/spi-private.h"
44 #include "deviceeventcontroller.h"
46 /* Our parent Gtk object type */
47 #define PARENT_TYPE BONOBO_TYPE_OBJECT
49 /* A pointer to our parent object class */
50 static GObjectClass *spi_device_event_controller_parent_class;
52 int (*x_default_error_handler) (Display *display, XErrorEvent *error_event);
56 SPI_DEVICE_TYPE_MOUSE,
57 SPI_DEVICE_TYPE_LAST_DEFINED
58 } SpiDeviceTypeCategory;
62 guint pending_add : 1;
63 guint pending_remove : 1;
65 Accessibility_ControllerEventMask mod_mask;
66 CORBA_unsigned_long key_val; /* KeyCode */
67 } DEControllerGrabMask;
71 SpiDeviceTypeCategory type;
72 } DEControllerListener;
75 DEControllerListener listener;
77 Accessibility_KeySet *keys;
78 Accessibility_ControllerEventMask mask;
79 Accessibility_KeyEventTypeSeq *typeseq;
80 Accessibility_EventListenerMode *mode;
81 } DEControllerKeyListener;
83 static void spi_controller_register_with_devices (SpiDEController *controller);
84 static gboolean spi_controller_update_key_grabs (SpiDEController *controller,
85 Accessibility_DeviceEvent *recv);
86 static void spi_controller_register_device_listener (SpiDEController *controller,
87 DEControllerListener *l,
88 CORBA_Environment *ev);
89 static void spi_device_event_controller_forward_key_event (SpiDEController *controller,
95 keycode_for_keysym (long keysym)
97 return XKeysymToKeycode (GDK_DISPLAY (), (KeySym) keysym);
100 static DEControllerGrabMask *
101 spi_grab_mask_clone (DEControllerGrabMask *grab_mask)
103 DEControllerGrabMask *clone = g_new (DEControllerGrabMask, 1);
105 memcpy (clone, grab_mask, sizeof (DEControllerGrabMask));
107 clone->ref_count = 1;
108 clone->pending_add = TRUE;
109 clone->pending_remove = FALSE;
115 spi_grab_mask_free (DEControllerGrabMask *grab_mask)
121 spi_grab_mask_compare_values (gconstpointer p1, gconstpointer p2)
123 DEControllerGrabMask *l1 = (DEControllerGrabMask *) p1;
124 DEControllerGrabMask *l2 = (DEControllerGrabMask *) p2;
132 return ((l1->mod_mask != l2->mod_mask) || (l1->key_val != l2->key_val));
136 static DEControllerKeyListener *
137 spi_dec_key_listener_new (CORBA_Object l,
138 const Accessibility_KeySet *keys,
139 const Accessibility_ControllerEventMask mask,
140 const Accessibility_KeyEventTypeSeq *typeseq,
141 const Accessibility_EventListenerMode *mode,
142 CORBA_Environment *ev)
144 DEControllerKeyListener *key_listener = g_new0 (DEControllerKeyListener, 1);
145 key_listener->listener.object = bonobo_object_dup_ref (l, ev);
146 key_listener->listener.type = SPI_DEVICE_TYPE_KBD;
147 key_listener->keys = ORBit_copy_value (keys, TC_Accessibility_KeySet);
148 key_listener->mask = mask;
149 key_listener->typeseq = ORBit_copy_value (typeseq, TC_Accessibility_KeyEventTypeSeq);
151 key_listener->mode = ORBit_copy_value (mode, TC_Accessibility_EventListenerMode);
153 key_listener->mode = NULL;
156 g_print ("new listener, with mask %x, is_global %d, keys %p (%d)\n",
157 (unsigned int) key_listener->mask,
158 (int) (mode ? mode->global : 0),
159 (void *) key_listener->keys,
160 (int) (key_listener->keys ? key_listener->keys->_length : 0));
167 spi_dec_key_listener_free (DEControllerKeyListener *key_listener,
168 CORBA_Environment *ev)
170 bonobo_object_release_unref (key_listener->listener.object, ev);
171 CORBA_free (key_listener->typeseq);
172 CORBA_free (key_listener->keys);
173 g_free (key_listener);
177 _register_keygrab (SpiDEController *controller,
178 DEControllerGrabMask *grab_mask)
182 l = g_list_find_custom (controller->keygrabs_list, grab_mask,
183 spi_grab_mask_compare_values);
186 DEControllerGrabMask *cur_mask = l->data;
188 cur_mask->ref_count++;
189 if (cur_mask->pending_remove)
191 cur_mask->pending_remove = FALSE;
196 controller->keygrabs_list =
197 g_list_prepend (controller->keygrabs_list,
198 spi_grab_mask_clone (grab_mask));
203 _deregister_keygrab (SpiDEController *controller,
204 DEControllerGrabMask *grab_mask)
208 l = g_list_find_custom (controller->keygrabs_list, grab_mask,
209 spi_grab_mask_compare_values);
213 DEControllerGrabMask *cur_mask = l->data;
215 cur_mask->ref_count--;
216 cur_mask->pending_remove = TRUE;
220 g_warning ("De-registering non-existant grab");
225 handle_keygrab (SpiDEController *controller,
226 DEControllerKeyListener *key_listener,
227 void (*process_cb) (SpiDEController *controller,
228 DEControllerGrabMask *grab_mask))
230 DEControllerGrabMask grab_mask = { 0 };
232 grab_mask.mod_mask = key_listener->mask;
233 if (key_listener->keys->_length == 0) /* special case means AnyKey/AllKeys */
235 grab_mask.key_val = AnyKey;
236 process_cb (controller, &grab_mask);
242 for (i = 0; i < key_listener->keys->_length; ++i)
244 long int key_val = key_listener->keys->_buffer[i];
245 /* X Grabs require keycodes, not keysyms */
248 key_val = XKeysymToKeycode (GDK_DISPLAY (), (KeySym) key_val);
250 grab_mask.key_val = key_val;
252 process_cb (controller, &grab_mask);
258 spi_controller_register_global_keygrabs (SpiDEController *controller,
259 DEControllerKeyListener *key_listener)
261 handle_keygrab (controller, key_listener, _register_keygrab);
262 spi_controller_update_key_grabs (controller, NULL);
266 spi_controller_deregister_global_keygrabs (SpiDEController *controller,
267 DEControllerKeyListener *key_listener)
269 handle_keygrab (controller, key_listener, _deregister_keygrab);
270 spi_controller_update_key_grabs (controller, NULL);
274 spi_controller_register_device_listener (SpiDEController *controller,
275 DEControllerListener *listener,
276 CORBA_Environment *ev)
278 DEControllerKeyListener *key_listener;
280 switch (listener->type) {
281 case SPI_DEVICE_TYPE_KBD:
282 key_listener = (DEControllerKeyListener *) listener;
284 controller->key_listeners = g_list_prepend (controller->key_listeners,
286 if (key_listener->mode->global)
288 spi_controller_register_global_keygrabs (controller, key_listener);
296 static GdkFilterReturn
297 global_filter_fn (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
299 XEvent *xevent = gdk_xevent;
300 SpiDEController *controller;
302 if (xevent->type != KeyPress && xevent->type != KeyRelease)
304 return GDK_FILTER_CONTINUE;
307 controller = SPI_DEVICE_EVENT_CONTROLLER (data);
309 spi_device_event_controller_forward_key_event (controller, xevent);
311 /* FIXME: is this right ? */
312 return GDK_FILTER_CONTINUE;
316 _spi_controller_device_error_handler (Display *display, XErrorEvent *error)
318 if (error->error_code == BadAccess)
320 g_message ("Could not complete key grab: grab already in use.\n");
324 (*x_default_error_handler) (display, error);
329 spi_controller_register_with_devices (SpiDEController *controller)
331 /* calls to device-specific implementations and routines go here */
332 /* register with: keyboard hardware code handler */
333 /* register with: (translated) keystroke handler */
335 gdk_window_add_filter (NULL, global_filter_fn, controller);
337 gdk_window_set_events (gdk_get_default_root_window (),
338 GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
340 x_default_error_handler = XSetErrorHandler (_spi_controller_device_error_handler);
342 XSelectInput (GDK_DISPLAY (),
343 DefaultRootWindow (GDK_DISPLAY ()),
344 KeyPressMask | KeyReleaseMask);
348 spi_key_set_contains_key (Accessibility_KeySet *key_set,
349 const Accessibility_DeviceEvent *key_event)
356 g_print ("null key set!");
360 len = key_set->_length;
362 if (len == 0) /* special case, means "all keys/any key" */
364 g_print ("anykey\n");
368 for (i = 0; i < len; ++i)
370 #ifdef SPI_KEYEVENT_DEBUG
371 g_print ("key_set[%d] = %d; key_event %d, code %d\n",
372 i, (int) key_set->_buffer[i],
373 (int) key_event->id, (int) key_event->hw_code);
375 if (key_set->_buffer[i] == (CORBA_long) key_event->id)
379 if (key_set->_buffer[i] == (CORBA_long) -key_event->hw_code)
389 spi_key_eventtype_seq_contains_event (Accessibility_KeyEventTypeSeq *type_seq,
390 const Accessibility_DeviceEvent *key_event)
398 g_print ("null type seq!");
402 len = type_seq->_length;
404 if (len == 0) /* special case, means "all events/any event" */
409 for (i = 0; i < len; ++i)
412 g_print ("type_seq[%d] = %d; key event type = %d\n", i,
413 (int) type_seq->_buffer[i], (int) key_event->type);
415 if (type_seq->_buffer[i] == (CORBA_long) key_event->type)
425 spi_key_event_matches_listener (const Accessibility_DeviceEvent *key_event,
426 DEControllerKeyListener *listener,
427 CORBA_boolean is_system_global)
429 if ((key_event->modifiers == (CORBA_unsigned_short) (listener->mask & 0xFFFF)) &&
430 spi_key_set_contains_key (listener->keys, key_event) &&
431 spi_key_eventtype_seq_contains_event (listener->typeseq, key_event) &&
432 (is_system_global == listener->mode->global))
443 spi_notify_keylisteners (GList **key_listeners,
444 const Accessibility_DeviceEvent *key_event,
445 CORBA_boolean is_system_global,
446 CORBA_Environment *ev)
449 GSList *notify = NULL, *l2;
450 gboolean is_consumed;
457 for (l = *key_listeners; l; l = l->next)
459 DEControllerKeyListener *key_listener = l->data;
461 if (spi_key_event_matches_listener (key_event, key_listener, is_system_global))
463 Accessibility_DeviceEventListener ls = key_listener->listener.object;
465 if (ls != CORBA_OBJECT_NIL)
467 notify = g_slist_prepend (notify, CORBA_Object_duplicate (ls, ev));
472 #ifdef SPI_KEYEVENT_DEBUG
475 g_print ("no match for listener %d\n", i);
480 for (l2 = notify; l2 && !is_consumed; l2 = l2->next)
482 Accessibility_DeviceEventListener ls = l2->data;
484 is_consumed = Accessibility_DeviceEventListener_notifyEvent (ls, key_event, ev);
489 CORBA_exception_free (ev);
492 CORBA_Object_release (ls, ev);
495 for (; l2; l2 = l2->next)
497 CORBA_Object_release (l2->data, ev);
500 g_slist_free (notify);
505 static Accessibility_DeviceEvent
506 spi_keystroke_from_x_key_event (XKeyEvent *x_key_event)
508 Accessibility_DeviceEvent key_event;
510 const int cbuf_bytes = 20;
511 char cbuf [cbuf_bytes];
513 keysym = XLookupKeysym (x_key_event, 0);
514 key_event.id = (CORBA_long)(keysym);
515 key_event.hw_code = (CORBA_short) x_key_event->keycode;
516 if (((XEvent *) x_key_event)->type == KeyPress)
518 key_event.type = Accessibility_KEY_PRESSED;
522 key_event.type = Accessibility_KEY_RELEASED;
524 key_event.modifiers = (CORBA_unsigned_short)(x_key_event->state);
525 key_event.is_text = CORBA_FALSE;
529 key_event.event_string = CORBA_string_dup ("space");
532 key_event.event_string = CORBA_string_dup ("Tab");
535 key_event.event_string = CORBA_string_dup ("Backspace");
538 key_event.event_string = CORBA_string_dup ("Return");
541 if (XLookupString (x_key_event, cbuf, cbuf_bytes, &keysym, NULL) > 0)
543 key_event.event_string = CORBA_string_dup (cbuf);
544 if (isgraph (keysym))
546 key_event.is_text = CORBA_TRUE; /* FIXME: incorrect for some composed chars? */
551 key_event.event_string = CORBA_string_dup ("");
555 key_event.timestamp = (CORBA_unsigned_long) x_key_event->time;
556 #ifdef SPI_KEYEVENT_DEBUG
558 "Key %lu pressed (%c), modifiers %d\n",
559 (unsigned long) keysym,
560 keysym ? (int) keysym : '*',
561 (int) x_key_event->state);
564 fprintf (stderr, "%s%c",
565 (x_key_event->state & Mod1Mask)?"Alt-":"",
566 ((x_key_event->state & ShiftMask)^(x_key_event->state & LockMask))?
567 g_ascii_toupper (keysym) : g_ascii_tolower (keysym));
568 #endif /* SPI_DEBUG */
573 spi_controller_update_key_grabs (SpiDEController *controller,
574 Accessibility_DeviceEvent *recv)
578 g_return_val_if_fail (controller != NULL, FALSE);
581 * masks known to work with default RH 7.1+:
582 * 0 (no mods), LockMask, Mod1Mask, Mod2Mask, ShiftMask,
583 * ShiftMask|LockMask, Mod1Mask|LockMask, Mod2Mask|LockMask,
584 * ShiftMask|Mod1Mask, ShiftMask|Mod2Mask, Mod1Mask|Mod2Mask,
585 * ShiftMask|LockMask|Mod1Mask, ShiftMask|LockMask|Mod2Mask,
587 * ControlMask grabs are broken, must be in use already
589 for (l = controller->keygrabs_list; l; l = next)
592 gboolean re_issue_grab;
593 DEControllerGrabMask *grab_mask = l->data;
597 re_issue_grab = recv &&
598 (recv->modifiers & grab_mask->mod_mask) &&
599 (grab_mask->key_val == keycode_for_keysym (recv->id));
602 fprintf (stderr, "mask=%lx %lx (%c%c) %s\n",
603 (long int) grab_mask->key_val,
604 (long int) grab_mask->mod_mask,
605 grab_mask->pending_add ? '+' : '.',
606 grab_mask->pending_remove ? '-' : '.',
607 re_issue_grab ? "re-issue": "");
612 if (grab_mask->pending_add && grab_mask->pending_remove)
616 else if (grab_mask->pending_remove)
619 fprintf (stderr, "ungrabbing, mask=%x\n", grab_mask->mod_mask);
621 XUngrabKey (GDK_DISPLAY (),
624 gdk_x11_get_default_root_xwindow ());
628 else if (grab_mask->pending_add || re_issue_grab)
632 fprintf (stderr, "grab with mask %x\n", grab_mask->mod_mask);
634 XGrabKey (GDK_DISPLAY (),
637 gdk_x11_get_default_root_xwindow (),
643 grab_mask->pending_add = FALSE;
644 grab_mask->pending_remove = FALSE;
648 g_assert (grab_mask->ref_count <= 0);
650 controller->keygrabs_list = g_list_delete_link (
651 controller->keygrabs_list, l);
653 spi_grab_mask_free (grab_mask);
656 /* TODO: check calls for errors and return FALSE if error occurs */
663 * Implemented GObject::finalize
666 spi_device_event_controller_object_finalize (GObject *object)
668 SpiDEController *controller;
670 controller = SPI_DEVICE_EVENT_CONTROLLER (object);
673 fprintf(stderr, "spi_device_event_controller_object_finalize called\n");
675 /* disconnect any special listeners, get rid of outstanding keygrabs */
676 XUngrabKey (GDK_DISPLAY (), AnyKey, AnyModifier, DefaultRootWindow (GDK_DISPLAY ()));
678 spi_device_event_controller_parent_class->finalize (object);
682 * CORBA Accessibility::DEController::registerKeystrokeListener
683 * method implementation
686 impl_register_keystroke_listener (PortableServer_Servant servant,
687 const Accessibility_DeviceEventListener l,
688 const Accessibility_KeySet *keys,
689 const Accessibility_ControllerEventMask mask,
690 const Accessibility_KeyEventTypeSeq *type,
691 const Accessibility_EventListenerMode *mode,
692 CORBA_Environment *ev)
694 SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
695 bonobo_object_from_servant (servant));
696 DEControllerKeyListener *dec_listener;
698 fprintf (stderr, "registering keystroke listener %p with maskVal %lu\n",
699 (void *) l, (unsigned long) mask);
701 dec_listener = spi_dec_key_listener_new (l, keys, mask, type, mode, ev);
702 spi_controller_register_device_listener (
703 controller, (DEControllerListener *) dec_listener, ev);
708 CORBA_Environment *ev;
709 DEControllerKeyListener *key_listener;
710 } RemoveKeyListenerClosure;
712 static SpiReEntrantContinue
713 remove_key_listener_cb (GList * const *list,
716 DEControllerKeyListener *key_listener = (*list)->data;
717 RemoveKeyListenerClosure *ctx = user_data;
719 if (CORBA_Object_is_equivalent (ctx->key_listener->listener.object,
720 key_listener->listener.object, ctx->ev))
722 spi_re_entrant_list_delete_link (list);
723 spi_dec_key_listener_free (key_listener, ctx->ev);
726 return SPI_RE_ENTRANT_CONTINUE;
729 static SpiReEntrantContinue
730 copy_key_listener_cb (GList * const *list,
733 DEControllerKeyListener *key_listener = (*list)->data;
734 RemoveKeyListenerClosure *ctx = user_data;
736 if (CORBA_Object_is_equivalent (ctx->key_listener->listener.object,
737 key_listener->listener.object, ctx->ev))
739 /* TODO: FIXME aggregate keys in case the listener is registered twice */
740 CORBA_free (ctx->key_listener->keys);
741 ctx->key_listener->keys = ORBit_copy_value (key_listener->keys, TC_Accessibility_KeySet);
744 return SPI_RE_ENTRANT_CONTINUE;
748 * CORBA Accessibility::DEController::deregisterKeystrokeListener
749 * method implementation
752 impl_deregister_keystroke_listener (PortableServer_Servant servant,
753 const Accessibility_DeviceEventListener l,
754 const Accessibility_KeySet *keys,
755 const Accessibility_ControllerEventMask mask,
756 const Accessibility_KeyEventTypeSeq *type,
757 CORBA_Environment *ev)
759 DEControllerKeyListener *key_listener;
760 RemoveKeyListenerClosure ctx;
761 SpiDEController *controller;
763 controller = SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
765 key_listener = spi_dec_key_listener_new (l, keys, mask, type, NULL, ev);
767 #ifdef SPI_DEREGISTER_DEBUG
768 fprintf (stderr, "deregistering keystroke listener %p with maskVal %lu\n",
769 (void *) l, (unsigned long) mask->value);
773 ctx.key_listener = key_listener;
775 /* special case, copy keyset from existing controller list entry */
776 if (keys->_length == 0)
778 spi_re_entrant_list_foreach (&controller->key_listeners,
779 copy_key_listener_cb, &ctx);
782 spi_controller_deregister_global_keygrabs (controller, key_listener);
784 spi_re_entrant_list_foreach (&controller->key_listeners,
785 remove_key_listener_cb, &ctx);
787 spi_dec_key_listener_free (key_listener, ev);
791 * CORBA Accessibility::DEController::registerKeystrokeListener
792 * method implementation
795 impl_generate_keyboard_event (PortableServer_Servant servant,
796 const CORBA_long keycode,
797 const CORBA_char *keystring,
798 const Accessibility_KeySynthType synth_type,
799 CORBA_Environment *ev)
804 fprintf (stderr, "synthesizing keystroke %ld, type %d\n",
805 (long) keycode, (int) synth_type);
807 /* TODO: hide/wrap/remove X dependency */
809 /* TODO: be accessX-savvy so that keyrelease occurs after sufficient timeout */
812 * TODO: when initializing, query for XTest extension before using,
813 * and fall back to XSendEvent() if XTest is not available.
816 /* TODO: implement keystring mode also */
817 gdk_error_trap_push ();
821 case Accessibility_KEY_PRESS:
822 XTestFakeKeyEvent (GDK_DISPLAY (), (unsigned int) keycode, True, CurrentTime);
824 case Accessibility_KEY_PRESSRELEASE:
825 XTestFakeKeyEvent (GDK_DISPLAY (), (unsigned int) keycode, True, CurrentTime);
826 case Accessibility_KEY_RELEASE:
827 XTestFakeKeyEvent (GDK_DISPLAY (), (unsigned int) keycode, False, CurrentTime);
829 case Accessibility_KEY_SYM:
830 key_synth_code = keycode_for_keysym (keycode);
831 XTestFakeKeyEvent (GDK_DISPLAY (), (unsigned int) key_synth_code, True, CurrentTime);
832 XTestFakeKeyEvent (GDK_DISPLAY (), (unsigned int) key_synth_code, False, CurrentTime);
834 case Accessibility_KEY_STRING:
835 fprintf (stderr, "Not yet implemented\n");
838 if (gdk_error_trap_pop ())
840 g_warning ("Error emitting keystroke");
844 /* Accessibility::DEController::generateMouseEvent */
846 impl_generate_mouse_event (PortableServer_Servant servant,
849 const CORBA_char *eventName,
850 CORBA_Environment *ev)
853 fprintf (stderr, "generating mouse %s event at %ld, %ld\n",
854 eventName, (long int) x, (long int) y);
856 g_warning ("not yet implemented");
859 /* Accessibility::DEController::notifyListenersSync */
861 impl_notify_listeners_sync (PortableServer_Servant servant,
862 const Accessibility_DeviceEvent *event,
863 CORBA_Environment *ev)
865 SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
866 bonobo_object_from_servant (servant));
868 g_print ("notifylistening listeners synchronously: controller %p, event id %d\n",
869 controller, (int) event->id);
871 return spi_notify_keylisteners (&controller->key_listeners, event, CORBA_FALSE, ev) ?
872 CORBA_TRUE : CORBA_FALSE;
875 /* Accessibility::DEController::notifyListenersAsync */
877 impl_notify_listeners_async (PortableServer_Servant servant,
878 const Accessibility_DeviceEvent *event,
879 CORBA_Environment *ev)
881 SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
882 bonobo_object_from_servant (servant));
884 fprintf (stderr, "notifying listeners asynchronously\n");
886 spi_notify_keylisteners (&controller->key_listeners, event, CORBA_FALSE, ev);
890 spi_device_event_controller_class_init (SpiDEControllerClass *klass)
892 GObjectClass * object_class = (GObjectClass *) klass;
893 POA_Accessibility_DeviceEventController__epv *epv = &klass->epv;
895 spi_device_event_controller_parent_class = g_type_class_peek_parent (klass);
897 object_class->finalize = spi_device_event_controller_object_finalize;
899 epv->registerKeystrokeListener = impl_register_keystroke_listener;
900 epv->deregisterKeystrokeListener = impl_deregister_keystroke_listener;
901 epv->generateKeyboardEvent = impl_generate_keyboard_event;
902 epv->generateMouseEvent = impl_generate_mouse_event;
903 epv->notifyListenersSync = impl_notify_listeners_sync;
904 epv->notifyListenersAsync = impl_notify_listeners_async;
908 spi_device_event_controller_init (SpiDEController *device_event_controller)
910 device_event_controller->key_listeners = NULL;
911 device_event_controller->mouse_listeners = NULL;
912 device_event_controller->keygrabs_list = NULL;
915 * TODO: fixme, this module makes the foolish assumptions that
916 * registryd uses the same display as the apps, and that the
917 * DISPLAY environment variable is set.
919 gdk_init (NULL, NULL);
921 spi_controller_register_with_devices (device_event_controller);
925 spi_device_event_controller_forward_key_event (SpiDEController *controller,
928 gboolean is_consumed = FALSE;
929 CORBA_Environment ev;
930 Accessibility_DeviceEvent key_event;
932 g_assert (event->type == KeyPress || event->type == KeyRelease);
934 CORBA_exception_init (&ev);
936 key_event = spi_keystroke_from_x_key_event ((XKeyEvent *) event);
937 /* relay to listeners, and decide whether to consume it or not */
938 is_consumed = spi_notify_keylisteners (
939 &controller->key_listeners, &key_event, CORBA_TRUE, &ev);
941 CORBA_exception_free (&ev);
945 XAllowEvents (GDK_DISPLAY (), AsyncKeyboard, CurrentTime);
949 XAllowEvents (GDK_DISPLAY (), ReplayKeyboard, CurrentTime);
952 spi_controller_update_key_grabs (controller, &key_event);
956 spi_device_event_controller_new (SpiRegistry *registry)
958 SpiDEController *retval = g_object_new (
959 SPI_DEVICE_EVENT_CONTROLLER_TYPE, NULL);
961 retval->registry = SPI_REGISTRY (bonobo_object_ref (
962 BONOBO_OBJECT (registry)));
967 BONOBO_TYPE_FUNC_FULL (SpiDEController,
968 Accessibility_DeviceEventController,
970 spi_device_event_controller);