2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5 * Copyright 2001, 2002 Sun Microsystems Inc.,
6 * Copyright 2001, 2002 Ximian, Inc.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
24 /* deviceeventcontroller.c: implement the DeviceEventController interface */
30 #undef SPI_KEYEVENT_DEBUG
35 #include <bonobo/bonobo-exception.h>
38 #include <X11/extensions/XTest.h>
39 #include <X11/XKBlib.h>
41 #include <X11/keysymdef.h>
43 #include <gdk/gdkx.h> /* TODO: hide dependency (wrap in single porting file) */
44 #include <gdk/gdkkeysyms.h>
45 #include <gdk/gdkwindow.h>
47 #include "../libspi/spi-private.h"
48 #include "deviceeventcontroller.h"
50 /* Our parent Gtk object type */
51 #define PARENT_TYPE BONOBO_TYPE_OBJECT
53 /* A pointer to our parent object class */
54 static GObjectClass *spi_device_event_controller_parent_class;
55 static int spi_error_code = 0;
56 static GdkPoint *last_mouse_pos = NULL;
57 static unsigned int mouse_mask_state = 0;
58 static unsigned int mouse_button_mask =
59 Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask;
60 static unsigned int key_modifier_mask =
61 Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask | ShiftMask | LockMask | ControlMask;
63 static GQuark spi_dec_private_quark = 0;
65 int (*x_default_error_handler) (Display *display, XErrorEvent *error_event);
69 SPI_DEVICE_TYPE_MOUSE,
70 SPI_DEVICE_TYPE_LAST_DEFINED
71 } SpiDeviceTypeCategory;
75 guint pending_add : 1;
76 guint pending_remove : 1;
78 Accessibility_ControllerEventMask mod_mask;
79 CORBA_unsigned_long key_val; /* KeyCode */
80 } DEControllerGrabMask;
84 SpiDeviceTypeCategory type;
85 } DEControllerListener;
88 DEControllerListener listener;
90 Accessibility_KeySet *keys;
91 Accessibility_ControllerEventMask mask;
92 Accessibility_KeyEventTypeSeq *typeseq;
93 Accessibility_EventListenerMode *mode;
94 } DEControllerKeyListener;
97 unsigned int last_press_keycode;
98 unsigned int last_release_keycode;
99 struct timeval last_press_time;
100 struct timeval last_release_time;
101 } DEControllerPrivateData;
103 static void spi_controller_register_with_devices (SpiDEController *controller);
104 static gboolean spi_controller_update_key_grabs (SpiDEController *controller,
105 Accessibility_DeviceEvent *recv);
106 static gboolean spi_controller_register_device_listener (SpiDEController *controller,
107 DEControllerListener *l,
108 CORBA_Environment *ev);
109 static void spi_device_event_controller_forward_key_event (SpiDEController *controller,
110 const XEvent *event);
111 static void spi_deregister_controller_key_listener (SpiDEController *controller,
112 DEControllerKeyListener *key_listener,
113 CORBA_Environment *ev);
115 static gboolean spi_clear_error_state (void);
116 static gboolean spi_dec_poll_mouse_moved (gpointer data);
117 static gboolean spi_dec_poll_mouse_moving (gpointer data);
118 static gboolean spi_dec_poll_mouse_idle (gpointer data);
120 #define spi_get_display() GDK_DISPLAY()
122 /* Private methods */
125 keycode_for_keysym (long keysym)
127 return XKeysymToKeycode (spi_get_display (), (KeySym) keysym);
130 static DEControllerGrabMask *
131 spi_grab_mask_clone (DEControllerGrabMask *grab_mask)
133 DEControllerGrabMask *clone = g_new (DEControllerGrabMask, 1);
135 memcpy (clone, grab_mask, sizeof (DEControllerGrabMask));
137 clone->ref_count = 1;
138 clone->pending_add = TRUE;
139 clone->pending_remove = FALSE;
145 spi_grab_mask_free (DEControllerGrabMask *grab_mask)
151 spi_grab_mask_compare_values (gconstpointer p1, gconstpointer p2)
153 DEControllerGrabMask *l1 = (DEControllerGrabMask *) p1;
154 DEControllerGrabMask *l2 = (DEControllerGrabMask *) p2;
162 return ((l1->mod_mask != l2->mod_mask) || (l1->key_val != l2->key_val));
166 static gint poll_count = 0;
169 spi_dec_poll_mouse_moved (gpointer data)
171 SpiRegistry *registry = SPI_REGISTRY (data);
172 CORBA_Environment ev;
173 Accessibility_Event e;
174 Window root_return, child_return;
175 int win_x_return,win_y_return;
177 int poll_count_modulus = 10;
178 unsigned int mask_return;
179 gchar event_name[24];
180 Display *display = spi_get_display ();
183 XQueryPointer(display, DefaultRootWindow (display),
184 &root_return, &child_return,
186 &win_x_return, &win_y_return, &mask_return);
188 if (mask_return != mouse_mask_state) {
189 if ((mask_return & mouse_button_mask) !=
190 (mouse_mask_state & mouse_button_mask)) {
191 int button_number = 0;
192 if (!(mask_return & Button1Mask) &&
193 (mouse_mask_state & Button1Mask)) {
195 } else if (!(mask_return & Button2Mask) &&
196 (mouse_mask_state & Button2Mask)) {
198 } else if (!(mask_return & Button3Mask) &&
199 (mouse_mask_state & Button3Mask)) {
201 } else if (!(mask_return & Button4Mask) &&
202 (mouse_mask_state & Button1Mask)) {
204 } else if (!(mask_return & Button5Mask) &&
205 (mouse_mask_state & Button5Mask)) {
210 fprintf (stderr, "Button %d Released\n",
213 snprintf (event_name, 22, "mouse:button:%dr", button_number);
215 e.source = BONOBO_OBJREF (registry->desktop);
216 e.detail1 = last_mouse_pos->x;
217 e.detail2 = last_mouse_pos->y;
218 CORBA_exception_init (&ev);
219 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (registry),
224 if ((mask_return & key_modifier_mask) !=
225 (mouse_mask_state & key_modifier_mask)) {
227 fprintf (stderr, "MODIFIER CHANGE EVENT!\n");
229 e.type = "keyboard:modifiers";
230 e.source = BONOBO_OBJREF (registry->desktop);
231 e.detail1 = mouse_mask_state;
232 e.detail2 = mask_return;
233 CORBA_exception_init (&ev);
234 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (registry),
238 mouse_mask_state = mask_return;
240 if (last_mouse_pos == NULL) {
241 last_mouse_pos = g_new0 (GdkPoint, 1);
242 last_mouse_pos->x = 0;
243 last_mouse_pos->y = 0;
245 if (poll_count++ == poll_count_modulus) {
247 e.type = "mouse:abs";
248 e.source = BONOBO_OBJREF (registry->desktop);
251 CORBA_exception_init (&ev);
252 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (registry),
256 if (x != last_mouse_pos->x || y != last_mouse_pos->y) {
257 e.type = "mouse:rel";
258 e.source = BONOBO_OBJREF (registry->desktop);
259 e.detail1 = x - last_mouse_pos->x;
260 e.detail2 = y - last_mouse_pos->y;
261 CORBA_exception_init (&ev);
262 last_mouse_pos->x = x;
263 last_mouse_pos->y = y;
264 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (registry),
273 spi_dec_poll_mouse_idle (gpointer data)
275 if (! spi_dec_poll_mouse_moved (data))
279 g_timeout_add (20, spi_dec_poll_mouse_moving, data);
285 spi_dec_poll_mouse_moving (gpointer data)
287 if (spi_dec_poll_mouse_moved (data))
291 g_timeout_add (100, spi_dec_poll_mouse_idle, data);
297 spi_dec_ungrab_mouse (gpointer data)
299 Display *display = spi_get_display ();
300 fprintf (stderr, "mouse ungrab : display = %p\n", display);
303 XUngrabButton (spi_get_display (), AnyButton, AnyModifier,
304 XDefaultRootWindow (spi_get_display ()));
305 fprintf (stderr, "mouse grab released\n");
311 spi_dec_init_mouse_listener (SpiRegistry *registry)
313 Display *display = spi_get_display ();
314 g_timeout_add (100, spi_dec_poll_mouse_idle, registry);
318 XGrabButton (display, AnyButton, 0,
319 gdk_x11_get_default_root_xwindow (),
320 True, ButtonPressMask | ButtonReleaseMask,
321 GrabModeSync, GrabModeAsync, None, None);
322 XSync (display, False);
324 fprintf (stderr, "mouse buttons grabbed\n");
329 static DEControllerKeyListener *
330 spi_dec_key_listener_new (CORBA_Object l,
331 const Accessibility_KeySet *keys,
332 const Accessibility_ControllerEventMask mask,
333 const Accessibility_KeyEventTypeSeq *typeseq,
334 const Accessibility_EventListenerMode *mode,
335 CORBA_Environment *ev)
337 DEControllerKeyListener *key_listener = g_new0 (DEControllerKeyListener, 1);
338 key_listener->listener.object = bonobo_object_dup_ref (l, ev);
339 key_listener->listener.type = SPI_DEVICE_TYPE_KBD;
340 key_listener->keys = ORBit_copy_value (keys, TC_Accessibility_KeySet);
341 key_listener->mask = mask;
342 key_listener->typeseq = ORBit_copy_value (typeseq, TC_Accessibility_KeyEventTypeSeq);
344 key_listener->mode = ORBit_copy_value (mode, TC_Accessibility_EventListenerMode);
346 key_listener->mode = NULL;
349 g_print ("new listener, with mask %x, is_global %d, keys %p (%d)\n",
350 (unsigned int) key_listener->mask,
351 (int) (mode ? mode->global : 0),
352 (void *) key_listener->keys,
353 (int) (key_listener->keys ? key_listener->keys->_length : 0));
359 static DEControllerKeyListener *
360 spi_key_listener_clone (DEControllerKeyListener *key_listener, CORBA_Environment *ev)
362 DEControllerKeyListener *clone = g_new0 (DEControllerKeyListener, 1);
363 clone->listener.object =
364 CORBA_Object_duplicate (key_listener->listener.object, ev);
365 clone->listener.type = SPI_DEVICE_TYPE_KBD;
366 clone->keys = ORBit_copy_value (key_listener->keys, TC_Accessibility_KeySet);
367 clone->mask = key_listener->mask;
368 clone->typeseq = ORBit_copy_value (key_listener->typeseq, TC_Accessibility_KeyEventTypeSeq);
369 if (key_listener->mode)
370 clone->mode = ORBit_copy_value (key_listener->mode, TC_Accessibility_EventListenerMode);
377 spi_key_listener_data_free (DEControllerKeyListener *key_listener, CORBA_Environment *ev)
379 CORBA_free (key_listener->typeseq);
380 CORBA_free (key_listener->keys);
381 g_free (key_listener);
385 spi_key_listener_clone_free (DEControllerKeyListener *clone, CORBA_Environment *ev)
387 CORBA_Object_release (clone->listener.object, ev);
388 spi_key_listener_data_free (clone, ev);
392 spi_dec_key_listener_free (DEControllerKeyListener *key_listener,
393 CORBA_Environment *ev)
395 bonobo_object_release_unref (key_listener->listener.object, ev);
396 spi_key_listener_data_free (key_listener, ev);
400 _register_keygrab (SpiDEController *controller,
401 DEControllerGrabMask *grab_mask)
405 l = g_list_find_custom (controller->keygrabs_list, grab_mask,
406 spi_grab_mask_compare_values);
409 DEControllerGrabMask *cur_mask = l->data;
411 cur_mask->ref_count++;
412 if (cur_mask->pending_remove)
414 cur_mask->pending_remove = FALSE;
419 controller->keygrabs_list =
420 g_list_prepend (controller->keygrabs_list,
421 spi_grab_mask_clone (grab_mask));
426 _deregister_keygrab (SpiDEController *controller,
427 DEControllerGrabMask *grab_mask)
431 l = g_list_find_custom (controller->keygrabs_list, grab_mask,
432 spi_grab_mask_compare_values);
436 DEControllerGrabMask *cur_mask = l->data;
438 cur_mask->ref_count--;
439 if (cur_mask->ref_count <= 0)
441 cur_mask->pending_remove = TRUE;
446 g_warning ("De-registering non-existant grab");
451 handle_keygrab (SpiDEController *controller,
452 DEControllerKeyListener *key_listener,
453 void (*process_cb) (SpiDEController *controller,
454 DEControllerGrabMask *grab_mask))
456 DEControllerGrabMask grab_mask = { 0 };
458 grab_mask.mod_mask = key_listener->mask;
459 if (key_listener->keys->_length == 0) /* special case means AnyKey/AllKeys */
461 grab_mask.key_val = AnyKey;
463 fprintf (stderr, "AnyKey grab!");
465 process_cb (controller, &grab_mask);
471 for (i = 0; i < key_listener->keys->_length; ++i)
473 Accessibility_KeyDefinition keydef = key_listener->keys->_buffer[i];
474 long int key_val = keydef.keysym;
475 /* X Grabs require keycodes, not keysyms */
476 if (keydef.keystring && keydef.keystring[0])
478 key_val = XStringToKeysym(keydef.keystring);
482 key_val = XKeysymToKeycode (spi_get_display (), (KeySym) key_val);
486 key_val = keydef.keycode;
488 grab_mask.key_val = key_val;
489 process_cb (controller, &grab_mask);
495 spi_controller_register_global_keygrabs (SpiDEController *controller,
496 DEControllerKeyListener *key_listener)
498 handle_keygrab (controller, key_listener, _register_keygrab);
499 return spi_controller_update_key_grabs (controller, NULL);
503 spi_controller_deregister_global_keygrabs (SpiDEController *controller,
504 DEControllerKeyListener *key_listener)
506 handle_keygrab (controller, key_listener, _deregister_keygrab);
507 spi_controller_update_key_grabs (controller, NULL);
511 spi_controller_register_device_listener (SpiDEController *controller,
512 DEControllerListener *listener,
513 CORBA_Environment *ev)
515 DEControllerKeyListener *key_listener;
517 switch (listener->type) {
518 case SPI_DEVICE_TYPE_KBD:
519 key_listener = (DEControllerKeyListener *) listener;
521 controller->key_listeners = g_list_prepend (controller->key_listeners,
523 if (key_listener->mode->global)
525 return spi_controller_register_global_keygrabs (controller, key_listener);
537 spi_device_event_controller_forward_mouse_event (SpiDEController *controller,
540 Accessibility_Event e;
541 CORBA_Environment ev;
542 gchar event_name[24];
543 int button = ((XButtonEvent *) xevent)->button;
545 unsigned int mouse_button_state = ((XButtonEvent *) xevent)->state;
550 mouse_button_state |= Button1Mask;
553 mouse_button_state |= Button2Mask;
556 mouse_button_state |= Button3Mask;
559 mouse_button_state |= Button4Mask;
562 mouse_button_state |= Button5Mask;
565 last_mouse_pos->x = ((XButtonEvent *) xevent)->x_root;
566 last_mouse_pos->y = ((XButtonEvent *) xevent)->y_root;
569 fprintf (stderr, "mouse button %d %s (%x)\n",
570 ((XButtonEvent *) xevent)->button,
571 (xevent->type == ButtonPress) ? "Press" : "Release",
574 snprintf (event_name, 22, "mouse:button:%d%c", button,
575 (xevent->type == ButtonPress) ? 'p' : 'r');
577 e.type = CORBA_string_dup (event_name);
578 e.source = BONOBO_OBJREF (controller->registry->desktop);
579 e.detail1 = last_mouse_pos->x;
580 e.detail2 = last_mouse_pos->y;
581 CORBA_exception_init (&ev);
582 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry),
586 XAllowEvents (spi_get_display (), ReplayPointer, CurrentTime);
589 static GdkFilterReturn
590 global_filter_fn (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
592 XEvent *xevent = gdk_xevent;
593 SpiDEController *controller;
595 if (xevent->type == KeyPress || xevent->type == KeyRelease)
597 controller = SPI_DEVICE_EVENT_CONTROLLER (data);
598 spi_device_event_controller_forward_key_event (controller, xevent);
599 /* FIXME: is this right ? */
600 return GDK_FILTER_CONTINUE;
602 if (xevent->type == ButtonPress || xevent->type == ButtonRelease)
604 controller = SPI_DEVICE_EVENT_CONTROLLER (data);
605 spi_device_event_controller_forward_mouse_event (controller, xevent);
608 return GDK_FILTER_CONTINUE;
612 _spi_controller_device_error_handler (Display *display, XErrorEvent *error)
614 if (error->error_code == BadAccess)
616 g_message ("Could not complete key grab: grab already in use.\n");
617 spi_error_code = BadAccess;
622 return (*x_default_error_handler) (display, error);
627 spi_controller_register_with_devices (SpiDEController *controller)
629 /* calls to device-specific implementations and routines go here */
630 /* register with: keyboard hardware code handler */
631 /* register with: (translated) keystroke handler */
633 gdk_window_add_filter (NULL, global_filter_fn, controller);
635 gdk_window_set_events (gdk_get_default_root_window (),
636 GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
638 x_default_error_handler = XSetErrorHandler (_spi_controller_device_error_handler);
642 spi_key_set_contains_key (Accessibility_KeySet *key_set,
643 const Accessibility_DeviceEvent *key_event)
650 g_print ("null key set!");
654 len = key_set->_length;
656 if (len == 0) /* special case, means "all keys/any key" */
658 g_print ("anykey\n");
662 for (i = 0; i < len; ++i)
664 #ifdef SPI_KEYEVENT_DEBUG
665 g_print ("key_set[%d] = %d; key_event %d, code %d, string %s\n",
666 i, (int) key_set->_buffer[i].keycode,
667 (int) key_event->id, (int) key_event->hw_code,
668 key_event->event_string);
670 if (key_set->_buffer[i].keysym == (CORBA_long) key_event->id)
674 if (key_set->_buffer[i].keycode == (CORBA_long) key_event->hw_code)
678 if (key_event->event_string && key_event->event_string[0] &&
679 !strcmp (key_set->_buffer[i].keystring, key_event->event_string))
689 spi_key_eventtype_seq_contains_event (Accessibility_KeyEventTypeSeq *type_seq,
690 const Accessibility_DeviceEvent *key_event)
698 g_print ("null type seq!");
702 len = type_seq->_length;
704 if (len == 0) /* special case, means "all events/any event" */
709 for (i = 0; i < len; ++i)
712 g_print ("type_seq[%d] = %d; key event type = %d\n", i,
713 (int) type_seq->_buffer[i], (int) key_event->type);
715 if (type_seq->_buffer[i] == (CORBA_long) key_event->type)
725 spi_key_event_matches_listener (const Accessibility_DeviceEvent *key_event,
726 DEControllerKeyListener *listener,
727 CORBA_boolean is_system_global)
729 if ((key_event->modifiers == (CORBA_unsigned_short) (listener->mask & 0xFFFF)) &&
730 spi_key_set_contains_key (listener->keys, key_event) &&
731 spi_key_eventtype_seq_contains_event (listener->typeseq, key_event) &&
732 (is_system_global == listener->mode->global))
743 spi_controller_notify_keylisteners (SpiDEController *controller,
744 const Accessibility_DeviceEvent *key_event,
745 CORBA_boolean is_system_global,
746 CORBA_Environment *ev)
749 GSList *notify = NULL, *l2;
750 GList **key_listeners = &controller->key_listeners;
751 gboolean is_consumed;
758 for (l = *key_listeners; l; l = l->next)
760 DEControllerKeyListener *key_listener = l->data;
762 if (spi_key_event_matches_listener (key_event, key_listener, is_system_global))
764 Accessibility_DeviceEventListener ls = key_listener->listener.object;
766 if (ls != CORBA_OBJECT_NIL)
768 /* we clone (don't dup) the listener, to avoid refcount inc. */
769 notify = g_slist_prepend (notify,
770 spi_key_listener_clone (key_listener, ev));
775 #ifdef SPI_KEYEVENT_DEBUG
778 g_print ("no match for event\n");
783 for (l2 = notify; l2 && !is_consumed; l2 = l2->next)
785 DEControllerKeyListener *key_listener = l2->data;
786 Accessibility_DeviceEventListener ls = key_listener->listener.object;
788 is_consumed = Accessibility_DeviceEventListener_notifyEvent (ls, key_event, ev);
793 spi_deregister_controller_key_listener (controller, key_listener,
795 CORBA_exception_free (ev);
798 CORBA_Object_release (ls, ev);
801 for (; l2; l2 = l2->next)
803 DEControllerKeyListener *key_listener = l2->data;
804 spi_key_listener_clone_free (key_listener, ev);
805 /* clone doesn't have its own ref, so don't use spi_key_listener_free */
808 g_slist_free (notify);
811 if (is_consumed) g_message ("consumed\n");
817 spi_clear_error_state ()
819 gboolean retval = spi_error_code != 0;
824 static Accessibility_DeviceEvent
825 spi_keystroke_from_x_key_event (XKeyEvent *x_key_event)
827 Accessibility_DeviceEvent key_event;
829 const int cbuf_bytes = 20;
830 char cbuf [cbuf_bytes];
832 keysym = XLookupKeysym (x_key_event, 0);
833 key_event.id = (CORBA_long)(keysym);
834 key_event.hw_code = (CORBA_short) x_key_event->keycode;
835 if (((XEvent *) x_key_event)->type == KeyPress)
837 key_event.type = Accessibility_KEY_PRESSED;
841 key_event.type = Accessibility_KEY_RELEASED;
843 key_event.modifiers = (CORBA_unsigned_short)(x_key_event->state);
844 key_event.is_text = CORBA_FALSE;
848 key_event.event_string = CORBA_string_dup ("space");
851 #ifdef SPI_KEYEVENT_DEBUG
852 fprintf(stderr, "Tab\n");
854 key_event.event_string = CORBA_string_dup ("Tab");
857 key_event.event_string = CORBA_string_dup ("Backspace");
860 key_event.event_string = CORBA_string_dup ("Return");
863 key_event.event_string = CORBA_string_dup ("Home");
866 key_event.event_string = CORBA_string_dup ("Page_Down");
869 key_event.event_string = CORBA_string_dup ("Page_Up");
872 key_event.event_string = CORBA_string_dup ("F1");
875 key_event.event_string = CORBA_string_dup ("F2");
878 key_event.event_string = CORBA_string_dup ("F3");
881 key_event.event_string = CORBA_string_dup ("F4");
884 key_event.event_string = CORBA_string_dup ("F5");
887 key_event.event_string = CORBA_string_dup ("F6");
890 key_event.event_string = CORBA_string_dup ("F7");
893 key_event.event_string = CORBA_string_dup ("F8");
896 key_event.event_string = CORBA_string_dup ("F9");
899 key_event.event_string = CORBA_string_dup ("F10");
902 key_event.event_string = CORBA_string_dup ("F11");
905 key_event.event_string = CORBA_string_dup ("F12");
908 key_event.event_string = CORBA_string_dup ("End");
911 key_event.event_string = CORBA_string_dup ("Escape");
914 key_event.event_string = CORBA_string_dup ("Up");
917 key_event.event_string = CORBA_string_dup ("Down");
920 key_event.event_string = CORBA_string_dup ("Left");
923 key_event.event_string = CORBA_string_dup ("Right");
926 if (XLookupString (x_key_event, cbuf, cbuf_bytes, &keysym, NULL) > 0)
928 key_event.event_string = CORBA_string_dup (cbuf);
929 if (isgraph (keysym))
931 key_event.is_text = CORBA_TRUE; /* FIXME: incorrect for some composed chars? */
936 key_event.event_string = CORBA_string_dup ("");
940 key_event.timestamp = (CORBA_unsigned_long) x_key_event->time;
941 #ifdef SPI_KEYEVENT_DEBUG
943 "Key %lu pressed (%c), modifiers %d\n",
944 (unsigned long) keysym,
945 keysym ? (int) keysym : '*',
946 (int) x_key_event->state);
949 fprintf (stderr, "%s%c",
950 (x_key_event->state & Mod1Mask)?"Alt-":"",
951 ((x_key_event->state & ShiftMask)^(x_key_event->state & LockMask))?
952 g_ascii_toupper (keysym) : g_ascii_tolower (keysym));
953 #endif /* SPI_DEBUG */
958 spi_controller_update_key_grabs (SpiDEController *controller,
959 Accessibility_DeviceEvent *recv)
962 gboolean update_failed = FALSE;
964 g_return_val_if_fail (controller != NULL, FALSE);
967 * masks known to work with default RH 7.1+:
968 * 0 (no mods), LockMask, Mod1Mask, Mod2Mask, ShiftMask,
969 * ShiftMask|LockMask, Mod1Mask|LockMask, Mod2Mask|LockMask,
970 * ShiftMask|Mod1Mask, ShiftMask|Mod2Mask, Mod1Mask|Mod2Mask,
971 * ShiftMask|LockMask|Mod1Mask, ShiftMask|LockMask|Mod2Mask,
973 * ControlMask grabs are broken, must be in use already
975 for (l = controller->keygrabs_list; l; l = next)
978 gboolean re_issue_grab;
979 DEControllerGrabMask *grab_mask = l->data;
983 re_issue_grab = recv &&
984 /* (recv->type == Accessibility_KEY_RELEASED) && - (?) */
985 (recv->modifiers & grab_mask->mod_mask) &&
986 (grab_mask->key_val == keycode_for_keysym (recv->id));
989 fprintf (stderr, "mask=%lx %lx (%c%c) %s\n",
990 (long int) grab_mask->key_val,
991 (long int) grab_mask->mod_mask,
992 grab_mask->pending_add ? '+' : '.',
993 grab_mask->pending_remove ? '-' : '.',
994 re_issue_grab ? "re-issue": "");
999 if (grab_mask->pending_add && grab_mask->pending_remove)
1003 else if (grab_mask->pending_remove)
1006 fprintf (stderr, "ungrabbing, mask=%x\n", grab_mask->mod_mask);
1008 XUngrabKey (spi_get_display (),
1010 grab_mask->mod_mask,
1011 gdk_x11_get_default_root_xwindow ());
1015 else if (grab_mask->pending_add || re_issue_grab)
1019 fprintf (stderr, "grab %d with mask %x\n", grab_mask->key_val, grab_mask->mod_mask);
1021 XGrabKey (spi_get_display (),
1023 grab_mask->mod_mask,
1024 gdk_x11_get_default_root_xwindow (),
1028 XSync (spi_get_display (), False);
1029 update_failed = spi_clear_error_state ();
1030 if (update_failed) {
1031 while (grab_mask->ref_count > 0) --grab_mask->ref_count;
1036 grab_mask->pending_add = FALSE;
1037 grab_mask->pending_remove = FALSE;
1041 g_assert (grab_mask->ref_count <= 0);
1043 controller->keygrabs_list = g_list_delete_link (
1044 controller->keygrabs_list, l);
1046 spi_grab_mask_free (grab_mask);
1051 return ! update_failed;
1055 * Implemented GObject::finalize
1058 spi_device_event_controller_object_finalize (GObject *object)
1060 SpiDEController *controller;
1062 controller = SPI_DEVICE_EVENT_CONTROLLER (object);
1065 fprintf(stderr, "spi_device_event_controller_object_finalize called\n");
1067 /* disconnect any special listeners, get rid of outstanding keygrabs */
1068 XUngrabKey (spi_get_display (), AnyKey, AnyModifier, DefaultRootWindow (spi_get_display ()));
1070 g_free (g_object_get_data (G_OBJECT (controller), "spi-dec-private"));
1071 spi_device_event_controller_parent_class->finalize (object);
1075 * CORBA Accessibility::DEController::registerKeystrokeListener
1076 * method implementation
1078 static CORBA_boolean
1079 impl_register_keystroke_listener (PortableServer_Servant servant,
1080 const Accessibility_DeviceEventListener l,
1081 const Accessibility_KeySet *keys,
1082 const Accessibility_ControllerEventMask mask,
1083 const Accessibility_KeyEventTypeSeq *type,
1084 const Accessibility_EventListenerMode *mode,
1085 CORBA_Environment *ev)
1087 SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1088 bonobo_object_from_servant (servant));
1089 DEControllerKeyListener *dec_listener;
1091 fprintf (stderr, "registering keystroke listener %p with maskVal %lu\n",
1092 (void *) l, (unsigned long) mask);
1094 dec_listener = spi_dec_key_listener_new (l, keys, mask, type, mode, ev);
1095 return spi_controller_register_device_listener (
1096 controller, (DEControllerListener *) dec_listener, ev);
1101 CORBA_Environment *ev;
1102 DEControllerKeyListener *key_listener;
1103 } RemoveKeyListenerClosure;
1105 static SpiReEntrantContinue
1106 remove_key_listener_cb (GList * const *list,
1109 DEControllerKeyListener *key_listener = (*list)->data;
1110 RemoveKeyListenerClosure *ctx = user_data;
1112 if (CORBA_Object_is_equivalent (ctx->key_listener->listener.object,
1113 key_listener->listener.object, ctx->ev))
1115 spi_re_entrant_list_delete_link (list);
1116 spi_dec_key_listener_free (key_listener, ctx->ev);
1119 return SPI_RE_ENTRANT_CONTINUE;
1122 static SpiReEntrantContinue
1123 copy_key_listener_cb (GList * const *list,
1126 DEControllerKeyListener *key_listener = (*list)->data;
1127 RemoveKeyListenerClosure *ctx = user_data;
1129 if (CORBA_Object_is_equivalent (ctx->key_listener->listener.object,
1130 key_listener->listener.object, ctx->ev))
1132 /* TODO: FIXME aggregate keys in case the listener is registered twice */
1133 CORBA_free (ctx->key_listener->keys);
1134 ctx->key_listener->keys = ORBit_copy_value (key_listener->keys, TC_Accessibility_KeySet);
1137 return SPI_RE_ENTRANT_CONTINUE;
1142 spi_deregister_controller_key_listener (SpiDEController *controller,
1143 DEControllerKeyListener *key_listener,
1144 CORBA_Environment *ev)
1146 RemoveKeyListenerClosure ctx;
1149 ctx.key_listener = key_listener;
1151 /* special case, copy keyset from existing controller list entry */
1152 if (key_listener->keys->_length == 0)
1154 spi_re_entrant_list_foreach (&controller->key_listeners,
1155 copy_key_listener_cb, &ctx);
1158 spi_controller_deregister_global_keygrabs (controller, key_listener);
1160 spi_re_entrant_list_foreach (&controller->key_listeners,
1161 remove_key_listener_cb, &ctx);
1166 * CORBA Accessibility::DEController::deregisterKeystrokeListener
1167 * method implementation
1170 impl_deregister_keystroke_listener (PortableServer_Servant servant,
1171 const Accessibility_DeviceEventListener l,
1172 const Accessibility_KeySet *keys,
1173 const Accessibility_ControllerEventMask mask,
1174 const Accessibility_KeyEventTypeSeq *type,
1175 CORBA_Environment *ev)
1177 DEControllerKeyListener *key_listener;
1178 SpiDEController *controller;
1180 controller = SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
1182 key_listener = spi_dec_key_listener_new (l, keys, mask, type, NULL, ev);
1184 #ifdef SPI_DEREGISTER_DEBUG
1185 fprintf (stderr, "deregistering keystroke listener %p with maskVal %lu\n",
1186 (void *) l, (unsigned long) mask->value);
1189 spi_deregister_controller_key_listener (controller, key_listener, ev);
1191 spi_dec_key_listener_free (key_listener, ev);
1194 static unsigned int dec_xkb_get_slowkeys_delay (SpiDEController *controller)
1196 unsigned int retval = 0;
1198 #ifdef XKB_HAS_GET_SLOW_KEYS_DELAY
1199 retval = XkbGetSlowKeysDelay (spi_get_display (),
1200 XkbUseCoreKbd, &bounce_delay);
1202 XkbDescPtr xkb = XkbGetMap (spi_get_display (), 0, XkbUseCoreKbd);
1203 if (!(xkb == (XkbDescPtr) BadAlloc || xkb == NULL))
1205 Status s = XkbGetControls (spi_get_display (),
1206 XkbAllControlsMask, xkb);
1209 if (xkb->ctrls->enabled_ctrls & XkbSlowKeysMask)
1210 retval = xkb->ctrls->slow_keys_delay;
1212 XkbFreeKeyboard (xkb, XkbAllControlsMask, True);
1216 #ifdef SPI_XKB_DEBUG
1217 fprintf (stderr, "SlowKeys delay: %d\n", (int) retval);
1222 static unsigned int dec_xkb_get_bouncekeys_delay (SpiDEController *controller)
1224 unsigned int retval = 0;
1226 #ifdef XKB_HAS_GET_BOUNCE_KEYS_DELAY
1227 retval = XkbGetBounceKeysDelay (spi_get_display (),
1228 XkbUseCoreKbd, &bounce_delay);
1230 XkbDescPtr xkb = XkbGetMap (spi_get_display (), 0, XkbUseCoreKbd);
1231 if (!(xkb == (XkbDescPtr) BadAlloc || xkb == NULL))
1233 Status s = XkbGetControls (spi_get_display (),
1234 XkbAllControlsMask, xkb);
1237 if (xkb->ctrls->enabled_ctrls & XkbBounceKeysMask)
1238 retval = xkb->ctrls->debounce_delay;
1240 XkbFreeKeyboard (xkb, XkbAllControlsMask, True);
1244 #ifdef SPI_XKB_DEBUG
1245 fprintf (stderr, "BounceKeys delay: %d\n", (int) retval);
1251 dec_synth_keycode_press (SpiDEController *controller,
1252 unsigned int keycode)
1254 unsigned int time = CurrentTime;
1255 unsigned int bounce_delay;
1256 unsigned int elapsed_msec;
1258 DEControllerPrivateData *priv =
1259 (DEControllerPrivateData *) g_object_get_qdata (G_OBJECT (controller),
1260 spi_dec_private_quark);
1261 if (keycode == priv->last_release_keycode)
1263 bounce_delay = dec_xkb_get_bouncekeys_delay (controller);
1266 gettimeofday (&tv, NULL);
1268 (tv.tv_sec - priv->last_release_time.tv_sec) * 1000
1269 + (tv.tv_usec - priv->last_release_time.tv_usec) / 1000;
1270 #ifdef SPI_XKB_DEBUG
1271 fprintf (stderr, "%d ms elapsed (%ld usec)\n", elapsed_msec,
1272 (long) (tv.tv_usec - priv->last_release_time.tv_usec));
1274 #ifdef THIS_IS_BROKEN
1275 if (elapsed_msec < bounce_delay)
1276 time = bounce_delay - elapsed_msec + 1;
1278 time = bounce_delay + 10;
1279 /* fudge for broken XTest */
1281 #ifdef SPI_XKB_DEBUG
1282 fprintf (stderr, "waiting %d ms\n", time);
1286 fprintf (stderr, "press %d\n", (int) keycode);
1287 XTestFakeKeyEvent (spi_get_display (), keycode, True, time);
1288 priv->last_press_keycode = keycode;
1289 XSync (spi_get_display (), False);
1290 gettimeofday (&priv->last_press_time, NULL);
1295 dec_synth_keycode_release (SpiDEController *controller,
1296 unsigned int keycode)
1298 unsigned int time = CurrentTime;
1299 unsigned int slow_delay;
1300 unsigned int elapsed_msec;
1302 DEControllerPrivateData *priv =
1303 (DEControllerPrivateData *) g_object_get_qdata (G_OBJECT (controller),
1304 spi_dec_private_quark);
1305 if (keycode == priv->last_press_keycode)
1307 slow_delay = dec_xkb_get_slowkeys_delay (controller);
1310 gettimeofday (&tv, NULL);
1312 (tv.tv_sec - priv->last_press_time.tv_sec) * 1000
1313 + (tv.tv_usec - priv->last_press_time.tv_usec) / 1000;
1314 #ifdef SPI_XKB_DEBUG
1315 fprintf (stderr, "%d ms elapsed (%ld usec)\n", elapsed_msec,
1316 (long) (tv.tv_usec - priv->last_press_time.tv_usec));
1318 #ifdef THIS_IS_BROKEN_DUNNO_WHY
1319 if (elapsed_msec < slow_delay)
1320 time = slow_delay - elapsed_msec + 1;
1322 time = slow_delay + 10;
1323 /* our XTest seems broken, we have to add slop as above */
1325 #ifdef SPI_XKB_DEBUG
1326 fprintf (stderr, "waiting %d ms\n", time);
1330 fprintf (stderr, "release %d\n", (int) keycode);
1331 XTestFakeKeyEvent (spi_get_display (), keycode, False, time);
1332 priv->last_release_keycode = keycode;
1333 XSync (spi_get_display (), False);
1334 gettimeofday (&priv->last_release_time, NULL);
1339 * CORBA Accessibility::DEController::registerKeystrokeListener
1340 * method implementation
1343 impl_generate_keyboard_event (PortableServer_Servant servant,
1344 const CORBA_long keycode,
1345 const CORBA_char *keystring,
1346 const Accessibility_KeySynthType synth_type,
1347 CORBA_Environment *ev)
1349 SpiDEController *controller =
1350 SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
1351 long key_synth_code;
1352 unsigned int slow_keys_delay;
1353 unsigned int press_time;
1354 unsigned int release_time;
1357 fprintf (stderr, "synthesizing keystroke %ld, type %d\n",
1358 (long) keycode, (int) synth_type);
1360 /* TODO: hide/wrap/remove X dependency */
1363 * TODO: when initializing, query for XTest extension before using,
1364 * and fall back to XSendEvent() if XTest is not available.
1367 /* TODO: implement keystring mode also */
1368 gdk_error_trap_push ();
1372 case Accessibility_KEY_PRESS:
1373 dec_synth_keycode_press (controller, keycode);
1375 case Accessibility_KEY_PRESSRELEASE:
1376 dec_synth_keycode_press (controller, keycode);
1377 case Accessibility_KEY_RELEASE:
1378 dec_synth_keycode_release (controller, keycode);
1380 case Accessibility_KEY_SYM:
1381 #ifdef SPI_XKB_DEBUG
1382 fprintf (stderr, "KeySym synthesis\n");
1384 key_synth_code = keycode_for_keysym (keycode);
1385 dec_synth_keycode_press (controller, key_synth_code);
1386 dec_synth_keycode_release (controller, key_synth_code);
1388 case Accessibility_KEY_STRING:
1389 fprintf (stderr, "Not yet implemented\n");
1392 if (gdk_error_trap_pop ())
1394 g_warning ("Error emitting keystroke");
1398 /* Accessibility::DEController::generateMouseEvent */
1400 impl_generate_mouse_event (PortableServer_Servant servant,
1403 const CORBA_char *eventName,
1404 CORBA_Environment *ev)
1407 gboolean error = FALSE;
1408 Display *display = spi_get_display ();
1410 fprintf (stderr, "generating mouse %s event at %ld, %ld\n",
1411 eventName, (long int) x, (long int) y);
1413 g_message ("mouse event synthesis\n");
1414 switch (eventName[0])
1417 switch (eventName[1])
1419 /* TODO: check number of buttons before parsing */
1434 if (x != -1 && y != -1)
1436 XTestFakeMotionEvent (display, DefaultScreen (display),
1439 XTestFakeButtonEvent (display, button, !(eventName[2] == 'r'), 0);
1440 if (eventName[2] == 'c')
1441 XTestFakeButtonEvent (display, button, FALSE, 1);
1442 else if (eventName[2] == 'd')
1444 XTestFakeButtonEvent (display, button, FALSE, 1);
1445 XTestFakeButtonEvent (display, button, TRUE, 2);
1446 XTestFakeButtonEvent (display, button, FALSE, 3);
1450 case 'r': /* relative motion */
1451 XTestFakeRelativeMotionEvent (display, x, y, 0);
1453 case 'a': /* absolute motion */
1454 XTestFakeMotionEvent (display, DefaultScreen (display),
1460 /* Accessibility::DEController::notifyListenersSync */
1461 static CORBA_boolean
1462 impl_notify_listeners_sync (PortableServer_Servant servant,
1463 const Accessibility_DeviceEvent *event,
1464 CORBA_Environment *ev)
1466 SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1467 bonobo_object_from_servant (servant));
1469 g_print ("notifylistening listeners synchronously: controller %p, event id %d\n",
1470 controller, (int) event->id);
1472 return spi_controller_notify_keylisteners (controller, event, CORBA_FALSE, ev) ?
1473 CORBA_TRUE : CORBA_FALSE;
1476 /* Accessibility::DEController::notifyListenersAsync */
1478 impl_notify_listeners_async (PortableServer_Servant servant,
1479 const Accessibility_DeviceEvent *event,
1480 CORBA_Environment *ev)
1482 SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1483 bonobo_object_from_servant (servant));
1485 fprintf (stderr, "notifying listeners asynchronously\n");
1487 spi_controller_notify_keylisteners (controller, event, CORBA_FALSE, ev);
1491 spi_device_event_controller_class_init (SpiDEControllerClass *klass)
1493 GObjectClass * object_class = (GObjectClass *) klass;
1494 POA_Accessibility_DeviceEventController__epv *epv = &klass->epv;
1496 spi_device_event_controller_parent_class = g_type_class_peek_parent (klass);
1498 object_class->finalize = spi_device_event_controller_object_finalize;
1500 epv->registerKeystrokeListener = impl_register_keystroke_listener;
1501 epv->deregisterKeystrokeListener = impl_deregister_keystroke_listener;
1502 epv->generateKeyboardEvent = impl_generate_keyboard_event;
1503 epv->generateMouseEvent = impl_generate_mouse_event;
1504 epv->notifyListenersSync = impl_notify_listeners_sync;
1505 epv->notifyListenersAsync = impl_notify_listeners_async;
1509 spi_device_event_controller_init (SpiDEController *device_event_controller)
1511 device_event_controller->key_listeners = NULL;
1512 device_event_controller->mouse_listeners = NULL;
1513 device_event_controller->keygrabs_list = NULL;
1516 * TODO: fixme, this module makes the foolish assumptions that
1517 * registryd uses the same display as the apps, and that the
1518 * DISPLAY environment variable is set.
1520 gdk_init (NULL, NULL);
1522 spi_controller_register_with_devices (device_event_controller);
1526 spi_device_event_controller_forward_key_event (SpiDEController *controller,
1527 const XEvent *event)
1529 gboolean is_consumed = FALSE;
1530 CORBA_Environment ev;
1531 Accessibility_DeviceEvent key_event;
1533 g_assert (event->type == KeyPress || event->type == KeyRelease);
1535 CORBA_exception_init (&ev);
1537 key_event = spi_keystroke_from_x_key_event ((XKeyEvent *) event);
1539 spi_controller_update_key_grabs (controller, &key_event);
1541 /* relay to listeners, and decide whether to consume it or not */
1542 is_consumed = spi_controller_notify_keylisteners (
1543 controller, &key_event, CORBA_TRUE, &ev);
1545 CORBA_exception_free (&ev);
1549 XAllowEvents (spi_get_display (), AsyncKeyboard, CurrentTime);
1553 XAllowEvents (spi_get_display (), ReplayKeyboard, CurrentTime);
1558 spi_device_event_controller_new (SpiRegistry *registry)
1560 SpiDEController *retval = g_object_new (
1561 SPI_DEVICE_EVENT_CONTROLLER_TYPE, NULL);
1562 DEControllerPrivateData *private;
1564 retval->registry = SPI_REGISTRY (bonobo_object_ref (
1565 BONOBO_OBJECT (registry)));
1567 private = g_new0 (DEControllerPrivateData, 1);
1568 gettimeofday (&private->last_press_time, NULL);
1569 gettimeofday (&private->last_release_time, NULL);
1570 if (!spi_dec_private_quark)
1571 spi_dec_private_quark = g_quark_from_static_string ("spi-dec-private");
1572 g_object_set_qdata (G_OBJECT (retval),
1573 spi_dec_private_quark,
1575 spi_dec_init_mouse_listener (registry);
1576 /* TODO: kill mouse listener on finalize */
1580 BONOBO_TYPE_FUNC_FULL (SpiDEController,
1581 Accessibility_DeviceEventController,
1583 spi_device_event_controller);