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;
109 } DEControllerPrivateData;
111 static void spi_controller_register_with_devices (SpiDEController *controller);
112 static gboolean spi_controller_update_key_grabs (SpiDEController *controller,
113 Accessibility_DeviceEvent *recv);
114 static gboolean spi_controller_register_device_listener (SpiDEController *controller,
115 DEControllerListener *l,
116 CORBA_Environment *ev);
117 static void spi_device_event_controller_forward_key_event (SpiDEController *controller,
118 const XEvent *event);
119 static void spi_deregister_controller_device_listener (SpiDEController *controller,
120 DEControllerListener *listener,
121 CORBA_Environment *ev);
122 static void spi_deregister_controller_key_listener (SpiDEController *controller,
123 DEControllerKeyListener *key_listener,
124 CORBA_Environment *ev);
125 static gboolean spi_controller_notify_mouselisteners (SpiDEController *controller,
126 const Accessibility_DeviceEvent *event,
127 CORBA_Environment *ev);
129 static gboolean spi_eventtype_seq_contains_event (Accessibility_EventTypeSeq *type_seq,
130 const Accessibility_DeviceEvent *event);
131 static gboolean spi_clear_error_state (void);
132 static gboolean spi_dec_poll_mouse_moved (gpointer data);
133 static gboolean spi_dec_poll_mouse_moving (gpointer data);
134 static gboolean spi_dec_poll_mouse_idle (gpointer data);
136 #define spi_get_display() GDK_DISPLAY()
138 /* Private methods */
141 keycode_for_keysym (long keysym)
143 return XKeysymToKeycode (spi_get_display (), (KeySym) keysym);
146 static DEControllerGrabMask *
147 spi_grab_mask_clone (DEControllerGrabMask *grab_mask)
149 DEControllerGrabMask *clone = g_new (DEControllerGrabMask, 1);
151 memcpy (clone, grab_mask, sizeof (DEControllerGrabMask));
153 clone->ref_count = 1;
154 clone->pending_add = TRUE;
155 clone->pending_remove = FALSE;
161 spi_grab_mask_free (DEControllerGrabMask *grab_mask)
167 spi_grab_mask_compare_values (gconstpointer p1, gconstpointer p2)
169 DEControllerGrabMask *l1 = (DEControllerGrabMask *) p1;
170 DEControllerGrabMask *l2 = (DEControllerGrabMask *) p2;
178 return ((l1->mod_mask != l2->mod_mask) || (l1->key_val != l2->key_val));
182 static gint poll_count = 0;
185 spi_dec_poll_mouse_moved (gpointer data)
187 SpiRegistry *registry = SPI_REGISTRY (data);
188 SpiDEController *controller = registry->de_controller;
189 CORBA_Environment ev;
190 Accessibility_Event e;
191 Accessibility_DeviceEvent mouse_e;
192 Window root_return, child_return;
193 int win_x_return,win_y_return;
195 int poll_count_modulus = 10;
196 unsigned int mask_return;
197 gchar event_name[24];
198 gboolean is_consumed;
199 Display *display = spi_get_display ();
202 XQueryPointer(display, DefaultRootWindow (display),
203 &root_return, &child_return,
205 &win_x_return, &win_y_return, &mask_return);
208 * Since many clients grab the pointer, and X goes an automatic
209 * pointer grab on mouse-down, we often must detect mouse button events
210 * by polling rather than via a button grab.
211 * The while loop (rather than if) is used since it's possible that
212 * multiple buttons have changed state since we last checked.
214 if (mask_return != mouse_mask_state)
216 while ((mask_return & mouse_button_mask) !=
217 (mouse_mask_state & mouse_button_mask))
219 int button_number = 0;
220 gboolean is_down = False;
222 if (!(mask_return & Button1Mask) &&
223 (mouse_mask_state & Button1Mask))
225 mouse_mask_state &= ~Button1Mask;
228 else if ((mask_return & Button1Mask) &&
229 !(mouse_mask_state & Button1Mask))
231 mouse_mask_state |= Button1Mask;
235 else if (!(mask_return & Button2Mask) &&
236 (mouse_mask_state & Button2Mask))
238 mouse_mask_state &= ~Button2Mask;
241 else if ((mask_return & Button2Mask) &&
242 !(mouse_mask_state & Button2Mask))
244 mouse_mask_state |= Button2Mask;
248 else if (!(mask_return & Button3Mask) &&
249 (mouse_mask_state & Button3Mask))
251 mouse_mask_state &= ~Button3Mask;
254 else if ((mask_return & Button3Mask) &&
255 !(mouse_mask_state & Button3Mask))
257 mouse_mask_state |= Button3Mask;
261 else if (!(mask_return & Button4Mask) &&
262 (mouse_mask_state & Button1Mask))
264 mouse_mask_state &= ~Button4Mask;
267 else if ((mask_return & Button4Mask) &&
268 !(mouse_mask_state & Button1Mask))
270 mouse_mask_state |= Button4Mask;
274 else if (!(mask_return & Button5Mask) &&
275 (mouse_mask_state & Button5Mask))
277 mouse_mask_state &= ~Button5Mask;
280 else if ((mask_return & Button5Mask) &&
281 !(mouse_mask_state & Button5Mask))
283 mouse_mask_state |= Button5Mask;
289 fprintf (stderr, "Button %d %s\n",
290 button_number, (is_down) ? "Pressed" : "Released");
292 snprintf (event_name, 22, "mouse:button:%d%c", button_number,
293 (is_down) ? 'p' : 'r');
294 /* TODO: distinguish between physical and
297 mouse_e.type = (is_down) ?
298 Accessibility_BUTTON_PRESSED_EVENT :
299 Accessibility_BUTTON_RELEASED_EVENT;
300 mouse_e.id = button_number;
301 mouse_e.hw_code = button_number;
302 mouse_e.modifiers = (CORBA_unsigned_short) mouse_mask_state;
303 mouse_e.timestamp = 0;
304 mouse_e.event_string = "";
305 mouse_e.is_text = CORBA_FALSE;
307 spi_controller_notify_mouselisteners (controller,
311 e.source = BONOBO_OBJREF (registry->desktop);
312 e.detail1 = last_mouse_pos->x;
313 e.detail2 = last_mouse_pos->y;
314 spi_init_any_nil (&e.any_data);
315 CORBA_exception_init (&ev);
317 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (registry),
323 if ((mask_return & key_modifier_mask) !=
324 (mouse_mask_state & key_modifier_mask)) {
326 fprintf (stderr, "MODIFIER CHANGE EVENT!\n");
328 e.type = "keyboard:modifiers";
329 e.source = BONOBO_OBJREF (registry->desktop);
330 e.detail1 = mouse_mask_state;
331 e.detail2 = mask_return;
332 spi_init_any_nil (&e.any_data);
333 CORBA_exception_init (&ev);
334 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (registry),
338 mouse_mask_state = mask_return;
341 if (poll_count++ == poll_count_modulus) {
343 e.type = "mouse:abs";
344 e.source = BONOBO_OBJREF (registry->desktop);
347 spi_init_any_nil (&e.any_data);
348 CORBA_exception_init (&ev);
349 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (registry),
353 if (x != last_mouse_pos->x || y != last_mouse_pos->y) {
354 e.type = "mouse:rel";
355 e.source = BONOBO_OBJREF (registry->desktop);
356 e.detail1 = x - last_mouse_pos->x;
357 e.detail2 = y - last_mouse_pos->y;
358 spi_init_any_nil (&e.any_data);
359 CORBA_exception_init (&ev);
360 last_mouse_pos->x = x;
361 last_mouse_pos->y = y;
362 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (registry),
371 spi_dec_poll_mouse_idle (gpointer data)
373 if (! spi_dec_poll_mouse_moved (data))
377 g_timeout_add (20, spi_dec_poll_mouse_moving, data);
383 spi_dec_poll_mouse_moving (gpointer data)
385 if (spi_dec_poll_mouse_moved (data))
389 g_timeout_add (100, spi_dec_poll_mouse_idle, data);
395 spi_dec_ungrab_mouse (gpointer data)
397 Display *display = spi_get_display ();
400 XUngrabButton (spi_get_display (), AnyButton, AnyModifier,
401 XDefaultRootWindow (spi_get_display ()));
407 spi_dec_init_mouse_listener (SpiRegistry *registry)
409 Display *display = spi_get_display ();
410 g_timeout_add (100, spi_dec_poll_mouse_idle, registry);
414 XGrabButton (display, AnyButton, AnyModifier,
415 gdk_x11_get_default_root_xwindow (),
416 True, ButtonPressMask | ButtonReleaseMask,
417 GrabModeSync, GrabModeAsync, None, None);
418 XSync (display, False);
420 fprintf (stderr, "mouse buttons grabbed\n");
425 static DEControllerKeyListener *
426 spi_dec_key_listener_new (CORBA_Object l,
427 const Accessibility_KeySet *keys,
428 const Accessibility_ControllerEventMask mask,
429 const Accessibility_EventTypeSeq *typeseq,
430 const Accessibility_EventListenerMode *mode,
431 CORBA_Environment *ev)
433 DEControllerKeyListener *key_listener = g_new0 (DEControllerKeyListener, 1);
434 key_listener->listener.object = bonobo_object_dup_ref (l, ev);
435 key_listener->listener.type = SPI_DEVICE_TYPE_KBD;
436 key_listener->keys = ORBit_copy_value (keys, TC_Accessibility_KeySet);
437 key_listener->mask = mask;
438 key_listener->listener.typeseq = ORBit_copy_value (typeseq, TC_Accessibility_EventTypeSeq);
440 key_listener->mode = ORBit_copy_value (mode, TC_Accessibility_EventListenerMode);
442 key_listener->mode = NULL;
445 g_print ("new listener, with mask %x, is_global %d, keys %p (%d)\n",
446 (unsigned int) key_listener->mask,
447 (int) (mode ? mode->global : 0),
448 (void *) key_listener->keys,
449 (int) (key_listener->keys ? key_listener->keys->_length : 0));
455 static DEControllerListener *
456 spi_dec_listener_new (CORBA_Object l,
457 const Accessibility_EventTypeSeq *typeseq,
458 CORBA_Environment *ev)
460 DEControllerListener *listener = g_new0 (DEControllerListener, 1);
461 listener->object = bonobo_object_dup_ref (l, ev);
462 listener->type = SPI_DEVICE_TYPE_MOUSE;
463 listener->typeseq = ORBit_copy_value (typeseq, TC_Accessibility_EventTypeSeq);
467 static DEControllerListener *
468 spi_listener_clone (DEControllerListener *listener, CORBA_Environment *ev)
470 DEControllerListener *clone = g_new0 (DEControllerListener, 1);
472 CORBA_Object_duplicate (listener->object, ev);
473 clone->type = listener->type;
474 clone->typeseq = ORBit_copy_value (listener->typeseq, TC_Accessibility_EventTypeSeq);
478 static DEControllerKeyListener *
479 spi_key_listener_clone (DEControllerKeyListener *key_listener, CORBA_Environment *ev)
481 DEControllerKeyListener *clone = g_new0 (DEControllerKeyListener, 1);
482 clone->listener.object =
483 CORBA_Object_duplicate (key_listener->listener.object, ev);
484 clone->listener.type = SPI_DEVICE_TYPE_KBD;
485 clone->keys = ORBit_copy_value (key_listener->keys, TC_Accessibility_KeySet);
486 clone->mask = key_listener->mask;
487 clone->listener.typeseq = ORBit_copy_value (key_listener->listener.typeseq, TC_Accessibility_EventTypeSeq);
488 if (key_listener->mode)
489 clone->mode = ORBit_copy_value (key_listener->mode, TC_Accessibility_EventListenerMode);
496 spi_key_listener_data_free (DEControllerKeyListener *key_listener, CORBA_Environment *ev)
498 CORBA_free (key_listener->listener.typeseq);
499 CORBA_free (key_listener->keys);
500 g_free (key_listener);
504 spi_key_listener_clone_free (DEControllerKeyListener *clone, CORBA_Environment *ev)
506 CORBA_Object_release (clone->listener.object, ev);
507 spi_key_listener_data_free (clone, ev);
511 spi_listener_clone_free (DEControllerListener *clone, CORBA_Environment *ev)
513 CORBA_Object_release (clone->object, ev);
514 CORBA_free (clone->typeseq);
519 spi_dec_listener_free (DEControllerListener *listener,
520 CORBA_Environment *ev)
522 bonobo_object_release_unref (listener->object, ev);
523 if (listener->type == SPI_DEVICE_TYPE_KBD)
524 spi_key_listener_data_free ((DEControllerKeyListener *) listener, ev);
528 _register_keygrab (SpiDEController *controller,
529 DEControllerGrabMask *grab_mask)
533 l = g_list_find_custom (controller->keygrabs_list, grab_mask,
534 spi_grab_mask_compare_values);
537 DEControllerGrabMask *cur_mask = l->data;
539 cur_mask->ref_count++;
540 if (cur_mask->pending_remove)
542 cur_mask->pending_remove = FALSE;
547 controller->keygrabs_list =
548 g_list_prepend (controller->keygrabs_list,
549 spi_grab_mask_clone (grab_mask));
554 _deregister_keygrab (SpiDEController *controller,
555 DEControllerGrabMask *grab_mask)
559 l = g_list_find_custom (controller->keygrabs_list, grab_mask,
560 spi_grab_mask_compare_values);
564 DEControllerGrabMask *cur_mask = l->data;
566 cur_mask->ref_count--;
567 if (cur_mask->ref_count <= 0)
569 cur_mask->pending_remove = TRUE;
574 DBG (1, g_warning ("De-registering non-existant grab"));
579 handle_keygrab (SpiDEController *controller,
580 DEControllerKeyListener *key_listener,
581 void (*process_cb) (SpiDEController *controller,
582 DEControllerGrabMask *grab_mask))
584 DEControllerGrabMask grab_mask = { 0 };
586 grab_mask.mod_mask = key_listener->mask;
587 if (key_listener->keys->_length == 0) /* special case means AnyKey/AllKeys */
589 grab_mask.key_val = AnyKey;
591 fprintf (stderr, "AnyKey grab!");
593 process_cb (controller, &grab_mask);
599 for (i = 0; i < key_listener->keys->_length; ++i)
601 Accessibility_KeyDefinition keydef = key_listener->keys->_buffer[i];
602 long int key_val = keydef.keysym;
603 /* X Grabs require keycodes, not keysyms */
604 if (keydef.keystring && keydef.keystring[0])
606 key_val = XStringToKeysym(keydef.keystring);
610 key_val = XKeysymToKeycode (spi_get_display (), (KeySym) key_val);
614 key_val = keydef.keycode;
616 grab_mask.key_val = key_val;
617 process_cb (controller, &grab_mask);
623 spi_controller_register_global_keygrabs (SpiDEController *controller,
624 DEControllerKeyListener *key_listener)
626 handle_keygrab (controller, key_listener, _register_keygrab);
627 return spi_controller_update_key_grabs (controller, NULL);
631 spi_controller_deregister_global_keygrabs (SpiDEController *controller,
632 DEControllerKeyListener *key_listener)
634 handle_keygrab (controller, key_listener, _deregister_keygrab);
635 spi_controller_update_key_grabs (controller, NULL);
639 spi_controller_register_device_listener (SpiDEController *controller,
640 DEControllerListener *listener,
641 CORBA_Environment *ev)
643 DEControllerKeyListener *key_listener;
645 switch (listener->type) {
646 case SPI_DEVICE_TYPE_KBD:
647 key_listener = (DEControllerKeyListener *) listener;
649 controller->key_listeners = g_list_prepend (controller->key_listeners,
651 if (key_listener->mode->global)
653 return spi_controller_register_global_keygrabs (controller, key_listener);
658 case SPI_DEVICE_TYPE_MOUSE:
659 controller->mouse_listeners = g_list_prepend (controller->mouse_listeners, listener);
662 DBG (1, g_warning ("listener registration for unknown device type.\n"));
669 spi_controller_notify_mouselisteners (SpiDEController *controller,
670 const Accessibility_DeviceEvent *event,
671 CORBA_Environment *ev)
674 GSList *notify = NULL, *l2;
675 GList **listeners = &controller->mouse_listeners;
676 gboolean is_consumed;
683 for (l = *listeners; l; l = l->next)
685 DEControllerListener *listener = l->data;
687 if (spi_eventtype_seq_contains_event (listener->typeseq, event))
689 Accessibility_DeviceEventListener ls = listener->object;
691 if (ls != CORBA_OBJECT_NIL)
693 /* we clone (don't dup) the listener, to avoid refcount inc. */
694 notify = g_slist_prepend (notify,
695 spi_listener_clone (listener, ev));
700 #ifdef SPI_KEYEVENT_DEBUG
703 g_print ("no match for event\n");
708 for (l2 = notify; l2 && !is_consumed; l2 = l2->next)
710 DEControllerListener *listener = l2->data;
711 Accessibility_DeviceEventListener ls = listener->object;
713 CORBA_exception_init (ev);
714 is_consumed = Accessibility_DeviceEventListener_notifyEvent (ls, event, ev);
718 DBG (2, g_warning ("error notifying listener, removing it\n"));
719 spi_deregister_controller_device_listener (controller, listener,
721 CORBA_exception_free (ev);
724 spi_listener_clone_free ((DEControllerListener *) l2->data, ev);
727 for (; l2; l2 = l2->next)
729 DEControllerListener *listener = l2->data;
730 spi_listener_clone_free (listener, ev);
731 /* clone doesn't have its own ref, so don't use spi_device_listener_free */
734 g_slist_free (notify);
737 if (is_consumed) g_message ("consumed\n");
743 spi_device_event_controller_forward_mouse_event (SpiDEController *controller,
746 Accessibility_Event e;
747 Accessibility_DeviceEvent mouse_e;
748 CORBA_Environment ev;
749 gchar event_name[24];
750 gboolean is_consumed = FALSE;
751 gboolean xkb_mod_unlatch_occurred;
752 DEControllerPrivateData *priv;
753 XButtonEvent *xbutton_event = (XButtonEvent *) xevent;
755 int button = xbutton_event->button;
757 unsigned int mouse_button_state = xbutton_event->state;
762 mouse_button_state |= Button1Mask;
765 mouse_button_state |= Button2Mask;
768 mouse_button_state |= Button3Mask;
771 mouse_button_state |= Button4Mask;
774 mouse_button_state |= Button5Mask;
777 last_mouse_pos->x = ((XButtonEvent *) xevent)->x_root;
778 last_mouse_pos->y = ((XButtonEvent *) xevent)->y_root;
781 fprintf (stderr, "mouse button %d %s (%x)\n",
782 xbutton_event->button,
783 (xevent->type == ButtonPress) ? "Press" : "Release",
786 snprintf (event_name, 22, "mouse:button:%d%c", button,
787 (xevent->type == ButtonPress) ? 'p' : 'r');
789 /* TODO: distinguish between physical and logical buttons */
790 mouse_e.type = (xevent->type == ButtonPress) ?
791 Accessibility_BUTTON_PRESSED_EVENT :
792 Accessibility_BUTTON_RELEASED_EVENT;
794 mouse_e.hw_code = button;
795 mouse_e.modifiers = (CORBA_unsigned_short) xbutton_event->state;
796 mouse_e.timestamp = (CORBA_unsigned_long) xbutton_event->time;
797 mouse_e.event_string = "";
798 mouse_e.is_text = CORBA_FALSE;
799 if ((mouse_button_state & mouse_button_mask) !=
800 (mouse_mask_state & mouse_button_mask))
802 mouse_mask_state = mouse_button_state;
804 spi_controller_notify_mouselisteners (controller, &mouse_e, &ev);
805 e.type = CORBA_string_dup (event_name);
806 e.source = BONOBO_OBJREF (controller->registry->desktop);
807 e.detail1 = last_mouse_pos->x;
808 e.detail2 = last_mouse_pos->y;
809 spi_init_any_nil (&e.any_data);
810 CORBA_exception_init (&ev);
812 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry),
816 xkb_mod_unlatch_occurred = (xevent->type == ButtonPress ||
817 xevent->type == ButtonRelease);
819 /* if client wants to consume this event, and XKB latch state was
820 * unset by this button event, we reset it
822 if (is_consumed && xkb_mod_unlatch_occurred)
824 priv = g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
825 priv->pending_xkb_mod_relatch_mask |= priv->xkb_latch_mask;
828 XAllowEvents (spi_get_display (),
829 (is_consumed) ? SyncPointer : ReplayPointer,
833 static GdkFilterReturn
834 global_filter_fn (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
836 XEvent *xevent = gdk_xevent;
837 SpiDEController *controller;
838 DEControllerPrivateData *priv;
839 Display *display = spi_get_display ();
840 controller = SPI_DEVICE_EVENT_CONTROLLER (data);
841 priv = (DEControllerPrivateData *)
842 g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
844 if (xevent->type == KeyPress || xevent->type == KeyRelease)
846 spi_device_event_controller_forward_key_event (controller, xevent);
847 return GDK_FILTER_CONTINUE;
849 if (xevent->type == ButtonPress || xevent->type == ButtonRelease)
851 spi_device_event_controller_forward_mouse_event (controller, xevent);
853 if (xevent->type == priv->xkb_base_event_code)
855 XkbAnyEvent * xkb_ev = (XkbAnyEvent *) xevent;
857 if (xkb_ev->xkb_type == XkbStateNotify)
859 XkbStateNotifyEvent *xkb_snev =
860 (XkbStateNotifyEvent *) xkb_ev;
861 priv->xkb_latch_mask = xkb_snev->latched_mods;
862 if (priv->pending_xkb_mod_relatch_mask)
864 unsigned int feedback_mask;
866 fprintf (stderr, "relatching %x\n",
867 priv->pending_xkb_mod_relatch_mask);
869 /* temporarily turn off the latch bell, if it's on */
870 XkbGetControls (display,
871 XkbAccessXFeedbackMask,
873 feedback_mask = priv->xkb_desc->ctrls->ax_options;
874 if (feedback_mask & XkbAX_StickyKeysFBMask)
876 XkbControlsChangesRec changes = {XkbAccessXFeedbackMask,
878 priv->xkb_desc->ctrls->ax_options
879 &= ~(XkbAX_StickyKeysFBMask);
880 XkbChangeControls (display, priv->xkb_desc, &changes);
882 XkbLatchModifiers (display,
884 priv->pending_xkb_mod_relatch_mask,
885 priv->pending_xkb_mod_relatch_mask);
886 if (feedback_mask & XkbAX_StickyKeysFBMask)
888 XkbControlsChangesRec changes = {XkbAccessXFeedbackMask,
890 priv->xkb_desc->ctrls->ax_options = feedback_mask;
891 XkbChangeControls (display, priv->xkb_desc, &changes);
894 fprintf (stderr, "relatched %x\n",
895 priv->pending_xkb_mod_relatch_mask);
897 priv->pending_xkb_mod_relatch_mask = 0;
901 DBG (2, g_warning ("XKB event %d\n", xkb_ev->xkb_type));
904 return GDK_FILTER_CONTINUE;
908 _spi_controller_device_error_handler (Display *display, XErrorEvent *error)
910 if (error->error_code == BadAccess)
912 g_message ("Could not complete key grab: grab already in use.\n");
913 spi_error_code = BadAccess;
918 return (*x_default_error_handler) (display, error);
923 spi_controller_register_with_devices (SpiDEController *controller)
925 DEControllerPrivateData *priv = (DEControllerPrivateData *)
926 g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
927 /* FIXME: should check for extension first! */
928 XTestGrabControl (spi_get_display (), True);
929 priv->xkb_desc = XkbGetMap (spi_get_display (), 0, XkbUseCoreKbd);
931 /* calls to device-specific implementations and routines go here */
932 /* register with: keyboard hardware code handler */
933 /* register with: (translated) keystroke handler */
935 priv->have_xkb = XkbQueryExtension (spi_get_display (),
936 &priv->xkb_major_extension_opcode,
937 &priv->xkb_base_event_code,
938 &priv->xkb_base_error_code, NULL, NULL);
941 XkbSelectEvents (spi_get_display (),
943 XkbStateNotifyMask, XkbStateNotifyMask);
945 gdk_window_add_filter (NULL, global_filter_fn, controller);
947 gdk_window_set_events (gdk_get_default_root_window (),
948 GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
950 x_default_error_handler = XSetErrorHandler (_spi_controller_device_error_handler);
954 spi_key_set_contains_key (Accessibility_KeySet *key_set,
955 const Accessibility_DeviceEvent *key_event)
962 g_print ("null key set!");
966 len = key_set->_length;
968 if (len == 0) /* special case, means "all keys/any key" */
970 g_print ("anykey\n");
974 for (i = 0; i < len; ++i)
976 #ifdef SPI_KEYEVENT_DEBUG
977 g_print ("key_set[%d] = %d; key_event %d, code %d, string %s\n",
978 i, (int) key_set->_buffer[i].keycode,
979 (int) key_event->id, (int) key_event->hw_code,
980 key_event->event_string);
982 if (key_set->_buffer[i].keysym == (CORBA_long) key_event->id)
986 if (key_set->_buffer[i].keycode == (CORBA_long) key_event->hw_code)
990 if (key_event->event_string && key_event->event_string[0] &&
991 !strcmp (key_set->_buffer[i].keystring, key_event->event_string))
1001 spi_eventtype_seq_contains_event (Accessibility_EventTypeSeq *type_seq,
1002 const Accessibility_DeviceEvent *event)
1010 g_print ("null type seq!");
1014 len = type_seq->_length;
1016 if (len == 0) /* special case, means "all events/any event" */
1021 for (i = 0; i < len; ++i)
1024 g_print ("type_seq[%d] = %d; event type = %d\n", i,
1025 (int) type_seq->_buffer[i], (int) event->type);
1027 if (type_seq->_buffer[i] == (CORBA_long) event->type)
1037 spi_key_event_matches_listener (const Accessibility_DeviceEvent *key_event,
1038 DEControllerKeyListener *listener,
1039 CORBA_boolean is_system_global)
1041 if ((key_event->modifiers == (CORBA_unsigned_short) (listener->mask & 0xFFFF)) &&
1042 spi_key_set_contains_key (listener->keys, key_event) &&
1043 spi_eventtype_seq_contains_event (listener->listener.typeseq, key_event) &&
1044 (is_system_global == listener->mode->global))
1055 spi_controller_notify_keylisteners (SpiDEController *controller,
1056 const Accessibility_DeviceEvent *key_event,
1057 CORBA_boolean is_system_global,
1058 CORBA_Environment *ev)
1061 GSList *notify = NULL, *l2;
1062 GList **key_listeners = &controller->key_listeners;
1063 gboolean is_consumed;
1070 for (l = *key_listeners; l; l = l->next)
1072 DEControllerKeyListener *key_listener = l->data;
1074 if (spi_key_event_matches_listener (key_event, key_listener, is_system_global))
1076 Accessibility_DeviceEventListener ls = key_listener->listener.object;
1078 if (ls != CORBA_OBJECT_NIL)
1080 /* we clone (don't dup) the listener, to avoid refcount inc. */
1081 notify = g_slist_prepend (notify,
1082 spi_key_listener_clone (key_listener, ev));
1087 #ifdef SPI_KEYEVENT_DEBUG
1090 g_print ("no match for event\n");
1094 is_consumed = FALSE;
1095 for (l2 = notify; l2 && !is_consumed; l2 = l2->next)
1097 DEControllerKeyListener *key_listener = l2->data;
1098 Accessibility_DeviceEventListener ls = key_listener->listener.object;
1100 is_consumed = Accessibility_DeviceEventListener_notifyEvent (ls, key_event, ev);
1104 is_consumed = FALSE;
1105 spi_deregister_controller_key_listener (controller, key_listener,
1107 CORBA_exception_free (ev);
1110 spi_key_listener_clone_free (key_listener, ev);
1113 for (; l2; l2 = l2->next)
1115 DEControllerKeyListener *key_listener = l2->data;
1116 spi_key_listener_clone_free (key_listener, ev);
1117 /* clone doesn't have its own ref, so don't use spi_dec_listener_free */
1120 g_slist_free (notify);
1123 if (is_consumed) g_message ("consumed\n");
1129 spi_clear_error_state ()
1131 gboolean retval = spi_error_code != 0;
1136 static Accessibility_DeviceEvent
1137 spi_keystroke_from_x_key_event (XKeyEvent *x_key_event)
1139 Accessibility_DeviceEvent key_event;
1141 const int cbuf_bytes = 20;
1142 char cbuf [cbuf_bytes];
1144 keysym = XLookupKeysym (x_key_event, 0);
1145 key_event.id = (CORBA_long)(keysym);
1146 key_event.hw_code = (CORBA_short) x_key_event->keycode;
1147 if (((XEvent *) x_key_event)->type == KeyPress)
1149 key_event.type = Accessibility_KEY_PRESSED;
1153 key_event.type = Accessibility_KEY_RELEASED;
1155 key_event.modifiers = (CORBA_unsigned_short)(x_key_event->state);
1156 key_event.is_text = CORBA_FALSE;
1160 key_event.event_string = CORBA_string_dup ("space");
1163 #ifdef SPI_KEYEVENT_DEBUG
1164 fprintf(stderr, "Tab\n");
1166 key_event.event_string = CORBA_string_dup ("Tab");
1169 key_event.event_string = CORBA_string_dup ("Backspace");
1172 key_event.event_string = CORBA_string_dup ("Return");
1175 key_event.event_string = CORBA_string_dup ("Home");
1178 key_event.event_string = CORBA_string_dup ("Page_Down");
1181 key_event.event_string = CORBA_string_dup ("Page_Up");
1184 key_event.event_string = CORBA_string_dup ("F1");
1187 key_event.event_string = CORBA_string_dup ("F2");
1190 key_event.event_string = CORBA_string_dup ("F3");
1193 key_event.event_string = CORBA_string_dup ("F4");
1196 key_event.event_string = CORBA_string_dup ("F5");
1199 key_event.event_string = CORBA_string_dup ("F6");
1202 key_event.event_string = CORBA_string_dup ("F7");
1205 key_event.event_string = CORBA_string_dup ("F8");
1208 key_event.event_string = CORBA_string_dup ("F9");
1211 key_event.event_string = CORBA_string_dup ("F10");
1214 key_event.event_string = CORBA_string_dup ("F11");
1217 key_event.event_string = CORBA_string_dup ("F12");
1220 key_event.event_string = CORBA_string_dup ("End");
1223 key_event.event_string = CORBA_string_dup ("Escape");
1226 key_event.event_string = CORBA_string_dup ("Up");
1229 key_event.event_string = CORBA_string_dup ("Down");
1232 key_event.event_string = CORBA_string_dup ("Left");
1235 key_event.event_string = CORBA_string_dup ("Right");
1238 if (XLookupString (x_key_event, cbuf, cbuf_bytes, &keysym, NULL) > 0)
1240 key_event.event_string = CORBA_string_dup (cbuf);
1241 if (isgraph (keysym))
1243 key_event.is_text = CORBA_TRUE; /* FIXME: incorrect for some composed chars? */
1248 key_event.event_string = CORBA_string_dup ("");
1252 key_event.timestamp = (CORBA_unsigned_long) x_key_event->time;
1253 #ifdef SPI_KEYEVENT_DEBUG
1255 "Key %lu pressed (%c), modifiers %d\n",
1256 (unsigned long) keysym,
1257 keysym ? (int) keysym : '*',
1258 (int) x_key_event->state);
1261 fprintf (stderr, "%s%c",
1262 (x_key_event->state & Mod1Mask)?"Alt-":"",
1263 ((x_key_event->state & ShiftMask)^(x_key_event->state & LockMask))?
1264 g_ascii_toupper (keysym) : g_ascii_tolower (keysym));
1265 #endif /* SPI_DEBUG */
1270 spi_controller_update_key_grabs (SpiDEController *controller,
1271 Accessibility_DeviceEvent *recv)
1274 gboolean update_failed = FALSE;
1276 g_return_val_if_fail (controller != NULL, FALSE);
1279 * masks known to work with default RH 7.1+:
1280 * 0 (no mods), LockMask, Mod1Mask, Mod2Mask, ShiftMask,
1281 * ShiftMask|LockMask, Mod1Mask|LockMask, Mod2Mask|LockMask,
1282 * ShiftMask|Mod1Mask, ShiftMask|Mod2Mask, Mod1Mask|Mod2Mask,
1283 * ShiftMask|LockMask|Mod1Mask, ShiftMask|LockMask|Mod2Mask,
1285 * ControlMask grabs are broken, must be in use already
1287 for (l = controller->keygrabs_list; l; l = next)
1290 gboolean re_issue_grab;
1291 DEControllerGrabMask *grab_mask = l->data;
1295 re_issue_grab = recv &&
1296 /* (recv->type == Accessibility_KEY_RELEASED) && - (?) */
1297 (recv->modifiers & grab_mask->mod_mask) &&
1298 (grab_mask->key_val == keycode_for_keysym (recv->id));
1301 fprintf (stderr, "mask=%lx %lx (%c%c) %s\n",
1302 (long int) grab_mask->key_val,
1303 (long int) grab_mask->mod_mask,
1304 grab_mask->pending_add ? '+' : '.',
1305 grab_mask->pending_remove ? '-' : '.',
1306 re_issue_grab ? "re-issue": "");
1311 if (grab_mask->pending_add && grab_mask->pending_remove)
1315 else if (grab_mask->pending_remove)
1318 fprintf (stderr, "ungrabbing, mask=%x\n", grab_mask->mod_mask);
1320 XUngrabKey (spi_get_display (),
1322 grab_mask->mod_mask,
1323 gdk_x11_get_default_root_xwindow ());
1327 else if (grab_mask->pending_add || re_issue_grab)
1331 fprintf (stderr, "grab %d with mask %x\n", grab_mask->key_val, grab_mask->mod_mask);
1333 XGrabKey (spi_get_display (),
1335 grab_mask->mod_mask,
1336 gdk_x11_get_default_root_xwindow (),
1340 XSync (spi_get_display (), False);
1341 update_failed = spi_clear_error_state ();
1342 if (update_failed) {
1343 while (grab_mask->ref_count > 0) --grab_mask->ref_count;
1348 grab_mask->pending_add = FALSE;
1349 grab_mask->pending_remove = FALSE;
1353 g_assert (grab_mask->ref_count <= 0);
1355 controller->keygrabs_list = g_list_delete_link (
1356 controller->keygrabs_list, l);
1358 spi_grab_mask_free (grab_mask);
1363 return ! update_failed;
1367 * Implemented GObject::finalize
1370 spi_device_event_controller_object_finalize (GObject *object)
1372 SpiDEController *controller;
1373 DEControllerPrivateData *private;
1374 controller = SPI_DEVICE_EVENT_CONTROLLER (object);
1377 fprintf(stderr, "spi_device_event_controller_object_finalize called\n");
1379 /* disconnect any special listeners, get rid of outstanding keygrabs */
1380 XUngrabKey (spi_get_display (), AnyKey, AnyModifier, DefaultRootWindow (spi_get_display ()));
1382 private = g_object_get_data (G_OBJECT (controller), "spi-dec-private");
1383 if (private->xkb_desc)
1384 XkbFreeKeyboard (private->xkb_desc, 0, True);
1386 spi_device_event_controller_parent_class->finalize (object);
1390 * CORBA Accessibility::DEController::registerKeystrokeListener
1391 * method implementation
1393 static CORBA_boolean
1394 impl_register_keystroke_listener (PortableServer_Servant servant,
1395 const Accessibility_DeviceEventListener l,
1396 const Accessibility_KeySet *keys,
1397 const Accessibility_ControllerEventMask mask,
1398 const Accessibility_EventTypeSeq *type,
1399 const Accessibility_EventListenerMode *mode,
1400 CORBA_Environment *ev)
1402 SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1403 bonobo_object_from_servant (servant));
1404 DEControllerKeyListener *dec_listener;
1406 fprintf (stderr, "registering keystroke listener %p with maskVal %lu\n",
1407 (void *) l, (unsigned long) mask);
1409 dec_listener = spi_dec_key_listener_new (l, keys, mask, type, mode, ev);
1410 return spi_controller_register_device_listener (
1411 controller, (DEControllerListener *) dec_listener, ev);
1416 * CORBA Accessibility::DEController::registerDeviceEventListener
1417 * method implementation
1419 static CORBA_boolean
1420 impl_register_device_listener (PortableServer_Servant servant,
1421 const Accessibility_DeviceEventListener l,
1422 const Accessibility_EventTypeSeq *event_types,
1423 CORBA_Environment *ev)
1425 SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1426 bonobo_object_from_servant (servant));
1427 DEControllerListener *dec_listener;
1429 dec_listener = spi_dec_listener_new (l, event_types, ev);
1430 return spi_controller_register_device_listener (
1431 controller, (DEControllerListener *) dec_listener, ev);
1435 CORBA_Environment *ev;
1436 DEControllerListener *listener;
1437 } RemoveListenerClosure;
1439 static SpiReEntrantContinue
1440 remove_listener_cb (GList * const *list,
1443 DEControllerListener *listener = (*list)->data;
1444 RemoveListenerClosure *ctx = user_data;
1446 if (CORBA_Object_is_equivalent (ctx->listener->object,
1447 listener->object, ctx->ev))
1449 spi_re_entrant_list_delete_link (list);
1450 spi_dec_listener_free (listener, ctx->ev);
1453 return SPI_RE_ENTRANT_CONTINUE;
1456 static SpiReEntrantContinue
1457 copy_key_listener_cb (GList * const *list,
1460 DEControllerKeyListener *key_listener = (*list)->data;
1461 RemoveListenerClosure *ctx = user_data;
1463 if (CORBA_Object_is_equivalent (ctx->listener->object,
1464 key_listener->listener.object, ctx->ev))
1466 /* TODO: FIXME aggregate keys in case the listener is registered twice */
1467 DEControllerKeyListener *ctx_key_listener =
1468 (DEControllerKeyListener *) ctx->listener;
1469 CORBA_free (ctx_key_listener->keys);
1470 ctx_key_listener->keys = ORBit_copy_value (key_listener->keys, TC_Accessibility_KeySet);
1473 return SPI_RE_ENTRANT_CONTINUE;
1477 spi_deregister_controller_device_listener (SpiDEController *controller,
1478 DEControllerListener *listener,
1479 CORBA_Environment *ev)
1481 RemoveListenerClosure ctx;
1484 ctx.listener = listener;
1486 spi_re_entrant_list_foreach (&controller->mouse_listeners,
1487 remove_listener_cb, &ctx);
1491 spi_deregister_controller_key_listener (SpiDEController *controller,
1492 DEControllerKeyListener *key_listener,
1493 CORBA_Environment *ev)
1495 RemoveListenerClosure ctx;
1498 ctx.listener = (DEControllerListener *) key_listener;
1500 /* special case, copy keyset from existing controller list entry */
1501 if (key_listener->keys->_length == 0)
1503 spi_re_entrant_list_foreach (&controller->key_listeners,
1504 copy_key_listener_cb, &ctx);
1507 spi_controller_deregister_global_keygrabs (controller, key_listener);
1509 spi_re_entrant_list_foreach (&controller->key_listeners,
1510 remove_listener_cb, &ctx);
1515 * CORBA Accessibility::DEController::deregisterKeystrokeListener
1516 * method implementation
1519 impl_deregister_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 CORBA_Environment *ev)
1526 DEControllerKeyListener *key_listener;
1527 SpiDEController *controller;
1529 controller = SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
1531 key_listener = spi_dec_key_listener_new (l, keys, mask, type, NULL, ev);
1533 #ifdef SPI_DEREGISTER_DEBUG
1534 fprintf (stderr, "deregistering keystroke listener %p with maskVal %lu\n",
1535 (void *) l, (unsigned long) mask->value);
1538 spi_deregister_controller_key_listener (controller, key_listener, ev);
1540 spi_dec_listener_free ((DEControllerListener *) key_listener, ev);
1544 * CORBA Accessibility::DEController::deregisterDeviceEventListener
1545 * method implementation
1548 impl_deregister_device_listener (PortableServer_Servant servant,
1549 const Accessibility_DeviceEventListener l,
1550 const Accessibility_EventTypeSeq *event_types,
1551 CORBA_Environment *ev)
1553 SpiDEController *controller;
1554 DEControllerListener *listener =
1555 spi_dec_listener_new (l, event_types, ev);
1557 controller = SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
1559 spi_deregister_controller_device_listener (controller, listener, ev);
1561 spi_dec_listener_free (listener, ev);
1564 static unsigned int dec_xkb_get_slowkeys_delay (SpiDEController *controller)
1566 unsigned int retval = 0;
1567 DEControllerPrivateData *priv = (DEControllerPrivateData *)
1568 g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
1570 #ifdef XKB_HAS_GET_SLOW_KEYS_DELAY
1571 retval = XkbGetSlowKeysDelay (spi_get_display (),
1572 XkbUseCoreKbd, &bounce_delay);
1574 if (!(priv->xkb_desc == (XkbDescPtr) BadAlloc || priv->xkb_desc == NULL))
1576 Status s = XkbGetControls (spi_get_display (),
1577 XkbAllControlsMask, priv->xkb_desc);
1580 if (priv->xkb_desc->ctrls->enabled_ctrls & XkbSlowKeysMask)
1581 retval = priv->xkb_desc->ctrls->slow_keys_delay;
1586 #ifdef SPI_XKB_DEBUG
1587 fprintf (stderr, "SlowKeys delay: %d\n", (int) retval);
1592 static unsigned int dec_xkb_get_bouncekeys_delay (SpiDEController *controller)
1594 unsigned int retval = 0;
1595 DEControllerPrivateData *priv = (DEControllerPrivateData *)
1596 g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
1598 #ifdef XKB_HAS_GET_BOUNCE_KEYS_DELAY
1599 retval = XkbGetBounceKeysDelay (spi_get_display (),
1600 XkbUseCoreKbd, &bounce_delay);
1602 if (!(priv->xkb_desc == (XkbDescPtr) BadAlloc || priv->xkb_desc == NULL))
1604 Status s = XkbGetControls (spi_get_display (),
1605 XkbAllControlsMask, priv->xkb_desc);
1608 if (priv->xkb_desc->ctrls->enabled_ctrls & XkbBounceKeysMask)
1609 retval = priv->xkb_desc->ctrls->debounce_delay;
1614 #ifdef SPI_XKB_DEBUG
1615 fprintf (stderr, "BounceKeys delay: %d\n", (int) retval);
1621 dec_synth_keycode_press (SpiDEController *controller,
1622 unsigned int keycode)
1624 unsigned int time = CurrentTime;
1625 unsigned int bounce_delay;
1626 unsigned int elapsed_msec;
1628 DEControllerPrivateData *priv =
1629 (DEControllerPrivateData *) g_object_get_qdata (G_OBJECT (controller),
1630 spi_dec_private_quark);
1631 if (keycode == priv->last_release_keycode)
1633 bounce_delay = dec_xkb_get_bouncekeys_delay (controller);
1636 gettimeofday (&tv, NULL);
1638 (tv.tv_sec - priv->last_release_time.tv_sec) * 1000
1639 + (tv.tv_usec - priv->last_release_time.tv_usec) / 1000;
1640 #ifdef SPI_XKB_DEBUG
1641 fprintf (stderr, "%d ms elapsed (%ld usec)\n", elapsed_msec,
1642 (long) (tv.tv_usec - priv->last_release_time.tv_usec));
1644 #ifdef THIS_IS_BROKEN
1645 if (elapsed_msec < bounce_delay)
1646 time = bounce_delay - elapsed_msec + 1;
1648 time = bounce_delay + 10;
1649 /* fudge for broken XTest */
1651 #ifdef SPI_XKB_DEBUG
1652 fprintf (stderr, "waiting %d ms\n", time);
1656 XTestFakeKeyEvent (spi_get_display (), keycode, True, time);
1657 priv->last_press_keycode = keycode;
1658 XSync (spi_get_display (), False);
1659 gettimeofday (&priv->last_press_time, NULL);
1664 dec_synth_keycode_release (SpiDEController *controller,
1665 unsigned int keycode)
1667 unsigned int time = CurrentTime;
1668 unsigned int slow_delay;
1669 unsigned int elapsed_msec;
1671 DEControllerPrivateData *priv =
1672 (DEControllerPrivateData *) g_object_get_qdata (G_OBJECT (controller),
1673 spi_dec_private_quark);
1674 if (keycode == priv->last_press_keycode)
1676 slow_delay = dec_xkb_get_slowkeys_delay (controller);
1679 gettimeofday (&tv, NULL);
1681 (tv.tv_sec - priv->last_press_time.tv_sec) * 1000
1682 + (tv.tv_usec - priv->last_press_time.tv_usec) / 1000;
1683 #ifdef SPI_XKB_DEBUG
1684 fprintf (stderr, "%d ms elapsed (%ld usec)\n", elapsed_msec,
1685 (long) (tv.tv_usec - priv->last_press_time.tv_usec));
1687 #ifdef THIS_IS_BROKEN_DUNNO_WHY
1688 if (elapsed_msec < slow_delay)
1689 time = slow_delay - elapsed_msec + 1;
1691 time = slow_delay + 10;
1692 /* our XTest seems broken, we have to add slop as above */
1694 #ifdef SPI_XKB_DEBUG
1695 fprintf (stderr, "waiting %d ms\n", time);
1699 XTestFakeKeyEvent (spi_get_display (), keycode, False, time);
1700 priv->last_release_keycode = keycode;
1701 XSync (spi_get_display (), False);
1702 gettimeofday (&priv->last_release_time, NULL);
1707 * CORBA Accessibility::DEController::registerKeystrokeListener
1708 * method implementation
1711 impl_generate_keyboard_event (PortableServer_Servant servant,
1712 const CORBA_long keycode,
1713 const CORBA_char *keystring,
1714 const Accessibility_KeySynthType synth_type,
1715 CORBA_Environment *ev)
1717 SpiDEController *controller =
1718 SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
1719 long key_synth_code;
1720 unsigned int slow_keys_delay;
1721 unsigned int press_time;
1722 unsigned int release_time;
1725 fprintf (stderr, "synthesizing keystroke %ld, type %d\n",
1726 (long) keycode, (int) synth_type);
1728 /* TODO: hide/wrap/remove X dependency */
1731 * TODO: when initializing, query for XTest extension before using,
1732 * and fall back to XSendEvent() if XTest is not available.
1735 /* TODO: implement keystring mode also */
1736 gdk_error_trap_push ();
1740 case Accessibility_KEY_PRESS:
1741 dec_synth_keycode_press (controller, keycode);
1743 case Accessibility_KEY_PRESSRELEASE:
1744 dec_synth_keycode_press (controller, keycode);
1745 case Accessibility_KEY_RELEASE:
1746 dec_synth_keycode_release (controller, keycode);
1748 case Accessibility_KEY_SYM:
1749 #ifdef SPI_XKB_DEBUG
1750 fprintf (stderr, "KeySym synthesis\n");
1752 key_synth_code = keycode_for_keysym (keycode);
1753 dec_synth_keycode_press (controller, key_synth_code);
1754 dec_synth_keycode_release (controller, key_synth_code);
1756 case Accessibility_KEY_STRING:
1757 fprintf (stderr, "Not yet implemented\n");
1760 if (gdk_error_trap_pop ())
1762 DBG (-1, g_warning ("Error emitting keystroke"));
1766 /* Accessibility::DEController::generateMouseEvent */
1768 impl_generate_mouse_event (PortableServer_Servant servant,
1771 const CORBA_char *eventName,
1772 CORBA_Environment *ev)
1775 gboolean error = FALSE;
1776 Display *display = spi_get_display ();
1778 fprintf (stderr, "generating mouse %s event at %ld, %ld\n",
1779 eventName, (long int) x, (long int) y);
1781 switch (eventName[0])
1784 switch (eventName[1])
1786 /* TODO: check number of buttons before parsing */
1801 if (x != -1 && y != -1)
1803 XTestFakeMotionEvent (display, DefaultScreen (display),
1806 XTestFakeButtonEvent (display, button, !(eventName[2] == 'r'), 0);
1807 if (eventName[2] == 'c')
1808 XTestFakeButtonEvent (display, button, FALSE, 1);
1809 else if (eventName[2] == 'd')
1811 XTestFakeButtonEvent (display, button, FALSE, 1);
1812 XTestFakeButtonEvent (display, button, TRUE, 2);
1813 XTestFakeButtonEvent (display, button, FALSE, 3);
1817 case 'r': /* relative motion */
1818 XTestFakeRelativeMotionEvent (display, x, y, 0);
1820 case 'a': /* absolute motion */
1821 XTestFakeMotionEvent (display, DefaultScreen (display),
1827 /* Accessibility::DEController::notifyListenersSync */
1828 static CORBA_boolean
1829 impl_notify_listeners_sync (PortableServer_Servant servant,
1830 const Accessibility_DeviceEvent *event,
1831 CORBA_Environment *ev)
1833 SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1834 bonobo_object_from_servant (servant));
1836 g_print ("notifylistening listeners synchronously: controller %p, event id %d\n",
1837 controller, (int) event->id);
1839 return spi_controller_notify_keylisteners (controller, event, CORBA_FALSE, ev) ?
1840 CORBA_TRUE : CORBA_FALSE;
1843 /* Accessibility::DEController::notifyListenersAsync */
1845 impl_notify_listeners_async (PortableServer_Servant servant,
1846 const Accessibility_DeviceEvent *event,
1847 CORBA_Environment *ev)
1849 SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1850 bonobo_object_from_servant (servant));
1852 fprintf (stderr, "notifying listeners asynchronously\n");
1854 spi_controller_notify_keylisteners (controller, event, CORBA_FALSE, ev);
1858 spi_device_event_controller_class_init (SpiDEControllerClass *klass)
1860 GObjectClass * object_class = (GObjectClass *) klass;
1861 POA_Accessibility_DeviceEventController__epv *epv = &klass->epv;
1863 spi_device_event_controller_parent_class = g_type_class_peek_parent (klass);
1865 object_class->finalize = spi_device_event_controller_object_finalize;
1867 epv->registerKeystrokeListener = impl_register_keystroke_listener;
1868 epv->deregisterKeystrokeListener = impl_deregister_keystroke_listener;
1869 epv->registerDeviceEventListener = impl_register_device_listener;
1870 epv->deregisterDeviceEventListener = impl_deregister_device_listener;
1871 epv->generateKeyboardEvent = impl_generate_keyboard_event;
1872 epv->generateMouseEvent = impl_generate_mouse_event;
1873 epv->notifyListenersSync = impl_notify_listeners_sync;
1874 epv->notifyListenersAsync = impl_notify_listeners_async;
1876 if (!spi_dec_private_quark)
1877 spi_dec_private_quark = g_quark_from_static_string ("spi-dec-private");
1881 spi_device_event_controller_init (SpiDEController *device_event_controller)
1883 DEControllerPrivateData *private;
1884 device_event_controller->key_listeners = NULL;
1885 device_event_controller->mouse_listeners = NULL;
1886 device_event_controller->keygrabs_list = NULL;
1889 * TODO: fixme, this module makes the foolish assumptions that
1890 * registryd uses the same display as the apps, and that the
1891 * DISPLAY environment variable is set.
1893 gdk_init (NULL, NULL);
1895 private = g_new0 (DEControllerPrivateData, 1);
1896 gettimeofday (&private->last_press_time, NULL);
1897 gettimeofday (&private->last_release_time, NULL);
1898 g_object_set_qdata (G_OBJECT (device_event_controller),
1899 spi_dec_private_quark,
1902 spi_controller_register_with_devices (device_event_controller);
1906 spi_device_event_controller_forward_key_event (SpiDEController *controller,
1907 const XEvent *event)
1909 gboolean is_consumed = FALSE;
1910 CORBA_Environment ev;
1911 Accessibility_DeviceEvent key_event;
1913 g_assert (event->type == KeyPress || event->type == KeyRelease);
1915 CORBA_exception_init (&ev);
1917 key_event = spi_keystroke_from_x_key_event ((XKeyEvent *) event);
1919 spi_controller_update_key_grabs (controller, &key_event);
1921 /* relay to listeners, and decide whether to consume it or not */
1922 is_consumed = spi_controller_notify_keylisteners (
1923 controller, &key_event, CORBA_TRUE, &ev);
1927 XAllowEvents (spi_get_display (), AsyncKeyboard, CurrentTime);
1931 XAllowEvents (spi_get_display (), ReplayKeyboard, CurrentTime);
1936 spi_device_event_controller_new (SpiRegistry *registry)
1938 SpiDEController *retval = g_object_new (
1939 SPI_DEVICE_EVENT_CONTROLLER_TYPE, NULL);
1940 DEControllerPrivateData *private;
1942 retval->registry = SPI_REGISTRY (bonobo_object_ref (
1943 BONOBO_OBJECT (registry)));
1945 spi_dec_init_mouse_listener (registry);
1946 /* TODO: kill mouse listener on finalize */
1950 BONOBO_TYPE_FUNC_FULL (SpiDEController,
1951 Accessibility_DeviceEventController,
1953 spi_device_event_controller);