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