Added simple scanning to the virtual keyboard demo, to show one way to
[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 = CORBA_Object_duplicate (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 controller_register_device_listener (SpiDeviceEventController *controller,
146                                      DEControllerListener *listener,
147                                      CORBA_Environment *ev)
148 {
149   Accessibility_ControllerEventMask *mask_ptr = NULL;
150   DEControllerKeyListener *key_listener;
151   
152   switch (listener->type) {
153   case SPI_DEVICE_TYPE_KBD:
154       key_listener = (DEControllerKeyListener *) listener;        
155       controller->key_listeners = g_list_append (controller->key_listeners, key_listener);
156       if (key_listener->is_system_global)
157         {
158           mask_ptr = (Accessibility_ControllerEventMask *)
159               g_list_find_custom (controller->keymask_list, (gpointer) key_listener->mask,
160                                   _eventmask_compare_value);
161           if (mask_ptr)
162               ++(mask_ptr->refcount);
163           else
164            {
165               if (key_listener->mask->refcount != (CORBA_unsigned_short) 1)
166                       fprintf (stderr, "mask initial refcount is not 1!\n");
167               if (key_listener->mask->value > (CORBA_unsigned_long) 2048)
168                       fprintf (stderr, "mask value looks invalid (%lu)\n",
169                                (unsigned long) key_listener->mask->value);
170               else
171                       fprintf (stderr, "appending mask with val=%lu\n",
172                                (unsigned long) key_listener->mask->value);
173               mask_ptr = Accessibility_ControllerEventMask__alloc();
174               mask_ptr->value = key_listener->mask->value;
175               mask_ptr->refcount = (CORBA_unsigned_short) 1;
176               controller->keymask_list = g_list_append (controller->keymask_list,
177                                                         (gpointer) mask_ptr);
178           }
179         }
180       break;
181   case SPI_DEVICE_TYPE_MOUSE:
182 /*    controller->mouse_listeners = g_list_append (controller->mouse_listeners,
183                                                    CORBA_Object_duplicate (l, ev));*/
184
185 /* possibly this interface should NOT be used for mouse events ? */
186       break;
187   }
188 }
189
190 static void
191 controller_deregister_device_listener (SpiDeviceEventController *controller,
192                                        DEControllerListener *listener,
193                                        CORBA_Environment *ev)
194 {
195   Accessibility_ControllerEventMask *mask_ptr;
196   DEControllerKeyListener *key_listener;
197   GList *list_ptr;
198   switch (listener->type) {
199   case SPI_DEVICE_TYPE_KBD:
200       key_listener = (DEControllerKeyListener *) listener;
201       list_ptr = g_list_find_custom (controller->key_listeners, listener, _compare_listeners);
202       /* TODO: need a different custom compare func */
203       if (list_ptr)
204           controller->key_listeners = g_list_remove (controller->key_listeners, list_ptr);
205       list_ptr = (GList *)
206                   g_list_find_custom (controller->keymask_list, (gpointer) key_listener->mask,
207                                      _eventmask_compare_value);
208       if (list_ptr)
209         {
210           mask_ptr = (Accessibility_ControllerEventMask *) list_ptr->data;
211           if (mask_ptr)
212               --mask_ptr->refcount;
213           if (!mask_ptr->refcount)
214             {
215               controller->keymask_list =
216                       g_list_remove (controller->keymask_list, mask_ptr);
217               ;  /* TODO: release any key grabs that are in place for this key mask */
218             }
219         }
220       break;
221   case SPI_DEVICE_TYPE_MOUSE:
222 /*    controller->mouse_listeners = g_list_append (controller->mouse_listeners,
223                                                    CORBA_Object_duplicate (l, ev));*/
224
225 /* possibly this interface should NOT be used for mouse events ? */
226       break;
227   }
228 }
229
230 static gboolean
231 _controller_register_with_devices (SpiDeviceEventController *controller)
232 {
233   gboolean retval = FALSE;
234
235   /* calls to device-specific implementations and routines go here */
236   /* register with: keyboard hardware code handler */
237   /* register with: (translated) keystroke handler */
238 #ifdef SPI_DEBUG
239   fprintf (stderr, "About to request events on window %ld of display %p\n",
240            (unsigned long) GDK_ROOT_WINDOW(), GDK_DISPLAY());
241 #endif
242   /* We must open a new connection to the server to avoid clashing with the GDK event loop */
243   display = XOpenDisplay (g_getenv ("DISPLAY"));
244   root_window = DefaultRootWindow (display);            
245   XSelectInput (display,
246                 root_window,
247                 KeyPressMask | KeyReleaseMask);
248   /* register with: mouse hardware device handler? */
249   /* register with: mouse event handler */
250   return retval;
251 }
252
253 static gboolean
254 key_set_contains_key (Accessibility_KeySet *key_set, Accessibility_KeyStroke *key_event)
255 {
256   gint i;
257   gint len;
258
259   /* g_assert (key_set); */
260   if (!key_set) { g_print ("null key set!"); return TRUE; }
261
262   len = key_set->_length;
263   
264   if (len == 0) /* special case, means "all keys/any key" */
265     {
266       return TRUE;
267     }
268
269   for (i=0; i<len; ++i)
270     {
271 #ifdef SPI_KEYEVENT_DEBUG           
272       g_print ("key_set[%d] = %d; key_event %d, code %d\n",
273                 i,
274                (int) key_set->_buffer[i],
275                (int) key_event->keyID,
276                (int) key_event->keycode); 
277 #endif
278       if (key_set->_buffer[i] == (CORBA_long) key_event->keyID) return TRUE;
279       if (key_set->_buffer[i] == (CORBA_long) -key_event->keycode) return TRUE;
280     }
281   
282   return FALSE;
283 }
284
285 static gboolean
286 key_eventtype_seq_contains_event (Accessibility_KeyEventTypeSeq *type_seq,
287                                   Accessibility_KeyStroke *key_event)
288 {
289   gint i;
290   gint len;
291
292   /* g_assert (type_seq); */
293   if (!type_seq) { g_print ("null type seq!"); return TRUE; }
294
295   len = type_seq->_length;
296   
297   if (len == 0) /* special case, means "all events/any event" */
298     {
299       return TRUE;
300     }
301
302   for (i=0; i<len; ++i)
303     {
304 /*      g_print ("type_seq[%d] = %d\n", i, (int) type_seq->_buffer[i]); */
305       if (type_seq->_buffer[i] == (CORBA_long) key_event->type) return TRUE;        
306     }
307   
308   return TRUE;
309 }
310
311 static gboolean
312 key_event_matches_listener (Accessibility_KeyStroke *key_event,
313                             DEControllerKeyListener *listener,
314                             CORBA_boolean is_system_global)
315 {
316   if ((key_event->modifiers == (CORBA_unsigned_short) (listener->mask->value & 0xFFFF)) &&
317        key_set_contains_key (listener->keys, key_event) &&
318        key_eventtype_seq_contains_event (listener->typeseq, key_event) && 
319       (is_system_global == listener->is_system_global))
320     {
321       return TRUE;
322     }
323   else
324     return FALSE;
325 }
326
327 static gboolean
328 notify_keylisteners (GList *key_listeners,
329                      Accessibility_KeyStroke *key_event,
330                      CORBA_boolean is_system_global,
331                      CORBA_Environment *ev)
332 {
333   int i, n_listeners = g_list_length (key_listeners);
334   gboolean is_consumed = FALSE;
335
336   for (i=0; i<n_listeners && !is_consumed; ++i)
337     {
338       Accessibility_KeystrokeListener ls;
339       DEControllerKeyListener *key_listener = (DEControllerKeyListener *)
340             g_list_nth_data (key_listeners, i);
341       ls = (Accessibility_KeystrokeListener) key_listener->listener.object;
342       if (key_event_matches_listener (key_event, key_listener, is_system_global))
343         {
344           if (!CORBA_Object_is_nil(ls, ev))
345             {
346               is_consumed = Accessibility_KeystrokeListener_keyEvent (ls, key_event, ev);
347             }           
348         }
349       else
350         {
351 #ifdef SPI_KEYEVENT_DEBUG
352               g_print ("no match for listener %d\n", i);
353 #endif
354               ;
355         }
356     }
357   return is_consumed;
358 }
359
360 static gboolean
361 _check_key_event (SpiDeviceEventController *controller)
362 {
363         static gboolean initialized = FALSE;
364         XEvent *x_event = g_new0 (XEvent, 1);
365         XKeyEvent *x_key_event;
366         KeySym keysym;
367         gboolean is_consumed = FALSE;
368         Accessibility_KeyStroke key_event;
369         static CORBA_Environment ev;
370
371         if (!initialized)
372         {
373           initialized = TRUE;
374           CORBA_exception_init (&ev);
375         }
376
377         while (XPending(display))
378           {
379             XNextEvent (display, x_event);
380             if (XFilterEvent (x_event, None)) continue;   
381             if (x_event->type == KeyPress)
382               {
383                 x_key_event = (XKeyEvent *)x_event;
384                 keysym = XLookupKeysym (x_key_event, 0);
385                 key_event.keyID = (CORBA_long)(keysym);
386                 key_event.keycode = (CORBA_short) x_key_event->keycode;
387                 key_event.type = Accessibility_KEY_PRESSED;
388                 key_event.modifiers = (CORBA_unsigned_short)(x_key_event->state);
389 #ifdef SPI_KEYEVENT_DEBUG
390             fprintf (stderr,
391                      "Key %lu pressed (%c), modifiers %d\n",
392                      (unsigned long) keysym,
393                      keysym ? (int) keysym : '*',
394                      (int) x_key_event->state);
395 #endif
396 #ifdef SPI_DEBUG
397             fprintf (stderr, "%s%c",
398                      (x_key_event->state & Mod1Mask)?"Alt-":"",
399                      ((x_key_event->state & ShiftMask)^(x_key_event->state & LockMask))?
400                      g_ascii_toupper (keysym) : g_ascii_tolower (keysym));
401 #endif /* SPI_DEBUG */
402               }
403             else
404             {
405 #ifdef SPI_KEYEVENT_DEBUG
406                     fprintf (stderr, "other event, type %d\n", (int) x_event->type);
407 #endif
408             }
409             /* relay to listeners, and decide whether to consume it or not */
410             is_consumed = notify_keylisteners (controller->key_listeners, &key_event, CORBA_TRUE, &ev);
411
412             if (is_consumed)
413             {
414               XAllowEvents (display, AsyncKeyboard, CurrentTime);
415             }
416             else
417             {
418               XAllowEvents (display, ReplayKeyboard, CurrentTime);
419             }
420           }
421         XUngrabKey (display, AnyKey, AnyModifier, root_window);
422         return _controller_grab_keyboard (controller);
423 }
424
425 static gboolean
426 _controller_grab_keyboard (SpiDeviceEventController *controller)
427 {
428         GList *maskList = controller->keymask_list;
429         int i;
430         int last_mask;
431         last_mask = g_list_length (maskList);
432
433 /*
434  * masks known to work with default RH 7.1: 
435  * 0 (no mods), LockMask, Mod1Mask, Mod2Mask, ShiftMask,
436  * ShiftMask|LockMask, Mod1Mask|LockMask, Mod2Mask|LockMask,
437  * ShiftMask|Mod1Mask, ShiftMask|Mod2Mask, Mod1Mask|Mod2Mask,
438  * ShiftMask|LockMask|Mod1Mask, ShiftMask|LockMask|Mod2Mask,
439  *
440  * ControlMask grabs are broken, must be in use already
441  */
442         
443         for (i=0; i < last_mask; ++i)
444         {
445                 Accessibility_ControllerEventMask *mask
446                         = (Accessibility_ControllerEventMask *)g_list_nth_data (maskList, i);
447                 unsigned long maskVal = 0xFFFFFFFF;
448                 if (mask) maskVal = (unsigned long) mask->value;
449 #ifdef SPI_KEYEVENT_DEBUG
450                 fprintf (stderr, "mask=%lx\n", maskVal);
451 #endif
452                 if (!(maskVal & ControlMask))
453                 {
454                         XGrabKey (display,
455                                   AnyKey,
456                                   maskVal,
457                                   root_window,
458                                   True,
459                                   GrabModeAsync,
460                                   GrabModeAsync);
461                         /* TODO: check call for errors and return FALSE if error occurs */
462                 } else {
463                         return FALSE; /* can't do control key yet */
464                 }
465         }
466         return TRUE;
467 }
468
469 /*
470  * Implemented GObject::finalize
471  */
472 static void
473 spi_device_event_controller_object_finalize (GObject *object)
474 {
475
476 #ifdef SPI_DEBUG
477         fprintf(stderr, "spi_device_event_controller_object_finalize called\n");
478 #endif
479         spi_device_event_controller_parent_class->finalize (object);
480 }
481
482 /*
483  * CORBA Accessibility::DeviceEventController::registerKeystrokeListener
484  *     method implementation
485  */
486 static void
487 impl_register_keystroke_listener (PortableServer_Servant     servant,
488                                   const Accessibility_KeystrokeListener l,
489                                   const Accessibility_KeySet *keys,
490                                   const Accessibility_ControllerEventMask *mask,
491                                   const Accessibility_KeyEventTypeSeq *type,
492                                   const CORBA_boolean is_system_global,
493                                   CORBA_Environment         *ev)
494 {
495         SpiDeviceEventController *controller = SPI_DEVICE_EVENT_CONTROLLER (
496                 bonobo_object_from_servant (servant));
497         DEControllerKeyListener *dec_listener;
498 #ifdef SPI_DEBUG
499         fprintf (stderr, "registering keystroke listener %p with maskVal %lu\n",
500                  (void *) l, (unsigned long) mask->value);
501 #endif
502         dec_listener = dec_key_listener_new (l, keys, mask, type, is_system_global, ev);
503         controller_register_device_listener (controller, (DEControllerListener *) dec_listener, ev);
504 }
505
506 /*
507  * CORBA Accessibility::DeviceEventController::deregisterKeystrokeListener
508  *     method implementation
509  */
510 static void
511 impl_deregister_keystroke_listener (PortableServer_Servant     servant,
512                                     const Accessibility_KeystrokeListener l,
513                                     const Accessibility_KeySet *keys,
514                                     const Accessibility_ControllerEventMask *mask,
515                                     const Accessibility_KeyEventTypeSeq *type,
516                                     const CORBA_boolean is_system_global,
517                                     CORBA_Environment         *ev)
518 {
519         SpiDeviceEventController *controller = SPI_DEVICE_EVENT_CONTROLLER (
520                 bonobo_object_from_servant (servant));
521         DEControllerKeyListener *key_listener = dec_key_listener_new (l,
522                                                                       keys,
523                                                                       mask,
524                                                                       type,
525                                                                       is_system_global,
526                                                                       ev);
527 #ifdef SPI_DEBUG
528         fprintf (stderr, "deregistering keystroke listener %p with maskVal %lu\n",
529                  (void *) l, (unsigned long) mask->value);
530 #endif
531         controller_deregister_device_listener(controller,
532                                               (DEControllerListener *) key_listener,
533                                               ev);
534 }
535
536 /*
537  * CORBA Accessibility::DeviceEventController::registerMouseListener
538  *     method implementation
539  */
540 /*
541 static void
542 impl_register_mouse_listener (PortableServer_Servant     servant,
543                               const Accessibility_MouseListener *l,
544                               CORBA_Environment         *ev)
545 {
546         SpiDeviceEventController *controller = SPI_DEVICE_EVENT_CONTROLLER (
547                 bonobo_object_from_servant (servant));
548 #ifdef SPI_DEBUG
549         fprintf (stderr, "registering mouse listener %p\n", l);
550 #endif
551         controller_register_device_listener(controller, DEVICE_TYPE_MOUSE, l, keys, mask, ev);
552 }
553 */
554
555 static KeyCode
556 keycode_for_keysym (long keysym)
557 {
558   return XKeysymToKeycode (display, (KeySym) keysym);
559 }
560
561 /*
562  * CORBA Accessibility::DeviceEventController::registerKeystrokeListener
563  *     method implementation
564  */
565 static void
566 impl_generate_key_event (PortableServer_Servant     servant,
567                          const CORBA_long           keycode,
568                          const Accessibility_KeySynthType synth_type,
569                          CORBA_Environment          *ev)
570 {
571         long key_synth_code;
572 #ifdef SPI_DEBUG
573         fprintf (stderr, "synthesizing keystroke %ld\n", (long) keycode);
574 #endif
575         /* TODO: hide/wrap/remove X dependency */
576
577         /* TODO: be accessX-savvy so that keyrelease occurs after sufficient timeout */
578         
579         /*
580          * TODO: when initializing, query for XTest extension before using,
581          * and fall back to XSendEvent() if XTest is not available.
582          */
583         
584         switch (synth_type)
585         {
586         case Accessibility_KEY_PRESS:
587                 XTestFakeKeyEvent (GDK_DISPLAY(), (unsigned int) keycode, True, CurrentTime);
588                 break;
589         case Accessibility_KEY_PRESSRELEASE:
590                 XTestFakeKeyEvent (GDK_DISPLAY(), (unsigned int) keycode, True, CurrentTime);
591         case Accessibility_KEY_RELEASE:
592                 XTestFakeKeyEvent (GDK_DISPLAY(), (unsigned int) keycode, False, CurrentTime);
593                 break;
594         case Accessibility_KEY_SYM:
595                 key_synth_code = keycode_for_keysym (keycode);
596                 XTestFakeKeyEvent (GDK_DISPLAY(), (unsigned int) key_synth_code, True, CurrentTime);
597                 XTestFakeKeyEvent (GDK_DISPLAY(), (unsigned int) key_synth_code, False, CurrentTime);
598                 break;
599         }
600 }
601
602 /* Accessibility::DeviceEventController::generateMouseEvent */
603 static void
604 impl_generate_mouse_event (PortableServer_Servant servant,
605                            const CORBA_long       x,
606                            const CORBA_long       y,
607                            const CORBA_char      *eventName,
608                            CORBA_Environment     *ev)
609 {
610 #ifdef SPI_DEBUG
611   fprintf (stderr, "generating mouse %s event at %ld, %ld\n", eventName, x, y);
612 #endif
613 }
614
615 /* Accessibility::DeviceEventController::notifyListenersSync */
616 static CORBA_boolean
617 impl_notify_listeners_sync(PortableServer_Servant     servant,
618                            const Accessibility_DeviceEvent *event,
619                            CORBA_Environment         *ev)
620 {
621   SpiDeviceEventController *controller = SPI_DEVICE_EVENT_CONTROLLER (
622                                          bonobo_object_from_servant (servant));
623   Accessibility_KeyStroke *key_event = (Accessibility_KeyStroke *) event;       
624 #ifdef SPI_DEBUG
625   g_print ("notifying listeners synchronously: controller %x, event id %d\n",
626            (void *) controller, (int) event->eventID);
627 #endif
628   return (notify_keylisteners (controller->key_listeners, key_event, CORBA_FALSE, ev) ?
629           CORBA_TRUE : CORBA_FALSE); 
630 }
631
632 /* Accessibility::DeviceEventController::notifyListenersAsync */
633 static void
634 impl_notify_listeners_async (PortableServer_Servant     servant,
635                              const Accessibility_DeviceEvent *event,
636                              CORBA_Environment         *ev)
637 {
638   SpiDeviceEventController *controller = SPI_DEVICE_EVENT_CONTROLLER(
639                                          bonobo_object_from_servant (servant));
640   Accessibility_KeyStroke *key_event = (Accessibility_KeyStroke *) event;       
641 #ifdef SPI_DEBUG
642   fprintf (stderr, "notifying listeners asynchronously\n");
643 #endif
644   notify_keylisteners (controller->key_listeners, key_event, CORBA_FALSE, ev); 
645 }
646
647 static void
648 spi_device_event_controller_class_init (SpiDeviceEventControllerClass *klass)
649 {
650         GObjectClass * object_class = (GObjectClass *) klass;
651         POA_Accessibility_DeviceEventController__epv *epv = &klass->epv;
652         spi_device_event_controller_parent_class = g_type_class_peek_parent (klass);
653
654         object_class->finalize = spi_device_event_controller_object_finalize;
655
656         epv->registerKeystrokeListener = impl_register_keystroke_listener;
657         epv->deregisterKeystrokeListener = impl_deregister_keystroke_listener;
658 /*        epv->registerMouseListener = impl_register_mouse_listener; */
659         epv->generateKeyEvent = impl_generate_key_event;
660         epv->generateMouseEvent = impl_generate_mouse_event;
661         epv->notifyListenersSync = impl_notify_listeners_sync;
662         epv->notifyListenersAsync = impl_notify_listeners_async;
663         klass->check_key_event = _check_key_event;
664 }
665
666 static void
667 spi_device_event_controller_init (SpiDeviceEventController *device_event_controller)
668 {
669   device_event_controller->key_listeners = NULL;
670   device_event_controller->mouse_listeners = NULL;
671   device_event_controller->keymask_list = NULL;
672   kbd_registered = _controller_register_with_devices (device_event_controller);
673 }
674
675 gboolean
676 spi_device_event_controller_check_key_event (SpiDeviceEventController *controller)
677 {
678         SpiDeviceEventControllerClass *klass = SPI_DEVICE_EVENT_CONTROLLER_GET_CLASS (controller);
679         if (klass->check_key_event)
680                 return (klass->check_key_event) (controller);
681         return FALSE;
682 }
683
684 SpiDeviceEventController *
685 spi_device_event_controller_new (void *registryp)
686 {
687   BonoboObject *registry = (BonoboObject *) registryp;  
688   SpiDeviceEventController *retval = g_object_new (
689           SPI_DEVICE_EVENT_CONTROLLER_TYPE, NULL);
690   retval->registry = registry;
691   bonobo_object_ref (registry);
692   return retval;
693 }
694
695 BONOBO_TYPE_FUNC_FULL (SpiDeviceEventController,
696                        Accessibility_DeviceEventController,
697                        PARENT_TYPE,
698                        spi_device_event_controller);
699