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