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