1 /* 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_static = {0, 0};
57 static GdkPoint *last_mouse_pos = &last_mouse_pos_static;
58 static unsigned int mouse_mask_state = 0;
59 static unsigned int mouse_button_mask =
60 Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask;
61 static unsigned int key_modifier_mask =
62 Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask | ShiftMask | LockMask | ControlMask;
64 static GQuark spi_dec_private_quark = 0;
66 int (*x_default_error_handler) (Display *display, XErrorEvent *error_event);
70 SPI_DEVICE_TYPE_MOUSE,
71 SPI_DEVICE_TYPE_LAST_DEFINED
72 } SpiDeviceTypeCategory;
76 guint pending_add : 1;
77 guint pending_remove : 1;
79 Accessibility_ControllerEventMask mod_mask;
80 CORBA_unsigned_long key_val; /* KeyCode */
81 } DEControllerGrabMask;
85 SpiDeviceTypeCategory type;
86 Accessibility_EventTypeSeq *typeseq;
87 } DEControllerListener;
90 DEControllerListener listener;
92 Accessibility_KeySet *keys;
93 Accessibility_ControllerEventMask mask;
94 Accessibility_EventListenerMode *mode;
95 } DEControllerKeyListener;
98 unsigned int last_press_keycode;
99 unsigned int last_release_keycode;
100 struct timeval last_press_time;
101 struct timeval last_release_time;
103 int xkb_major_extension_opcode;
104 int xkb_base_event_code;
105 int xkb_base_error_code;
106 unsigned int xkb_latch_mask;
107 unsigned int pending_xkb_mod_relatch_mask;
108 KeyCode *shift_keycodes;
110 } DEControllerPrivateData;
112 static void spi_controller_register_with_devices (SpiDEController *controller);
113 static gboolean spi_controller_update_key_grabs (SpiDEController *controller,
114 Accessibility_DeviceEvent *recv);
115 static gboolean spi_controller_register_device_listener (SpiDEController *controller,
116 DEControllerListener *l,
117 CORBA_Environment *ev);
118 static void spi_device_event_controller_forward_key_event (SpiDEController *controller,
119 const XEvent *event);
120 static void spi_deregister_controller_device_listener (SpiDEController *controller,
121 DEControllerListener *listener,
122 CORBA_Environment *ev);
123 static void spi_deregister_controller_key_listener (SpiDEController *controller,
124 DEControllerKeyListener *key_listener,
125 CORBA_Environment *ev);
126 static gboolean spi_controller_notify_mouselisteners (SpiDEController *controller,
127 const Accessibility_DeviceEvent *event,
128 CORBA_Environment *ev);
130 static gboolean spi_eventtype_seq_contains_event (Accessibility_EventTypeSeq *type_seq,
131 const Accessibility_DeviceEvent *event);
132 static gboolean spi_clear_error_state (void);
133 static gboolean spi_dec_poll_mouse_moved (gpointer data);
134 static gboolean spi_dec_poll_mouse_moving (gpointer data);
135 static gboolean spi_dec_poll_mouse_idle (gpointer data);
137 #define spi_get_display() GDK_DISPLAY()
139 /* Private methods */
142 keycode_for_keysym (long keysym)
144 return XKeysymToKeycode (spi_get_display (), (KeySym) keysym);
147 #define SPI_DEC_MAX_SHIFT_KEYSYMS 15
148 static long _shift_keysyms[SPI_DEC_MAX_SHIFT_KEYSYMS] =
149 {XK_Shift_L, XK_Shift_R,
150 XK_Control_L, XK_Control_R,
151 XK_Caps_Lock, XK_Shift_Lock,
153 XK_Meta_L, XK_Meta_R,
154 XK_Super_L, XK_Super_R,
155 XK_Hyper_L, XK_Hyper_R,
159 spi_keycodes_contain (KeyCode keycodes[], KeyCode keycode)
165 while (i < SPI_DEC_MAX_SHIFT_KEYSYMS)
167 if (keycodes[i] == keycode)
176 spi_dec_init_keycode_list (SpiDEController *controller)
178 DEControllerPrivateData *priv =
179 g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
182 priv->shift_keycodes = g_malloc (sizeof (KeyCode) *
183 SPI_DEC_MAX_SHIFT_KEYSYMS);
184 for (i = 0; _shift_keysyms[i] != 0; ++i)
186 keycode = keycode_for_keysym (_shift_keysyms [i]);
187 priv->shift_keycodes [i] = keycode;
189 priv->shift_keycodes [i] = 0; /* terminate the list */
192 static DEControllerGrabMask *
193 spi_grab_mask_clone (DEControllerGrabMask *grab_mask)
195 DEControllerGrabMask *clone = g_new (DEControllerGrabMask, 1);
197 memcpy (clone, grab_mask, sizeof (DEControllerGrabMask));
199 clone->ref_count = 1;
200 clone->pending_add = TRUE;
201 clone->pending_remove = FALSE;
207 spi_grab_mask_free (DEControllerGrabMask *grab_mask)
213 spi_grab_mask_compare_values (gconstpointer p1, gconstpointer p2)
215 DEControllerGrabMask *l1 = (DEControllerGrabMask *) p1;
216 DEControllerGrabMask *l2 = (DEControllerGrabMask *) p2;
224 return ((l1->mod_mask != l2->mod_mask) || (l1->key_val != l2->key_val));
229 spi_dec_set_unlatch_pending (SpiDEController *controller, unsigned mask)
231 DEControllerPrivateData *priv =
232 g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
234 if (priv->xkb_latch_mask) fprintf (stderr, "unlatch pending! %x\n", mask);
236 priv->pending_xkb_mod_relatch_mask |= priv->xkb_latch_mask;
239 static gint poll_count = 0;
242 spi_dec_button_update_and_emit (SpiDEController *controller,
245 CORBA_Environment ev;
246 Accessibility_Event e;
247 Accessibility_DeviceEvent mouse_e;
248 gchar event_name[24];
249 gboolean is_consumed = FALSE;
251 if ((mask_return & mouse_button_mask) !=
252 (mouse_mask_state & mouse_button_mask))
254 int button_number = 0;
255 gboolean is_down = False;
257 if (!(mask_return & Button1Mask) &&
258 (mouse_mask_state & Button1Mask))
260 mouse_mask_state &= ~Button1Mask;
263 else if ((mask_return & Button1Mask) &&
264 !(mouse_mask_state & Button1Mask))
266 mouse_mask_state |= Button1Mask;
270 else if (!(mask_return & Button2Mask) &&
271 (mouse_mask_state & Button2Mask))
273 mouse_mask_state &= ~Button2Mask;
276 else if ((mask_return & Button2Mask) &&
277 !(mouse_mask_state & Button2Mask))
279 mouse_mask_state |= Button2Mask;
283 else if (!(mask_return & Button3Mask) &&
284 (mouse_mask_state & Button3Mask))
286 mouse_mask_state &= ~Button3Mask;
289 else if ((mask_return & Button3Mask) &&
290 !(mouse_mask_state & Button3Mask))
292 mouse_mask_state |= Button3Mask;
296 else if (!(mask_return & Button4Mask) &&
297 (mouse_mask_state & Button1Mask))
299 mouse_mask_state &= ~Button4Mask;
302 else if ((mask_return & Button4Mask) &&
303 !(mouse_mask_state & Button1Mask))
305 mouse_mask_state |= Button4Mask;
309 else if (!(mask_return & Button5Mask) &&
310 (mouse_mask_state & Button5Mask))
312 mouse_mask_state &= ~Button5Mask;
315 else if ((mask_return & Button5Mask) &&
316 !(mouse_mask_state & Button5Mask))
318 mouse_mask_state |= Button5Mask;
324 fprintf (stderr, "Button %d %s\n",
325 button_number, (is_down) ? "Pressed" : "Released");
327 snprintf (event_name, 22, "mouse:button:%d%c", button_number,
328 (is_down) ? 'p' : 'r');
329 /* TODO: distinguish between physical and
332 mouse_e.type = (is_down) ?
333 Accessibility_BUTTON_PRESSED_EVENT :
334 Accessibility_BUTTON_RELEASED_EVENT;
335 mouse_e.id = button_number;
336 mouse_e.hw_code = button_number;
337 mouse_e.modifiers = (CORBA_unsigned_short) mouse_mask_state;
338 mouse_e.timestamp = 0;
339 mouse_e.event_string = "";
340 mouse_e.is_text = CORBA_FALSE;
342 spi_controller_notify_mouselisteners (controller,
346 e.source = BONOBO_OBJREF (controller->registry->desktop);
347 e.detail1 = last_mouse_pos->x;
348 e.detail2 = last_mouse_pos->y;
349 spi_init_any_nil (&e.any_data);
350 CORBA_exception_init (&ev);
353 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry),
358 spi_dec_set_unlatch_pending (controller, mask_return);
370 spi_dec_mouse_check (SpiDEController *controller,
371 int *x, int *y, gboolean *moved)
373 Accessibility_Event e;
374 CORBA_Environment ev;
375 int win_x_return,win_y_return;
376 int poll_count_modulus = 10;
377 unsigned int mask_return;
378 Window root_return, child_return;
379 Display *display = spi_get_display ();
382 XQueryPointer(display, DefaultRootWindow (display),
383 &root_return, &child_return,
385 &win_x_return, &win_y_return, &mask_return);
387 * Since many clients grab the pointer, and X goes an automatic
388 * pointer grab on mouse-down, we often must detect mouse button events
389 * by polling rather than via a button grab.
390 * The while loop (rather than if) is used since it's possible that
391 * multiple buttons have changed state since we last checked.
393 if (mask_return != mouse_mask_state)
395 while (spi_dec_button_update_and_emit (controller, mask_return));
398 if (poll_count++ == poll_count_modulus) {
400 e.type = "mouse:abs";
401 e.source = BONOBO_OBJREF (controller->registry->desktop);
404 spi_init_any_nil (&e.any_data);
405 CORBA_exception_init (&ev);
406 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry),
410 if (*x != last_mouse_pos->x || *y != last_mouse_pos->y)
412 e.type = "mouse:rel";
413 e.source = BONOBO_OBJREF (controller->registry->desktop);
414 e.detail1 = *x - last_mouse_pos->x;
415 e.detail2 = *y - last_mouse_pos->y;
416 spi_init_any_nil (&e.any_data);
417 CORBA_exception_init (&ev);
418 last_mouse_pos->x = *x;
419 last_mouse_pos->y = *y;
420 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry),
434 spi_dec_emit_modifier_event (SpiDEController *controller, guint prev_mask,
437 Accessibility_Event e;
438 CORBA_Environment ev;
441 fprintf (stderr, "MODIFIER CHANGE EVENT! %x to %x\n",
442 prev_mask, current_mask);
444 e.type = "keyboard:modifiers";
445 e.source = BONOBO_OBJREF (controller->registry->desktop);
446 e.detail1 = prev_mask & key_modifier_mask;
447 e.detail2 = current_mask & key_modifier_mask;
448 spi_init_any_nil (&e.any_data);
449 CORBA_exception_init (&ev);
450 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry),
456 spi_dec_poll_mouse_moved (gpointer data)
458 SpiRegistry *registry = SPI_REGISTRY (data);
459 SpiDEController *controller = registry->de_controller;
464 mask_return = spi_dec_mouse_check (controller, &x, &y, &moved);
466 if ((mask_return & key_modifier_mask) !=
467 (mouse_mask_state & key_modifier_mask))
469 spi_dec_emit_modifier_event (controller, mouse_mask_state, mask_return);
470 mouse_mask_state = mask_return;
477 spi_dec_poll_mouse_idle (gpointer data)
479 if (! spi_dec_poll_mouse_moved (data))
483 g_timeout_add (20, spi_dec_poll_mouse_moving, data);
489 spi_dec_poll_mouse_moving (gpointer data)
491 if (spi_dec_poll_mouse_moved (data))
495 g_timeout_add (100, spi_dec_poll_mouse_idle, data);
501 spi_dec_ungrab_mouse (gpointer data)
503 Display *display = spi_get_display ();
506 XUngrabButton (spi_get_display (), AnyButton, AnyModifier,
507 XDefaultRootWindow (spi_get_display ()));
513 spi_dec_init_mouse_listener (SpiRegistry *registry)
515 Display *display = spi_get_display ();
516 g_timeout_add (100, spi_dec_poll_mouse_idle, registry);
520 XGrabButton (display, AnyButton, AnyModifier,
521 gdk_x11_get_default_root_xwindow (),
522 True, ButtonPressMask | ButtonReleaseMask,
523 GrabModeSync, GrabModeAsync, None, None);
524 XSync (display, False);
526 fprintf (stderr, "mouse buttons grabbed\n");
531 static DEControllerKeyListener *
532 spi_dec_key_listener_new (CORBA_Object l,
533 const Accessibility_KeySet *keys,
534 const Accessibility_ControllerEventMask mask,
535 const Accessibility_EventTypeSeq *typeseq,
536 const Accessibility_EventListenerMode *mode,
537 CORBA_Environment *ev)
539 DEControllerKeyListener *key_listener = g_new0 (DEControllerKeyListener, 1);
540 key_listener->listener.object = bonobo_object_dup_ref (l, ev);
541 key_listener->listener.type = SPI_DEVICE_TYPE_KBD;
542 key_listener->keys = ORBit_copy_value (keys, TC_Accessibility_KeySet);
543 key_listener->mask = mask;
544 key_listener->listener.typeseq = ORBit_copy_value (typeseq, TC_Accessibility_EventTypeSeq);
546 key_listener->mode = ORBit_copy_value (mode, TC_Accessibility_EventListenerMode);
548 key_listener->mode = NULL;
551 g_print ("new listener, with mask %x, is_global %d, keys %p (%d)\n",
552 (unsigned int) key_listener->mask,
553 (int) (mode ? mode->global : 0),
554 (void *) key_listener->keys,
555 (int) (key_listener->keys ? key_listener->keys->_length : 0));
561 static DEControllerListener *
562 spi_dec_listener_new (CORBA_Object l,
563 const Accessibility_EventTypeSeq *typeseq,
564 CORBA_Environment *ev)
566 DEControllerListener *listener = g_new0 (DEControllerListener, 1);
567 listener->object = bonobo_object_dup_ref (l, ev);
568 listener->type = SPI_DEVICE_TYPE_MOUSE;
569 listener->typeseq = ORBit_copy_value (typeseq, TC_Accessibility_EventTypeSeq);
573 static DEControllerListener *
574 spi_listener_clone (DEControllerListener *listener, CORBA_Environment *ev)
576 DEControllerListener *clone = g_new0 (DEControllerListener, 1);
578 CORBA_Object_duplicate (listener->object, ev);
579 clone->type = listener->type;
580 clone->typeseq = ORBit_copy_value (listener->typeseq, TC_Accessibility_EventTypeSeq);
584 static DEControllerKeyListener *
585 spi_key_listener_clone (DEControllerKeyListener *key_listener, CORBA_Environment *ev)
587 DEControllerKeyListener *clone = g_new0 (DEControllerKeyListener, 1);
588 clone->listener.object =
589 CORBA_Object_duplicate (key_listener->listener.object, ev);
590 clone->listener.type = SPI_DEVICE_TYPE_KBD;
591 clone->keys = ORBit_copy_value (key_listener->keys, TC_Accessibility_KeySet);
592 clone->mask = key_listener->mask;
593 clone->listener.typeseq = ORBit_copy_value (key_listener->listener.typeseq, TC_Accessibility_EventTypeSeq);
594 if (key_listener->mode)
595 clone->mode = ORBit_copy_value (key_listener->mode, TC_Accessibility_EventListenerMode);
602 spi_key_listener_data_free (DEControllerKeyListener *key_listener, CORBA_Environment *ev)
604 CORBA_free (key_listener->listener.typeseq);
605 CORBA_free (key_listener->keys);
606 g_free (key_listener);
610 spi_key_listener_clone_free (DEControllerKeyListener *clone, CORBA_Environment *ev)
612 CORBA_Object_release (clone->listener.object, ev);
613 spi_key_listener_data_free (clone, ev);
617 spi_listener_clone_free (DEControllerListener *clone, CORBA_Environment *ev)
619 CORBA_Object_release (clone->object, ev);
620 CORBA_free (clone->typeseq);
625 spi_dec_listener_free (DEControllerListener *listener,
626 CORBA_Environment *ev)
628 bonobo_object_release_unref (listener->object, ev);
629 if (listener->type == SPI_DEVICE_TYPE_KBD)
630 spi_key_listener_data_free ((DEControllerKeyListener *) listener, ev);
634 _register_keygrab (SpiDEController *controller,
635 DEControllerGrabMask *grab_mask)
639 l = g_list_find_custom (controller->keygrabs_list, grab_mask,
640 spi_grab_mask_compare_values);
643 DEControllerGrabMask *cur_mask = l->data;
645 cur_mask->ref_count++;
646 if (cur_mask->pending_remove)
648 cur_mask->pending_remove = FALSE;
653 controller->keygrabs_list =
654 g_list_prepend (controller->keygrabs_list,
655 spi_grab_mask_clone (grab_mask));
660 _deregister_keygrab (SpiDEController *controller,
661 DEControllerGrabMask *grab_mask)
665 l = g_list_find_custom (controller->keygrabs_list, grab_mask,
666 spi_grab_mask_compare_values);
670 DEControllerGrabMask *cur_mask = l->data;
672 cur_mask->ref_count--;
673 if (cur_mask->ref_count <= 0)
675 cur_mask->pending_remove = TRUE;
680 DBG (1, g_warning ("De-registering non-existant grab"));
685 handle_keygrab (SpiDEController *controller,
686 DEControllerKeyListener *key_listener,
687 void (*process_cb) (SpiDEController *controller,
688 DEControllerGrabMask *grab_mask))
690 DEControllerGrabMask grab_mask = { 0 };
692 grab_mask.mod_mask = key_listener->mask;
693 if (key_listener->keys->_length == 0) /* special case means AnyKey/AllKeys */
695 grab_mask.key_val = AnyKey;
697 fprintf (stderr, "AnyKey grab!");
699 process_cb (controller, &grab_mask);
705 for (i = 0; i < key_listener->keys->_length; ++i)
707 Accessibility_KeyDefinition keydef = key_listener->keys->_buffer[i];
708 long int key_val = keydef.keysym;
709 /* X Grabs require keycodes, not keysyms */
710 if (keydef.keystring && keydef.keystring[0])
712 key_val = XStringToKeysym(keydef.keystring);
716 key_val = XKeysymToKeycode (spi_get_display (), (KeySym) key_val);
720 key_val = keydef.keycode;
722 grab_mask.key_val = key_val;
723 process_cb (controller, &grab_mask);
729 spi_controller_register_global_keygrabs (SpiDEController *controller,
730 DEControllerKeyListener *key_listener)
732 handle_keygrab (controller, key_listener, _register_keygrab);
733 return spi_controller_update_key_grabs (controller, NULL);
737 spi_controller_deregister_global_keygrabs (SpiDEController *controller,
738 DEControllerKeyListener *key_listener)
740 handle_keygrab (controller, key_listener, _deregister_keygrab);
741 spi_controller_update_key_grabs (controller, NULL);
745 spi_controller_register_device_listener (SpiDEController *controller,
746 DEControllerListener *listener,
747 CORBA_Environment *ev)
749 DEControllerKeyListener *key_listener;
751 switch (listener->type) {
752 case SPI_DEVICE_TYPE_KBD:
753 key_listener = (DEControllerKeyListener *) listener;
755 controller->key_listeners = g_list_prepend (controller->key_listeners,
757 if (key_listener->mode->global)
759 return spi_controller_register_global_keygrabs (controller, key_listener);
764 case SPI_DEVICE_TYPE_MOUSE:
765 controller->mouse_listeners = g_list_prepend (controller->mouse_listeners, listener);
768 DBG (1, g_warning ("listener registration for unknown device type.\n"));
775 spi_controller_notify_mouselisteners (SpiDEController *controller,
776 const Accessibility_DeviceEvent *event,
777 CORBA_Environment *ev)
780 GSList *notify = NULL, *l2;
781 GList **listeners = &controller->mouse_listeners;
782 gboolean is_consumed;
789 for (l = *listeners; l; l = l->next)
791 DEControllerListener *listener = l->data;
793 if (spi_eventtype_seq_contains_event (listener->typeseq, event))
795 Accessibility_DeviceEventListener ls = listener->object;
797 if (ls != CORBA_OBJECT_NIL)
799 /* we clone (don't dup) the listener, to avoid refcount inc. */
800 notify = g_slist_prepend (notify,
801 spi_listener_clone (listener, ev));
806 #ifdef SPI_KEYEVENT_DEBUG
809 g_print ("no match for event\n");
814 for (l2 = notify; l2 && !is_consumed; l2 = l2->next)
816 DEControllerListener *listener = l2->data;
817 Accessibility_DeviceEventListener ls = listener->object;
819 CORBA_exception_init (ev);
820 is_consumed = Accessibility_DeviceEventListener_notifyEvent (ls, event, ev);
824 DBG (2, g_warning ("error notifying listener, removing it\n"));
825 spi_deregister_controller_device_listener (controller, listener,
827 CORBA_exception_free (ev);
830 spi_listener_clone_free ((DEControllerListener *) l2->data, ev);
833 for (; l2; l2 = l2->next)
835 DEControllerListener *listener = l2->data;
836 spi_listener_clone_free (listener, ev);
837 /* clone doesn't have its own ref, so don't use spi_device_listener_free */
840 g_slist_free (notify);
843 if (is_consumed) g_message ("consumed\n");
849 spi_device_event_controller_forward_mouse_event (SpiDEController *controller,
852 Accessibility_Event e;
853 Accessibility_DeviceEvent mouse_e;
854 CORBA_Environment ev;
855 gchar event_name[24];
856 gboolean is_consumed = FALSE;
857 gboolean xkb_mod_unlatch_occurred;
858 XButtonEvent *xbutton_event = (XButtonEvent *) xevent;
860 int button = xbutton_event->button;
862 unsigned int mouse_button_state = xbutton_event->state;
867 mouse_button_state |= Button1Mask;
870 mouse_button_state |= Button2Mask;
873 mouse_button_state |= Button3Mask;
876 mouse_button_state |= Button4Mask;
879 mouse_button_state |= Button5Mask;
883 last_mouse_pos->x = ((XButtonEvent *) xevent)->x_root;
884 last_mouse_pos->y = ((XButtonEvent *) xevent)->y_root;
887 fprintf (stderr, "mouse button %d %s (%x)\n",
888 xbutton_event->button,
889 (xevent->type == ButtonPress) ? "Press" : "Release",
892 snprintf (event_name, 22, "mouse:button:%d%c", button,
893 (xevent->type == ButtonPress) ? 'p' : 'r');
895 /* TODO: distinguish between physical and logical buttons */
896 mouse_e.type = (xevent->type == ButtonPress) ?
897 Accessibility_BUTTON_PRESSED_EVENT :
898 Accessibility_BUTTON_RELEASED_EVENT;
900 mouse_e.hw_code = button;
901 mouse_e.modifiers = (CORBA_unsigned_short) xbutton_event->state;
902 mouse_e.timestamp = (CORBA_unsigned_long) xbutton_event->time;
903 mouse_e.event_string = "";
904 mouse_e.is_text = CORBA_FALSE;
905 if ((mouse_button_state & mouse_button_mask) !=
906 (mouse_mask_state & mouse_button_mask))
908 if ((mouse_mask_state & key_modifier_mask) !=
909 (mouse_button_state & key_modifier_mask))
910 spi_dec_emit_modifier_event (controller,
911 mouse_mask_state, mouse_button_state);
912 mouse_mask_state = mouse_button_state;
914 spi_controller_notify_mouselisteners (controller, &mouse_e, &ev);
915 e.type = CORBA_string_dup (event_name);
916 e.source = BONOBO_OBJREF (controller->registry->desktop);
917 e.detail1 = last_mouse_pos->x;
918 e.detail2 = last_mouse_pos->y;
919 spi_init_any_nil (&e.any_data);
920 CORBA_exception_init (&ev);
922 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry),
927 xkb_mod_unlatch_occurred = (xevent->type == ButtonPress ||
928 xevent->type == ButtonRelease);
930 /* if client wants to consume this event, and XKB latch state was
931 * unset by this button event, we reset it
933 if (is_consumed && (xkb_mod_unlatch_occurred))
934 spi_dec_set_unlatch_pending (controller, mouse_mask_state);
936 XAllowEvents (spi_get_display (),
937 (is_consumed) ? SyncPointer : ReplayPointer,
941 static GdkFilterReturn
942 global_filter_fn (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
944 XEvent *xevent = gdk_xevent;
945 SpiDEController *controller;
946 DEControllerPrivateData *priv;
947 Display *display = spi_get_display ();
948 controller = SPI_DEVICE_EVENT_CONTROLLER (data);
949 priv = (DEControllerPrivateData *)
950 g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
952 if (xevent->type == KeyPress || xevent->type == KeyRelease)
954 spi_device_event_controller_forward_key_event (controller, xevent);
955 return GDK_FILTER_CONTINUE;
957 if (xevent->type == ButtonPress || xevent->type == ButtonRelease)
959 spi_device_event_controller_forward_mouse_event (controller, xevent);
961 if (xevent->type == priv->xkb_base_event_code)
963 XkbAnyEvent * xkb_ev = (XkbAnyEvent *) xevent;
964 /* ugly but probably necessary...*/
965 XSynchronize (spi_get_display (), TRUE);
967 if (xkb_ev->xkb_type == XkbStateNotify)
969 XkbStateNotifyEvent *xkb_snev =
970 (XkbStateNotifyEvent *) xkb_ev;
971 /* check the mouse, to catch mouse events grabbed by
972 * another client; in case we should revert this XKB delatch
974 if (!priv->pending_xkb_mod_relatch_mask)
978 spi_dec_mouse_check (controller, &x, &y, &moved);
980 /* we check again, since the previous call may have
982 if (priv->pending_xkb_mod_relatch_mask)
984 unsigned int feedback_mask;
986 fprintf (stderr, "relatching %x\n",
987 priv->pending_xkb_mod_relatch_mask);
989 /* temporarily turn off the latch bell, if it's on */
990 XkbGetControls (display,
991 XkbAccessXFeedbackMask,
993 feedback_mask = priv->xkb_desc->ctrls->ax_options;
994 if (feedback_mask & XkbAX_StickyKeysFBMask)
996 XkbControlsChangesRec changes = {XkbAccessXFeedbackMask,
998 priv->xkb_desc->ctrls->ax_options
999 &= ~(XkbAX_StickyKeysFBMask);
1000 XkbChangeControls (display, priv->xkb_desc, &changes);
1002 XkbLatchModifiers (display,
1004 priv->pending_xkb_mod_relatch_mask,
1005 priv->pending_xkb_mod_relatch_mask);
1006 if (feedback_mask & XkbAX_StickyKeysFBMask)
1008 XkbControlsChangesRec changes = {XkbAccessXFeedbackMask,
1010 priv->xkb_desc->ctrls->ax_options = feedback_mask;
1011 XkbChangeControls (display, priv->xkb_desc, &changes);
1013 #ifdef SPI_XKB_DEBUG
1014 fprintf (stderr, "relatched %x\n",
1015 priv->pending_xkb_mod_relatch_mask);
1017 priv->pending_xkb_mod_relatch_mask = 0;
1021 priv->xkb_latch_mask = xkb_snev->latched_mods;
1025 DBG (2, g_warning ("XKB event %d\n", xkb_ev->xkb_type));
1026 XSynchronize (spi_get_display (), FALSE);
1029 return GDK_FILTER_CONTINUE;
1033 _spi_controller_device_error_handler (Display *display, XErrorEvent *error)
1035 if (error->error_code == BadAccess)
1037 g_message ("Could not complete key grab: grab already in use.\n");
1038 spi_error_code = BadAccess;
1043 return (*x_default_error_handler) (display, error);
1048 spi_controller_register_with_devices (SpiDEController *controller)
1050 DEControllerPrivateData *priv = (DEControllerPrivateData *)
1051 g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
1052 /* FIXME: should check for extension first! */
1053 XTestGrabControl (spi_get_display (), True);
1054 priv->xkb_desc = XkbGetMap (spi_get_display (), 0, XkbUseCoreKbd);
1056 /* calls to device-specific implementations and routines go here */
1057 /* register with: keyboard hardware code handler */
1058 /* register with: (translated) keystroke handler */
1060 priv->have_xkb = XkbQueryExtension (spi_get_display (),
1061 &priv->xkb_major_extension_opcode,
1062 &priv->xkb_base_event_code,
1063 &priv->xkb_base_error_code, NULL, NULL);
1066 XkbSelectEvents (spi_get_display (),
1068 XkbStateNotifyMask, XkbStateNotifyMask);
1070 gdk_window_add_filter (NULL, global_filter_fn, controller);
1072 gdk_window_set_events (gdk_get_default_root_window (),
1073 GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
1075 x_default_error_handler = XSetErrorHandler (_spi_controller_device_error_handler);
1079 spi_key_set_contains_key (Accessibility_KeySet *key_set,
1080 const Accessibility_DeviceEvent *key_event)
1087 g_print ("null key set!");
1091 len = key_set->_length;
1093 if (len == 0) /* special case, means "all keys/any key" */
1095 g_print ("anykey\n");
1099 for (i = 0; i < len; ++i)
1101 #ifdef SPI_KEYEVENT_DEBUG
1102 g_print ("key_set[%d] = %d; key_event %d, code %d, string %s\n",
1103 i, (int) key_set->_buffer[i].keycode,
1104 (int) key_event->id, (int) key_event->hw_code,
1105 key_event->event_string);
1107 if (key_set->_buffer[i].keysym == (CORBA_long) key_event->id)
1111 if (key_set->_buffer[i].keycode == (CORBA_long) key_event->hw_code)
1115 if (key_event->event_string && key_event->event_string[0] &&
1116 !strcmp (key_set->_buffer[i].keystring, key_event->event_string))
1126 spi_eventtype_seq_contains_event (Accessibility_EventTypeSeq *type_seq,
1127 const Accessibility_DeviceEvent *event)
1135 g_print ("null type seq!");
1139 len = type_seq->_length;
1141 if (len == 0) /* special case, means "all events/any event" */
1146 for (i = 0; i < len; ++i)
1149 g_print ("type_seq[%d] = %d; event type = %d\n", i,
1150 (int) type_seq->_buffer[i], (int) event->type);
1152 if (type_seq->_buffer[i] == (CORBA_long) event->type)
1162 spi_key_event_matches_listener (const Accessibility_DeviceEvent *key_event,
1163 DEControllerKeyListener *listener,
1164 CORBA_boolean is_system_global)
1166 if ((key_event->modifiers == (CORBA_unsigned_short) (listener->mask & 0xFFFF)) &&
1167 spi_key_set_contains_key (listener->keys, key_event) &&
1168 spi_eventtype_seq_contains_event (listener->listener.typeseq, key_event) &&
1169 (is_system_global == listener->mode->global))
1180 spi_controller_notify_keylisteners (SpiDEController *controller,
1181 const Accessibility_DeviceEvent *key_event,
1182 CORBA_boolean is_system_global,
1183 CORBA_Environment *ev)
1186 GSList *notify = NULL, *l2;
1187 GList **key_listeners = &controller->key_listeners;
1188 gboolean is_consumed;
1195 for (l = *key_listeners; l; l = l->next)
1197 DEControllerKeyListener *key_listener = l->data;
1199 if (spi_key_event_matches_listener (key_event, key_listener, is_system_global))
1201 Accessibility_DeviceEventListener ls = key_listener->listener.object;
1203 if (ls != CORBA_OBJECT_NIL)
1205 /* we clone (don't dup) the listener, to avoid refcount inc. */
1206 notify = g_slist_prepend (notify,
1207 spi_key_listener_clone (key_listener, ev));
1212 #ifdef SPI_KEYEVENT_DEBUG
1215 g_print ("no match for event\n");
1219 is_consumed = FALSE;
1220 for (l2 = notify; l2 && !is_consumed; l2 = l2->next)
1222 DEControllerKeyListener *key_listener = l2->data;
1223 Accessibility_DeviceEventListener ls = key_listener->listener.object;
1225 is_consumed = Accessibility_DeviceEventListener_notifyEvent (ls, key_event, ev);
1229 is_consumed = FALSE;
1230 spi_deregister_controller_key_listener (controller, key_listener,
1232 CORBA_exception_free (ev);
1235 spi_key_listener_clone_free (key_listener, ev);
1238 for (; l2; l2 = l2->next)
1240 DEControllerKeyListener *key_listener = l2->data;
1241 spi_key_listener_clone_free (key_listener, ev);
1242 /* clone doesn't have its own ref, so don't use spi_dec_listener_free */
1245 g_slist_free (notify);
1248 if (is_consumed) g_message ("consumed\n");
1254 spi_clear_error_state ()
1256 gboolean retval = spi_error_code != 0;
1261 static Accessibility_DeviceEvent
1262 spi_keystroke_from_x_key_event (XKeyEvent *x_key_event)
1264 Accessibility_DeviceEvent key_event;
1266 const int cbuf_bytes = 20;
1267 char cbuf [cbuf_bytes];
1269 keysym = XLookupKeysym (x_key_event, 0);
1270 key_event.id = (CORBA_long)(keysym);
1271 key_event.hw_code = (CORBA_short) x_key_event->keycode;
1272 if (((XEvent *) x_key_event)->type == KeyPress)
1274 key_event.type = Accessibility_KEY_PRESSED;
1278 key_event.type = Accessibility_KEY_RELEASED;
1280 key_event.modifiers = (CORBA_unsigned_short)(x_key_event->state);
1281 key_event.is_text = CORBA_FALSE;
1285 key_event.event_string = CORBA_string_dup ("space");
1288 #ifdef SPI_KEYEVENT_DEBUG
1289 fprintf(stderr, "Tab\n");
1291 key_event.event_string = CORBA_string_dup ("Tab");
1294 key_event.event_string = CORBA_string_dup ("Backspace");
1297 key_event.event_string = CORBA_string_dup ("Return");
1300 key_event.event_string = CORBA_string_dup ("Home");
1303 key_event.event_string = CORBA_string_dup ("Page_Down");
1306 key_event.event_string = CORBA_string_dup ("Page_Up");
1309 key_event.event_string = CORBA_string_dup ("F1");
1312 key_event.event_string = CORBA_string_dup ("F2");
1315 key_event.event_string = CORBA_string_dup ("F3");
1318 key_event.event_string = CORBA_string_dup ("F4");
1321 key_event.event_string = CORBA_string_dup ("F5");
1324 key_event.event_string = CORBA_string_dup ("F6");
1327 key_event.event_string = CORBA_string_dup ("F7");
1330 key_event.event_string = CORBA_string_dup ("F8");
1333 key_event.event_string = CORBA_string_dup ("F9");
1336 key_event.event_string = CORBA_string_dup ("F10");
1339 key_event.event_string = CORBA_string_dup ("F11");
1342 key_event.event_string = CORBA_string_dup ("F12");
1345 key_event.event_string = CORBA_string_dup ("End");
1348 key_event.event_string = CORBA_string_dup ("Escape");
1351 key_event.event_string = CORBA_string_dup ("Up");
1354 key_event.event_string = CORBA_string_dup ("Down");
1357 key_event.event_string = CORBA_string_dup ("Left");
1360 key_event.event_string = CORBA_string_dup ("Right");
1363 if (XLookupString (x_key_event, cbuf, cbuf_bytes, &keysym, NULL) > 0)
1365 key_event.event_string = CORBA_string_dup (cbuf);
1366 if (isgraph (keysym))
1368 key_event.is_text = CORBA_TRUE; /* FIXME: incorrect for some composed chars? */
1373 key_event.event_string = CORBA_string_dup ("");
1377 key_event.timestamp = (CORBA_unsigned_long) x_key_event->time;
1378 #ifdef SPI_KEYEVENT_DEBUG
1380 "Key %lu pressed (%c), modifiers %d\n",
1381 (unsigned long) keysym,
1382 keysym ? (int) keysym : '*',
1383 (int) x_key_event->state);
1386 fprintf (stderr, "%s%c",
1387 (x_key_event->state & Mod1Mask)?"Alt-":"",
1388 ((x_key_event->state & ShiftMask)^(x_key_event->state & LockMask))?
1389 g_ascii_toupper (keysym) : g_ascii_tolower (keysym));
1390 #endif /* SPI_DEBUG */
1395 spi_controller_update_key_grabs (SpiDEController *controller,
1396 Accessibility_DeviceEvent *recv)
1399 gboolean update_failed = FALSE;
1401 g_return_val_if_fail (controller != NULL, FALSE);
1404 * masks known to work with default RH 7.1+:
1405 * 0 (no mods), LockMask, Mod1Mask, Mod2Mask, ShiftMask,
1406 * ShiftMask|LockMask, Mod1Mask|LockMask, Mod2Mask|LockMask,
1407 * ShiftMask|Mod1Mask, ShiftMask|Mod2Mask, Mod1Mask|Mod2Mask,
1408 * ShiftMask|LockMask|Mod1Mask, ShiftMask|LockMask|Mod2Mask,
1410 * ControlMask grabs are broken, must be in use already
1412 for (l = controller->keygrabs_list; l; l = next)
1415 gboolean re_issue_grab;
1416 DEControllerGrabMask *grab_mask = l->data;
1420 re_issue_grab = recv &&
1421 /* (recv->type == Accessibility_KEY_RELEASED) && - (?) */
1422 (recv->modifiers & grab_mask->mod_mask) &&
1423 (grab_mask->key_val == keycode_for_keysym (recv->id));
1426 fprintf (stderr, "mask=%lx %lx (%c%c) %s\n",
1427 (long int) grab_mask->key_val,
1428 (long int) grab_mask->mod_mask,
1429 grab_mask->pending_add ? '+' : '.',
1430 grab_mask->pending_remove ? '-' : '.',
1431 re_issue_grab ? "re-issue": "");
1436 if (grab_mask->pending_add && grab_mask->pending_remove)
1440 else if (grab_mask->pending_remove)
1443 fprintf (stderr, "ungrabbing, mask=%x\n", grab_mask->mod_mask);
1445 XUngrabKey (spi_get_display (),
1447 grab_mask->mod_mask,
1448 gdk_x11_get_default_root_xwindow ());
1452 else if (grab_mask->pending_add || re_issue_grab)
1456 fprintf (stderr, "grab %d with mask %x\n", grab_mask->key_val, grab_mask->mod_mask);
1458 XGrabKey (spi_get_display (),
1460 grab_mask->mod_mask,
1461 gdk_x11_get_default_root_xwindow (),
1465 XSync (spi_get_display (), False);
1466 update_failed = spi_clear_error_state ();
1467 if (update_failed) {
1468 while (grab_mask->ref_count > 0) --grab_mask->ref_count;
1473 grab_mask->pending_add = FALSE;
1474 grab_mask->pending_remove = FALSE;
1478 g_assert (grab_mask->ref_count <= 0);
1480 controller->keygrabs_list = g_list_delete_link (
1481 controller->keygrabs_list, l);
1483 spi_grab_mask_free (grab_mask);
1488 return ! update_failed;
1492 * Implemented GObject::finalize
1495 spi_device_event_controller_object_finalize (GObject *object)
1497 SpiDEController *controller;
1498 DEControllerPrivateData *private;
1499 controller = SPI_DEVICE_EVENT_CONTROLLER (object);
1502 fprintf(stderr, "spi_device_event_controller_object_finalize called\n");
1504 /* disconnect any special listeners, get rid of outstanding keygrabs */
1505 XUngrabKey (spi_get_display (), AnyKey, AnyModifier, DefaultRootWindow (spi_get_display ()));
1507 private = g_object_get_data (G_OBJECT (controller), "spi-dec-private");
1508 if (private->xkb_desc)
1509 XkbFreeKeyboard (private->xkb_desc, 0, True);
1511 spi_device_event_controller_parent_class->finalize (object);
1515 * CORBA Accessibility::DEController::registerKeystrokeListener
1516 * method implementation
1518 static CORBA_boolean
1519 impl_register_keystroke_listener (PortableServer_Servant servant,
1520 const Accessibility_DeviceEventListener l,
1521 const Accessibility_KeySet *keys,
1522 const Accessibility_ControllerEventMask mask,
1523 const Accessibility_EventTypeSeq *type,
1524 const Accessibility_EventListenerMode *mode,
1525 CORBA_Environment *ev)
1527 SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1528 bonobo_object_from_servant (servant));
1529 DEControllerKeyListener *dec_listener;
1531 fprintf (stderr, "registering keystroke listener %p with maskVal %lu\n",
1532 (void *) l, (unsigned long) mask);
1534 dec_listener = spi_dec_key_listener_new (l, keys, mask, type, mode, ev);
1535 return spi_controller_register_device_listener (
1536 controller, (DEControllerListener *) dec_listener, ev);
1541 * CORBA Accessibility::DEController::registerDeviceEventListener
1542 * method implementation
1544 static CORBA_boolean
1545 impl_register_device_listener (PortableServer_Servant servant,
1546 const Accessibility_DeviceEventListener l,
1547 const Accessibility_EventTypeSeq *event_types,
1548 CORBA_Environment *ev)
1550 SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1551 bonobo_object_from_servant (servant));
1552 DEControllerListener *dec_listener;
1554 dec_listener = spi_dec_listener_new (l, event_types, ev);
1555 return spi_controller_register_device_listener (
1556 controller, (DEControllerListener *) dec_listener, ev);
1560 CORBA_Environment *ev;
1561 DEControllerListener *listener;
1562 } RemoveListenerClosure;
1564 static SpiReEntrantContinue
1565 remove_listener_cb (GList * const *list,
1568 DEControllerListener *listener = (*list)->data;
1569 RemoveListenerClosure *ctx = user_data;
1571 if (CORBA_Object_is_equivalent (ctx->listener->object,
1572 listener->object, ctx->ev))
1574 spi_re_entrant_list_delete_link (list);
1575 spi_dec_listener_free (listener, ctx->ev);
1578 return SPI_RE_ENTRANT_CONTINUE;
1581 static SpiReEntrantContinue
1582 copy_key_listener_cb (GList * const *list,
1585 DEControllerKeyListener *key_listener = (*list)->data;
1586 RemoveListenerClosure *ctx = user_data;
1588 if (CORBA_Object_is_equivalent (ctx->listener->object,
1589 key_listener->listener.object, ctx->ev))
1591 /* TODO: FIXME aggregate keys in case the listener is registered twice */
1592 DEControllerKeyListener *ctx_key_listener =
1593 (DEControllerKeyListener *) ctx->listener;
1594 CORBA_free (ctx_key_listener->keys);
1595 ctx_key_listener->keys = ORBit_copy_value (key_listener->keys, TC_Accessibility_KeySet);
1598 return SPI_RE_ENTRANT_CONTINUE;
1602 spi_deregister_controller_device_listener (SpiDEController *controller,
1603 DEControllerListener *listener,
1604 CORBA_Environment *ev)
1606 RemoveListenerClosure ctx;
1609 ctx.listener = listener;
1611 spi_re_entrant_list_foreach (&controller->mouse_listeners,
1612 remove_listener_cb, &ctx);
1616 spi_deregister_controller_key_listener (SpiDEController *controller,
1617 DEControllerKeyListener *key_listener,
1618 CORBA_Environment *ev)
1620 RemoveListenerClosure ctx;
1623 ctx.listener = (DEControllerListener *) key_listener;
1625 /* special case, copy keyset from existing controller list entry */
1626 if (key_listener->keys->_length == 0)
1628 spi_re_entrant_list_foreach (&controller->key_listeners,
1629 copy_key_listener_cb, &ctx);
1632 spi_controller_deregister_global_keygrabs (controller, key_listener);
1634 spi_re_entrant_list_foreach (&controller->key_listeners,
1635 remove_listener_cb, &ctx);
1640 * CORBA Accessibility::DEController::deregisterKeystrokeListener
1641 * method implementation
1644 impl_deregister_keystroke_listener (PortableServer_Servant servant,
1645 const Accessibility_DeviceEventListener l,
1646 const Accessibility_KeySet *keys,
1647 const Accessibility_ControllerEventMask mask,
1648 const Accessibility_EventTypeSeq *type,
1649 CORBA_Environment *ev)
1651 DEControllerKeyListener *key_listener;
1652 SpiDEController *controller;
1654 controller = SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
1656 key_listener = spi_dec_key_listener_new (l, keys, mask, type, NULL, ev);
1658 #ifdef SPI_DEREGISTER_DEBUG
1659 fprintf (stderr, "deregistering keystroke listener %p with maskVal %lu\n",
1660 (void *) l, (unsigned long) mask->value);
1663 spi_deregister_controller_key_listener (controller, key_listener, ev);
1665 spi_dec_listener_free ((DEControllerListener *) key_listener, ev);
1669 * CORBA Accessibility::DEController::deregisterDeviceEventListener
1670 * method implementation
1673 impl_deregister_device_listener (PortableServer_Servant servant,
1674 const Accessibility_DeviceEventListener l,
1675 const Accessibility_EventTypeSeq *event_types,
1676 CORBA_Environment *ev)
1678 SpiDEController *controller;
1679 DEControllerListener *listener =
1680 spi_dec_listener_new (l, event_types, ev);
1682 controller = SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
1684 spi_deregister_controller_device_listener (controller, listener, ev);
1686 spi_dec_listener_free (listener, ev);
1689 static unsigned int dec_xkb_get_slowkeys_delay (SpiDEController *controller)
1691 unsigned int retval = 0;
1692 DEControllerPrivateData *priv = (DEControllerPrivateData *)
1693 g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
1695 #ifdef XKB_HAS_GET_SLOW_KEYS_DELAY
1696 retval = XkbGetSlowKeysDelay (spi_get_display (),
1697 XkbUseCoreKbd, &bounce_delay);
1699 if (!(priv->xkb_desc == (XkbDescPtr) BadAlloc || priv->xkb_desc == NULL))
1701 Status s = XkbGetControls (spi_get_display (),
1702 XkbAllControlsMask, priv->xkb_desc);
1705 if (priv->xkb_desc->ctrls->enabled_ctrls & XkbSlowKeysMask)
1706 retval = priv->xkb_desc->ctrls->slow_keys_delay;
1711 #ifdef SPI_XKB_DEBUG
1712 fprintf (stderr, "SlowKeys delay: %d\n", (int) retval);
1717 static unsigned int dec_xkb_get_bouncekeys_delay (SpiDEController *controller)
1719 unsigned int retval = 0;
1720 DEControllerPrivateData *priv = (DEControllerPrivateData *)
1721 g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
1723 #ifdef XKB_HAS_GET_BOUNCE_KEYS_DELAY
1724 retval = XkbGetBounceKeysDelay (spi_get_display (),
1725 XkbUseCoreKbd, &bounce_delay);
1727 if (!(priv->xkb_desc == (XkbDescPtr) BadAlloc || priv->xkb_desc == NULL))
1729 Status s = XkbGetControls (spi_get_display (),
1730 XkbAllControlsMask, priv->xkb_desc);
1733 if (priv->xkb_desc->ctrls->enabled_ctrls & XkbBounceKeysMask)
1734 retval = priv->xkb_desc->ctrls->debounce_delay;
1739 #ifdef SPI_XKB_DEBUG
1740 fprintf (stderr, "BounceKeys delay: %d\n", (int) retval);
1746 dec_synth_keycode_press (SpiDEController *controller,
1747 unsigned int keycode)
1749 unsigned int time = CurrentTime;
1750 unsigned int bounce_delay;
1751 unsigned int elapsed_msec;
1753 DEControllerPrivateData *priv =
1754 (DEControllerPrivateData *) g_object_get_qdata (G_OBJECT (controller),
1755 spi_dec_private_quark);
1756 if (keycode == priv->last_release_keycode)
1758 bounce_delay = dec_xkb_get_bouncekeys_delay (controller);
1761 gettimeofday (&tv, NULL);
1763 (tv.tv_sec - priv->last_release_time.tv_sec) * 1000
1764 + (tv.tv_usec - priv->last_release_time.tv_usec) / 1000;
1765 #ifdef SPI_XKB_DEBUG
1766 fprintf (stderr, "%d ms elapsed (%ld usec)\n", elapsed_msec,
1767 (long) (tv.tv_usec - priv->last_release_time.tv_usec));
1769 #ifdef THIS_IS_BROKEN
1770 if (elapsed_msec < bounce_delay)
1771 time = bounce_delay - elapsed_msec + 1;
1773 time = bounce_delay + 10;
1774 /* fudge for broken XTest */
1776 #ifdef SPI_XKB_DEBUG
1777 fprintf (stderr, "waiting %d ms\n", time);
1781 XTestFakeKeyEvent (spi_get_display (), keycode, True, time);
1782 priv->last_press_keycode = keycode;
1783 XSync (spi_get_display (), False);
1784 gettimeofday (&priv->last_press_time, NULL);
1789 dec_synth_keycode_release (SpiDEController *controller,
1790 unsigned int keycode)
1792 unsigned int time = CurrentTime;
1793 unsigned int slow_delay;
1794 unsigned int elapsed_msec;
1796 DEControllerPrivateData *priv =
1797 (DEControllerPrivateData *) g_object_get_qdata (G_OBJECT (controller),
1798 spi_dec_private_quark);
1799 if (keycode == priv->last_press_keycode)
1801 slow_delay = dec_xkb_get_slowkeys_delay (controller);
1804 gettimeofday (&tv, NULL);
1806 (tv.tv_sec - priv->last_press_time.tv_sec) * 1000
1807 + (tv.tv_usec - priv->last_press_time.tv_usec) / 1000;
1808 #ifdef SPI_XKB_DEBUG
1809 fprintf (stderr, "%d ms elapsed (%ld usec)\n", elapsed_msec,
1810 (long) (tv.tv_usec - priv->last_press_time.tv_usec));
1812 #ifdef THIS_IS_BROKEN_DUNNO_WHY
1813 if (elapsed_msec < slow_delay)
1814 time = slow_delay - elapsed_msec + 1;
1816 time = slow_delay + 10;
1817 /* our XTest seems broken, we have to add slop as above */
1819 #ifdef SPI_XKB_DEBUG
1820 fprintf (stderr, "waiting %d ms\n", time);
1824 XTestFakeKeyEvent (spi_get_display (), keycode, False, time);
1825 priv->last_release_keycode = keycode;
1826 XSync (spi_get_display (), False);
1827 gettimeofday (&priv->last_release_time, NULL);
1832 * CORBA Accessibility::DEController::registerKeystrokeListener
1833 * method implementation
1836 impl_generate_keyboard_event (PortableServer_Servant servant,
1837 const CORBA_long keycode,
1838 const CORBA_char *keystring,
1839 const Accessibility_KeySynthType synth_type,
1840 CORBA_Environment *ev)
1842 SpiDEController *controller =
1843 SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
1844 DEControllerPrivateData *priv;
1845 long key_synth_code;
1846 unsigned int slow_keys_delay;
1847 unsigned int press_time;
1848 unsigned int release_time;
1851 fprintf (stderr, "synthesizing keystroke %ld, type %d\n",
1852 (long) keycode, (int) synth_type);
1854 /* TODO: hide/wrap/remove X dependency */
1857 * TODO: when initializing, query for XTest extension before using,
1858 * and fall back to XSendEvent() if XTest is not available.
1861 /* TODO: implement keystring mode also */
1862 gdk_error_trap_push ();
1863 key_synth_code = keycode;
1867 case Accessibility_KEY_PRESS:
1868 dec_synth_keycode_press (controller, keycode);
1870 case Accessibility_KEY_PRESSRELEASE:
1871 dec_synth_keycode_press (controller, keycode);
1872 case Accessibility_KEY_RELEASE:
1873 dec_synth_keycode_release (controller, keycode);
1875 case Accessibility_KEY_SYM:
1876 #ifdef SPI_XKB_DEBUG
1877 fprintf (stderr, "KeySym synthesis\n");
1879 key_synth_code = keycode_for_keysym (keycode);
1880 dec_synth_keycode_press (controller, key_synth_code);
1881 dec_synth_keycode_release (controller, key_synth_code);
1883 case Accessibility_KEY_STRING:
1884 fprintf (stderr, "Not yet implemented\n");
1887 if (gdk_error_trap_pop ())
1889 DBG (-1, g_warning ("Error emitting keystroke"));
1892 /* now we must determine whether this keystroke is expected
1893 * to delatch XKB. This is a bit of a hack :-( */
1894 priv = g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
1895 if (!priv->shift_keycodes)
1896 spi_dec_init_keycode_list (controller);
1897 if (!spi_keycodes_contain (priv->shift_keycodes, key_synth_code))
1899 priv->pending_xkb_mod_relatch_mask = 0;
1900 priv->xkb_latch_mask = 0;
1901 fprintf (stderr, "resetting the relatch masks.\n");
1907 priv->pending_xkb_mod_relatch_mask =
1908 spi_dec_mouse_check (controller, &x, &y, &moved);
1909 fprintf (stderr, "preparing to relatch %x\n");
1913 /* Accessibility::DEController::generateMouseEvent */
1915 impl_generate_mouse_event (PortableServer_Servant servant,
1918 const CORBA_char *eventName,
1919 CORBA_Environment *ev)
1922 gboolean error = FALSE;
1923 Display *display = spi_get_display ();
1925 fprintf (stderr, "generating mouse %s event at %ld, %ld\n",
1926 eventName, (long int) x, (long int) y);
1928 switch (eventName[0])
1931 switch (eventName[1])
1933 /* TODO: check number of buttons before parsing */
1948 if (x != -1 && y != -1)
1950 XTestFakeMotionEvent (display, DefaultScreen (display),
1953 XTestFakeButtonEvent (display, button, !(eventName[2] == 'r'), 0);
1954 if (eventName[2] == 'c')
1955 XTestFakeButtonEvent (display, button, FALSE, 1);
1956 else if (eventName[2] == 'd')
1958 XTestFakeButtonEvent (display, button, FALSE, 1);
1959 XTestFakeButtonEvent (display, button, TRUE, 2);
1960 XTestFakeButtonEvent (display, button, FALSE, 3);
1964 case 'r': /* relative motion */
1965 XTestFakeRelativeMotionEvent (display, x, y, 0);
1967 case 'a': /* absolute motion */
1968 XTestFakeMotionEvent (display, DefaultScreen (display),
1974 /* Accessibility::DEController::notifyListenersSync */
1975 static CORBA_boolean
1976 impl_notify_listeners_sync (PortableServer_Servant servant,
1977 const Accessibility_DeviceEvent *event,
1978 CORBA_Environment *ev)
1980 SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1981 bonobo_object_from_servant (servant));
1983 g_print ("notifylistening listeners synchronously: controller %p, event id %d\n",
1984 controller, (int) event->id);
1986 return spi_controller_notify_keylisteners (controller, event, CORBA_FALSE, ev) ?
1987 CORBA_TRUE : CORBA_FALSE;
1990 /* Accessibility::DEController::notifyListenersAsync */
1992 impl_notify_listeners_async (PortableServer_Servant servant,
1993 const Accessibility_DeviceEvent *event,
1994 CORBA_Environment *ev)
1996 SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1997 bonobo_object_from_servant (servant));
1999 fprintf (stderr, "notifying listeners asynchronously\n");
2001 spi_controller_notify_keylisteners (controller, event, CORBA_FALSE, ev);
2005 spi_device_event_controller_class_init (SpiDEControllerClass *klass)
2007 GObjectClass * object_class = (GObjectClass *) klass;
2008 POA_Accessibility_DeviceEventController__epv *epv = &klass->epv;
2010 spi_device_event_controller_parent_class = g_type_class_peek_parent (klass);
2012 object_class->finalize = spi_device_event_controller_object_finalize;
2014 epv->registerKeystrokeListener = impl_register_keystroke_listener;
2015 epv->deregisterKeystrokeListener = impl_deregister_keystroke_listener;
2016 epv->registerDeviceEventListener = impl_register_device_listener;
2017 epv->deregisterDeviceEventListener = impl_deregister_device_listener;
2018 epv->generateKeyboardEvent = impl_generate_keyboard_event;
2019 epv->generateMouseEvent = impl_generate_mouse_event;
2020 epv->notifyListenersSync = impl_notify_listeners_sync;
2021 epv->notifyListenersAsync = impl_notify_listeners_async;
2023 if (!spi_dec_private_quark)
2024 spi_dec_private_quark = g_quark_from_static_string ("spi-dec-private");
2028 spi_device_event_controller_init (SpiDEController *device_event_controller)
2030 DEControllerPrivateData *private;
2031 device_event_controller->key_listeners = NULL;
2032 device_event_controller->mouse_listeners = NULL;
2033 device_event_controller->keygrabs_list = NULL;
2036 * TODO: fixme, this module makes the foolish assumptions that
2037 * registryd uses the same display as the apps, and that the
2038 * DISPLAY environment variable is set.
2040 gdk_init (NULL, NULL);
2042 private = g_new0 (DEControllerPrivateData, 1);
2043 gettimeofday (&private->last_press_time, NULL);
2044 gettimeofday (&private->last_release_time, NULL);
2045 g_object_set_qdata (G_OBJECT (device_event_controller),
2046 spi_dec_private_quark,
2048 private->shift_keycodes = NULL;
2049 spi_controller_register_with_devices (device_event_controller);
2053 spi_device_event_controller_forward_key_event (SpiDEController *controller,
2054 const XEvent *event)
2056 gboolean is_consumed = FALSE;
2057 CORBA_Environment ev;
2058 Accessibility_DeviceEvent key_event;
2060 g_assert (event->type == KeyPress || event->type == KeyRelease);
2062 CORBA_exception_init (&ev);
2064 key_event = spi_keystroke_from_x_key_event ((XKeyEvent *) event);
2066 spi_controller_update_key_grabs (controller, &key_event);
2068 /* relay to listeners, and decide whether to consume it or not */
2069 is_consumed = spi_controller_notify_keylisteners (
2070 controller, &key_event, CORBA_TRUE, &ev);
2074 XAllowEvents (spi_get_display (), AsyncKeyboard, CurrentTime);
2078 XAllowEvents (spi_get_display (), ReplayKeyboard, CurrentTime);
2083 spi_device_event_controller_new (SpiRegistry *registry)
2085 SpiDEController *retval = g_object_new (
2086 SPI_DEVICE_EVENT_CONTROLLER_TYPE, NULL);
2087 DEControllerPrivateData *private;
2089 retval->registry = SPI_REGISTRY (bonobo_object_ref (
2090 BONOBO_OBJECT (registry)));
2092 spi_dec_init_mouse_listener (registry);
2093 /* TODO: kill mouse listener on finalize */
2097 BONOBO_TYPE_FUNC_FULL (SpiDEController,
2098 Accessibility_DeviceEventController,
2100 spi_device_event_controller);