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