2001-12-10 Michael Meeks <michael@ximian.com>
[platform/core/uifw/at-spi2-atk.git] / registryd / deviceeventcontroller.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2001 Sun Microsystems Inc.
6  *
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.
11  *
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.
16  *
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.
21  */
22
23 /* deviceeventcontroler.c: implement the DeviceEventController interface */
24
25 #include <config.h>
26
27 #ifdef SPI_DEBUG
28 #  include <stdio.h>
29 #endif
30
31 #include <X11/Xlib.h>
32 #include <X11/extensions/XTest.h>
33 #include <gdk/gdkx.h> /* TODO: hide dependency (wrap in single porting file) */
34 #include <gdk/gdkwindow.h>
35
36 #include <libspi/deviceeventcontroller.h>
37
38 /* Our parent Gtk object type */
39 #define PARENT_TYPE BONOBO_TYPE_OBJECT
40
41 /* A pointer to our parent object class */
42 static GObjectClass *spi_device_event_controller_parent_class;
43
44 static gboolean kbd_registered = FALSE;
45
46 static Display *display;
47
48 static Window root_window;
49
50 typedef enum {
51         SPI_DEVICE_TYPE_KBD,
52         SPI_DEVICE_TYPE_MOUSE,
53         SPI_DEVICE_TYPE_LAST_DEFINED
54 } SpiDeviceTypeCategory;
55
56 struct _DEControllerListener {
57         CORBA_Object          object;
58         SpiDeviceTypeCategory type;
59 };
60
61 typedef struct _DEControllerListener DEControllerListener;
62
63 struct _DEControllerKeyListener {
64         DEControllerListener listener;
65         Accessibility_KeySet *keys;
66         Accessibility_ControllerEventMask *mask;
67         Accessibility_KeyEventTypeSeq *typeseq;
68         gboolean is_system_global;      
69 };
70
71 typedef struct _DEControllerKeyListener DEControllerKeyListener;
72
73 static gboolean _controller_register_with_devices (SpiDeviceEventController *controller);
74 static gboolean _controller_grab_keyboard (SpiDeviceEventController *controller);
75
76 static void controller_register_device_listener (SpiDeviceEventController *controller,
77                                                  DEControllerListener *l,
78                                                  CORBA_Environment *ev);
79
80 /*
81  * Private methods
82  */
83
84 static gint
85 _compare_corba_objects (gconstpointer p1, gconstpointer p2)
86 {
87   CORBA_Environment ev;
88   gint retval;
89   retval = !CORBA_Object_is_equivalent ((CORBA_Object) p1, (CORBA_Object) p2, &ev);
90
91 #ifdef SPI_DEBUG
92   fprintf (stderr, "comparing %p to %p; result %d\n",
93            p1, p2,
94            retval);
95 #endif
96   return retval;  
97 }
98
99 static gint
100 _compare_listeners (gconstpointer p1, gconstpointer p2)
101 {
102   DEControllerListener *l1 = (DEControllerListener *) p1;       
103   DEControllerListener *l2 = (DEControllerListener *) p2;       
104   return _compare_corba_objects (l1->object, l2->object);
105 }
106
107 static gint
108 _eventmask_compare_value (gconstpointer p1, gconstpointer p2)
109 {
110     long d;
111     if (!p1 || !p2)
112         return (gint) (p1?1:(p2?-1:0));
113     else
114         d = ((long)((Accessibility_ControllerEventMask*)p2)->value) -
115                 ((long)((Accessibility_ControllerEventMask*)p1)->value);
116     return (gint) d;
117 }
118
119 static DEControllerKeyListener *
120 dec_key_listener_new (CORBA_Object l,
121                       const Accessibility_KeySet *keys,
122                       const Accessibility_ControllerEventMask *mask,
123                       const Accessibility_KeyEventTypeSeq *typeseq,
124                       const CORBA_boolean is_system_global,
125                       CORBA_Environment *ev)
126 {
127   DEControllerKeyListener *key_listener = g_new0 (DEControllerKeyListener, 1);
128   key_listener->listener.object = bonobo_object_dup_ref (l, ev);
129   key_listener->listener.type = SPI_DEVICE_TYPE_KBD;
130   key_listener->keys = ORBit_copy_value (keys, TC_Accessibility_KeySet);
131   key_listener->mask = ORBit_copy_value (mask, TC_Accessibility_ControllerEventMask);
132   key_listener->typeseq = ORBit_copy_value (typeseq, TC_Accessibility_KeyEventTypeSeq);
133   key_listener->is_system_global = is_system_global;
134
135 #ifdef SPI_DEBUG
136   g_print ("new listener, with mask %x, is_global %d, keys %p\n",
137            (unsigned int) key_listener->mask->value,
138            (int) key_listener->is_system_global,
139            (void *) key_listener->keys);
140 #endif
141   return key_listener;  
142 }
143
144 static void
145 dec_key_listener_free (DEControllerKeyListener *key_listener, CORBA_Environment *ev)
146 {
147   bonobo_object_release_unref (key_listener->listener.object, ev);
148   CORBA_free (key_listener->typeseq);
149   CORBA_free (key_listener->mask);
150   CORBA_free (key_listener->keys);
151   g_free (key_listener);
152 }
153
154 static void
155 controller_register_device_listener (SpiDeviceEventController *controller,
156                                      DEControllerListener *listener,
157                                      CORBA_Environment *ev)
158 {
159   Accessibility_ControllerEventMask *mask_ptr = NULL;
160   DEControllerKeyListener *key_listener;
161   
162   switch (listener->type) {
163   case SPI_DEVICE_TYPE_KBD:
164       key_listener = (DEControllerKeyListener *) listener;        
165       controller->key_listeners = g_list_prepend (controller->key_listeners, key_listener);
166       if (key_listener->is_system_global)
167         {
168           mask_ptr = (Accessibility_ControllerEventMask *)
169               g_list_find_custom (controller->keymask_list, (gpointer) key_listener->mask,
170                                   _eventmask_compare_value);
171           if (mask_ptr)
172               ++(mask_ptr->refcount);
173           else
174            {
175               if (key_listener->mask->refcount != (CORBA_unsigned_short) 1)
176                       fprintf (stderr, "mask initial refcount is not 1!\n");
177               if (key_listener->mask->value > (CORBA_unsigned_long) 2048)
178                       fprintf (stderr, "mask value looks invalid (%lu)\n",
179                                (unsigned long) key_listener->mask->value);
180               else
181                       fprintf (stderr, "appending mask with val=%lu\n",
182                                (unsigned long) key_listener->mask->value);
183               mask_ptr = Accessibility_ControllerEventMask__alloc();
184               mask_ptr->value = key_listener->mask->value;
185               mask_ptr->refcount = (CORBA_unsigned_short) 1;
186               controller->keymask_list = g_list_append (controller->keymask_list,
187                                                         (gpointer) mask_ptr);
188           }
189         }
190       break;
191   case SPI_DEVICE_TYPE_MOUSE:
192 /*    controller->mouse_listeners = g_list_append (controller->mouse_listeners,
193                                                    CORBA_Object_duplicate (l, ev));*/
194
195 /* possibly this interface should NOT be used for mouse events ? */
196       break;
197   }
198 }
199
200 static void
201 controller_deregister_device_listener (SpiDeviceEventController *controller,
202                                        DEControllerListener *listener,
203                                        CORBA_Environment *ev)
204 {
205   Accessibility_ControllerEventMask *mask_ptr;
206   DEControllerKeyListener *key_listener;
207   DEControllerListener *dec_listener;
208   GList *list_ptr;
209   switch (listener->type) {
210   case SPI_DEVICE_TYPE_KBD:
211       key_listener = (DEControllerKeyListener *) listener;
212       /* first, deref matching event mask, if any */
213       list_ptr = (GList *)
214                   g_list_find_custom (controller->keymask_list, (gpointer) key_listener->mask,
215                                      _eventmask_compare_value);
216       if (list_ptr)
217         {
218           mask_ptr = (Accessibility_ControllerEventMask *) list_ptr->data;
219           if (mask_ptr)
220               --mask_ptr->refcount;
221           if (!mask_ptr->refcount)
222             {
223               controller->keymask_list =
224                       g_list_remove_link (controller->keymask_list, list_ptr);
225               ;  /* TODO: release any key grabs that are in place for this key mask */
226             }
227         }
228       /* now, remove this listener from the keylistener list */
229       list_ptr = g_list_find_custom (controller->key_listeners, listener, _compare_listeners);
230       if (list_ptr)
231         {
232           dec_listener = (DEControllerListener *) list_ptr->data;
233 #ifdef SPI_DEBUG          
234           g_print ("removing keylistener %p\n", dec_listener->object);
235 #endif
236           controller->key_listeners = g_list_remove_link (controller->key_listeners,
237                                                           list_ptr);
238           dec_key_listener_free ((DEControllerKeyListener *) dec_listener, ev);
239         }
240       break;
241   case SPI_DEVICE_TYPE_MOUSE:
242 /*    controller->mouse_listeners = g_list_append (controller->mouse_listeners,
243                                                    CORBA_Object_duplicate (l, ev));*/
244
245 /* possibly this interface should NOT be used for mouse events ? */
246       break;
247   }
248 }
249
250 static gboolean
251 _controller_register_with_devices (SpiDeviceEventController *controller)
252 {
253   gboolean retval = FALSE;
254
255   /* calls to device-specific implementations and routines go here */
256   /* register with: keyboard hardware code handler */
257   /* register with: (translated) keystroke handler */
258 #ifdef SPI_DEBUG
259   fprintf (stderr, "About to request events on window %ld of display %p\n",
260            (unsigned long) GDK_ROOT_WINDOW(), GDK_DISPLAY());
261 #endif
262   /* We must open a new connection to the server to avoid clashing with the GDK event loop */
263   display = XOpenDisplay (g_getenv ("DISPLAY"));
264   root_window = DefaultRootWindow (display);            
265   XSelectInput (display,
266                 root_window,
267                 KeyPressMask | KeyReleaseMask);
268   /* register with: mouse hardware device handler? */
269   /* register with: mouse event handler */
270   return retval;
271 }
272
273 static gboolean
274 key_set_contains_key (Accessibility_KeySet *key_set, Accessibility_KeyStroke *key_event)
275 {
276   gint i;
277   gint len;
278
279   /* g_assert (key_set); */
280   if (!key_set) { g_print ("null key set!"); return TRUE; }
281
282   len = key_set->_length;
283   
284   if (len == 0) /* special case, means "all keys/any key" */
285     {
286       return TRUE;
287     }
288
289   for (i=0; i<len; ++i)
290     {
291 #ifdef SPI_KEYEVENT_DEBUG           
292       g_print ("key_set[%d] = %d; key_event %d, code %d\n",
293                 i,
294                (int) key_set->_buffer[i],
295                (int) key_event->keyID,
296                (int) key_event->keycode); 
297 #endif
298       if (key_set->_buffer[i] == (CORBA_long) key_event->keyID) return TRUE;
299       if (key_set->_buffer[i] == (CORBA_long) -key_event->keycode) return TRUE;
300     }
301   
302   return FALSE;
303 }
304
305 static gboolean
306 key_eventtype_seq_contains_event (Accessibility_KeyEventTypeSeq *type_seq,
307                                   Accessibility_KeyStroke *key_event)
308 {
309   gint i;
310   gint len;
311
312   /* g_assert (type_seq); */
313   if (!type_seq) { g_print ("null type seq!"); return TRUE; }
314
315   len = type_seq->_length;
316   
317   if (len == 0) /* special case, means "all events/any event" */
318     {
319       return TRUE;
320     }
321
322   for (i=0; i<len; ++i)
323     {
324 /*      g_print ("type_seq[%d] = %d\n", i, (int) type_seq->_buffer[i]); */
325       if (type_seq->_buffer[i] == (CORBA_long) key_event->type) return TRUE;        
326     }
327   
328   return TRUE;
329 }
330
331 static gboolean
332 key_event_matches_listener (Accessibility_KeyStroke *key_event,
333                             DEControllerKeyListener *listener,
334                             CORBA_boolean is_system_global)
335 {
336   if ((key_event->modifiers == (CORBA_unsigned_short) (listener->mask->value & 0xFFFF)) &&
337        key_set_contains_key (listener->keys, key_event) &&
338        key_eventtype_seq_contains_event (listener->typeseq, key_event) && 
339       (is_system_global == listener->is_system_global))
340     {
341       return TRUE;
342     }
343   else
344     return FALSE;
345 }
346
347 static gboolean
348 notify_keylisteners (GList *key_listeners,
349                      Accessibility_KeyStroke *key_event,
350                      CORBA_boolean is_system_global,
351                      CORBA_Environment *ev)
352 {
353   int i, n_listeners = g_list_length (key_listeners);
354   gboolean is_consumed = FALSE;
355
356   for (i=0; i<n_listeners && !is_consumed; ++i)
357     {
358       Accessibility_KeystrokeListener ls;
359       DEControllerKeyListener *key_listener = (DEControllerKeyListener *)
360             g_list_nth_data (key_listeners, i);
361       ls = (Accessibility_KeystrokeListener) key_listener->listener.object;
362       if (key_event_matches_listener (key_event, key_listener, is_system_global))
363         {
364           if (!CORBA_Object_is_nil(ls, ev))
365             {
366               is_consumed = Accessibility_KeystrokeListener_keyEvent (ls, key_event, ev);
367             }           
368         }
369       else
370         {
371 #ifdef SPI_KEYEVENT_DEBUG
372               g_print ("no match for listener %d\n", i);
373 #endif
374               ;
375         }
376     }
377   return is_consumed;
378 }
379
380 static gboolean
381 _check_key_event (SpiDeviceEventController *controller)
382 {
383         static gboolean initialized = FALSE;
384         XEvent *x_event = g_new0 (XEvent, 1);
385         XKeyEvent *x_key_event;
386         KeySym keysym;
387         gboolean is_consumed = FALSE;
388         Accessibility_KeyStroke key_event;
389         static CORBA_Environment ev;
390
391         if (!initialized)
392         {
393           initialized = TRUE;
394           CORBA_exception_init (&ev);
395         }
396
397         while (XPending(display))
398           {
399             XNextEvent (display, x_event);
400             if (XFilterEvent (x_event, None)) continue;   
401             if (x_event->type == KeyPress)
402               {
403                 x_key_event = (XKeyEvent *)x_event;
404                 keysym = XLookupKeysym (x_key_event, 0);
405                 key_event.keyID = (CORBA_long)(keysym);
406                 key_event.keycode = (CORBA_short) x_key_event->keycode;
407                 key_event.type = Accessibility_KEY_PRESSED;
408                 key_event.modifiers = (CORBA_unsigned_short)(x_key_event->state);
409 #ifdef SPI_KEYEVENT_DEBUG
410             fprintf (stderr,
411                      "Key %lu pressed (%c), modifiers %d\n",
412                      (unsigned long) keysym,
413                      keysym ? (int) keysym : '*',
414                      (int) x_key_event->state);
415 #endif
416 #ifdef SPI_DEBUG
417             fprintf (stderr, "%s%c",
418                      (x_key_event->state & Mod1Mask)?"Alt-":"",
419                      ((x_key_event->state & ShiftMask)^(x_key_event->state & LockMask))?
420                      g_ascii_toupper (keysym) : g_ascii_tolower (keysym));
421 #endif /* SPI_DEBUG */
422               }
423             else
424             {
425 #ifdef SPI_KEYEVENT_DEBUG
426                     fprintf (stderr, "other event, type %d\n", (int) x_event->type);
427 #endif
428             }
429             /* relay to listeners, and decide whether to consume it or not */
430             is_consumed = notify_keylisteners (controller->key_listeners, &key_event, CORBA_TRUE, &ev);
431
432             if (is_consumed)
433             {
434               XAllowEvents (display, AsyncKeyboard, CurrentTime);
435             }
436             else
437             {
438               XAllowEvents (display, ReplayKeyboard, CurrentTime);
439             }
440           }
441         XUngrabKey (display, AnyKey, AnyModifier, root_window);
442         return _controller_grab_keyboard (controller);
443 }
444
445 static gboolean
446 _controller_grab_keyboard (SpiDeviceEventController *controller)
447 {
448         GList *maskList = controller->keymask_list;
449         int i;
450         int last_mask;
451         last_mask = g_list_length (maskList);
452
453 /*
454  * masks known to work with default RH 7.1: 
455  * 0 (no mods), LockMask, Mod1Mask, Mod2Mask, ShiftMask,
456  * ShiftMask|LockMask, Mod1Mask|LockMask, Mod2Mask|LockMask,
457  * ShiftMask|Mod1Mask, ShiftMask|Mod2Mask, Mod1Mask|Mod2Mask,
458  * ShiftMask|LockMask|Mod1Mask, ShiftMask|LockMask|Mod2Mask,
459  *
460  * ControlMask grabs are broken, must be in use already
461  */
462         
463         for (i=0; i < last_mask; ++i)
464         {
465                 Accessibility_ControllerEventMask *mask
466                         = (Accessibility_ControllerEventMask *)g_list_nth_data (maskList, i);
467                 unsigned long maskVal = 0xFFFFFFFF;
468                 if (mask) maskVal = (unsigned long) mask->value;
469 #ifdef SPI_KEYEVENT_DEBUG
470                 fprintf (stderr, "mask=%lx\n", maskVal);
471 #endif
472                 if (!(maskVal & ControlMask))
473                 {
474                         XGrabKey (display,
475                                   AnyKey,
476                                   maskVal,
477                                   root_window,
478                                   True,
479                                   GrabModeAsync,
480                                   GrabModeAsync);
481                         /* TODO: check call for errors and return FALSE if error occurs */
482                 } else {
483                         return FALSE; /* can't do control key yet */
484                 }
485         }
486         return TRUE;
487 }
488
489 /*
490  * Implemented GObject::finalize
491  */
492 static void
493 spi_device_event_controller_object_finalize (GObject *object)
494 {
495
496 #ifdef SPI_DEBUG
497         fprintf(stderr, "spi_device_event_controller_object_finalize called\n");
498 #endif
499         /* disconnect any special listeners, get rid of outstanding keygrabs */
500         
501         spi_device_event_controller_parent_class->finalize (object);
502 }
503
504 /*
505  * CORBA Accessibility::DeviceEventController::registerKeystrokeListener
506  *     method implementation
507  */
508 static void
509 impl_register_keystroke_listener (PortableServer_Servant     servant,
510                                   const Accessibility_KeystrokeListener l,
511                                   const Accessibility_KeySet *keys,
512                                   const Accessibility_ControllerEventMask *mask,
513                                   const Accessibility_KeyEventTypeSeq *type,
514                                   const CORBA_boolean is_system_global,
515                                   CORBA_Environment         *ev)
516 {
517         SpiDeviceEventController *controller = SPI_DEVICE_EVENT_CONTROLLER (
518                 bonobo_object_from_servant (servant));
519         DEControllerKeyListener *dec_listener;
520 #ifdef SPI_DEBUG
521         fprintf (stderr, "registering keystroke listener %p with maskVal %lu\n",
522                  (void *) l, (unsigned long) mask->value);
523 #endif
524         dec_listener = dec_key_listener_new (l, keys, mask, type, is_system_global, ev);
525         controller_register_device_listener (controller, (DEControllerListener *) dec_listener, ev);
526 }
527
528 /*
529  * CORBA Accessibility::DeviceEventController::deregisterKeystrokeListener
530  *     method implementation
531  */
532 static void
533 impl_deregister_keystroke_listener (PortableServer_Servant     servant,
534                                     const Accessibility_KeystrokeListener l,
535                                     const Accessibility_KeySet *keys,
536                                     const Accessibility_ControllerEventMask *mask,
537                                     const Accessibility_KeyEventTypeSeq *type,
538                                     const CORBA_boolean is_system_global,
539                                     CORBA_Environment         *ev)
540 {
541         SpiDeviceEventController *controller = SPI_DEVICE_EVENT_CONTROLLER (
542                 bonobo_object_from_servant (servant));
543         DEControllerKeyListener *key_listener = dec_key_listener_new (l,
544                                                                       keys,
545                                                                       mask,
546                                                                       type,
547                                                                       is_system_global,
548                                                                       ev);
549 #ifdef SPI_DEREGISTER_DEBUG
550         fprintf (stderr, "deregistering keystroke listener %p with maskVal %lu\n",
551                  (void *) l, (unsigned long) mask->value);
552 #endif
553         controller_deregister_device_listener(controller,
554                                               (DEControllerListener *) key_listener,
555                                               ev);
556         dec_key_listener_free (key_listener, ev);
557 }
558
559 /*
560  * CORBA Accessibility::DeviceEventController::registerMouseListener
561  *     method implementation
562  */
563 /*
564 static void
565 impl_register_mouse_listener (PortableServer_Servant     servant,
566                               const Accessibility_MouseListener *l,
567                               CORBA_Environment         *ev)
568 {
569         SpiDeviceEventController *controller = SPI_DEVICE_EVENT_CONTROLLER (
570                 bonobo_object_from_servant (servant));
571 #ifdef SPI_DEBUG
572         fprintf (stderr, "registering mouse listener %p\n", l);
573 #endif
574         controller_register_device_listener(controller, DEVICE_TYPE_MOUSE, l, keys, mask, ev);
575 }
576 */
577
578 static KeyCode
579 keycode_for_keysym (long keysym)
580 {
581   return XKeysymToKeycode (display, (KeySym) keysym);
582 }
583
584 /*
585  * CORBA Accessibility::DeviceEventController::registerKeystrokeListener
586  *     method implementation
587  */
588 static void
589 impl_generate_key_event (PortableServer_Servant     servant,
590                          const CORBA_long           keycode,
591                          const Accessibility_KeySynthType synth_type,
592                          CORBA_Environment          *ev)
593 {
594         long key_synth_code;
595 #ifdef SPI_DEBUG
596         fprintf (stderr, "synthesizing keystroke %ld\n", (long) keycode);
597 #endif
598         /* TODO: hide/wrap/remove X dependency */
599
600         /* TODO: be accessX-savvy so that keyrelease occurs after sufficient timeout */
601         
602         /*
603          * TODO: when initializing, query for XTest extension before using,
604          * and fall back to XSendEvent() if XTest is not available.
605          */
606         
607         switch (synth_type)
608         {
609         case Accessibility_KEY_PRESS:
610                 XTestFakeKeyEvent (GDK_DISPLAY(), (unsigned int) keycode, True, CurrentTime);
611                 break;
612         case Accessibility_KEY_PRESSRELEASE:
613                 XTestFakeKeyEvent (GDK_DISPLAY(), (unsigned int) keycode, True, CurrentTime);
614         case Accessibility_KEY_RELEASE:
615                 XTestFakeKeyEvent (GDK_DISPLAY(), (unsigned int) keycode, False, CurrentTime);
616                 break;
617         case Accessibility_KEY_SYM:
618                 key_synth_code = keycode_for_keysym (keycode);
619                 XTestFakeKeyEvent (GDK_DISPLAY(), (unsigned int) key_synth_code, True, CurrentTime);
620                 XTestFakeKeyEvent (GDK_DISPLAY(), (unsigned int) key_synth_code, False, CurrentTime);
621                 break;
622         }
623 }
624
625 /* Accessibility::DeviceEventController::generateMouseEvent */
626 static void
627 impl_generate_mouse_event (PortableServer_Servant servant,
628                            const CORBA_long       x,
629                            const CORBA_long       y,
630                            const CORBA_char      *eventName,
631                            CORBA_Environment     *ev)
632 {
633 #ifdef SPI_DEBUG
634   fprintf (stderr, "generating mouse %s event at %ld, %ld\n", eventName, x, y);
635 #endif
636 }
637
638 /* Accessibility::DeviceEventController::notifyListenersSync */
639 static CORBA_boolean
640 impl_notify_listeners_sync(PortableServer_Servant     servant,
641                            const Accessibility_DeviceEvent *event,
642                            CORBA_Environment         *ev)
643 {
644   SpiDeviceEventController *controller = SPI_DEVICE_EVENT_CONTROLLER (
645                                          bonobo_object_from_servant (servant));
646   Accessibility_KeyStroke *key_event = (Accessibility_KeyStroke *) event;       
647 #ifdef SPI_DEBUG
648   g_print ("notifying listeners synchronously: controller %x, event id %d\n",
649            (void *) controller, (int) event->eventID);
650 #endif
651   return (notify_keylisteners (controller->key_listeners, key_event, CORBA_FALSE, ev) ?
652           CORBA_TRUE : CORBA_FALSE); 
653 }
654
655 /* Accessibility::DeviceEventController::notifyListenersAsync */
656 static void
657 impl_notify_listeners_async (PortableServer_Servant     servant,
658                              const Accessibility_DeviceEvent *event,
659                              CORBA_Environment         *ev)
660 {
661   SpiDeviceEventController *controller = SPI_DEVICE_EVENT_CONTROLLER(
662                                          bonobo_object_from_servant (servant));
663   Accessibility_KeyStroke *key_event = (Accessibility_KeyStroke *) event;       
664 #ifdef SPI_DEBUG
665   fprintf (stderr, "notifying listeners asynchronously\n");
666 #endif
667   notify_keylisteners (controller->key_listeners, key_event, CORBA_FALSE, ev); 
668 }
669
670 static void
671 spi_device_event_controller_class_init (SpiDeviceEventControllerClass *klass)
672 {
673         GObjectClass * object_class = (GObjectClass *) klass;
674         POA_Accessibility_DeviceEventController__epv *epv = &klass->epv;
675         spi_device_event_controller_parent_class = g_type_class_peek_parent (klass);
676
677         object_class->finalize = spi_device_event_controller_object_finalize;
678
679         epv->registerKeystrokeListener = impl_register_keystroke_listener;
680         epv->deregisterKeystrokeListener = impl_deregister_keystroke_listener;
681 /*        epv->registerMouseListener = impl_register_mouse_listener; */
682         epv->generateKeyEvent = impl_generate_key_event;
683         epv->generateMouseEvent = impl_generate_mouse_event;
684         epv->notifyListenersSync = impl_notify_listeners_sync;
685         epv->notifyListenersAsync = impl_notify_listeners_async;
686         klass->check_key_event = _check_key_event;
687 }
688
689 static void
690 spi_device_event_controller_init (SpiDeviceEventController *device_event_controller)
691 {
692   device_event_controller->key_listeners = NULL;
693   device_event_controller->mouse_listeners = NULL;
694   device_event_controller->keymask_list = NULL;
695   kbd_registered = _controller_register_with_devices (device_event_controller);
696 }
697
698 gboolean
699 spi_device_event_controller_check_key_event (SpiDeviceEventController *controller)
700 {
701         SpiDeviceEventControllerClass *klass = SPI_DEVICE_EVENT_CONTROLLER_GET_CLASS (controller);
702         if (klass->check_key_event)
703                 return (klass->check_key_event) (controller);
704         return FALSE;
705 }
706
707 SpiDeviceEventController *
708 spi_device_event_controller_new (void *registryp)
709 {
710   BonoboObject *registry = (BonoboObject *) registryp;  
711   SpiDeviceEventController *retval = g_object_new (
712           SPI_DEVICE_EVENT_CONTROLLER_TYPE, NULL);
713   retval->registry = registry;
714   bonobo_object_ref (registry);
715   return retval;
716 }
717
718 BONOBO_TYPE_FUNC_FULL (SpiDeviceEventController,
719                        Accessibility_DeviceEventController,
720                        PARENT_TYPE,
721                        spi_device_event_controller);
722