2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5 * Copyright 2001, 2002 Sun Microsystems Inc.,
6 * Copyright 2001, 2002 Ximian, Inc.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
24 /* deviceeventcontroller.c: implement the DeviceEventController interface */
30 #undef SPI_KEYEVENT_DEBUG
35 #include <bonobo/bonobo-exception.h>
38 #include <X11/extensions/XTest.h>
39 #include <X11/XKBlib.h>
41 #include <X11/keysymdef.h>
43 #include <gdk/gdkx.h> /* TODO: hide dependency (wrap in single porting file) */
44 #include <gdk/gdkkeysyms.h>
45 #include <gdk/gdkwindow.h>
47 #include "../libspi/spi-private.h"
48 #include "deviceeventcontroller.h"
50 /* Our parent Gtk object type */
51 #define PARENT_TYPE BONOBO_TYPE_OBJECT
53 /* A pointer to our parent object class */
54 static GObjectClass *spi_device_event_controller_parent_class;
55 static int spi_error_code = 0;
56 static GdkPoint last_mouse_pos_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);
207 if (mask_return != mouse_mask_state) {
208 if ((mask_return & mouse_button_mask) !=
209 (mouse_mask_state & mouse_button_mask)) {
210 int button_number = 0;
211 if (!(mask_return & Button1Mask) &&
212 (mouse_mask_state & Button1Mask)) {
214 } else if (!(mask_return & Button2Mask) &&
215 (mouse_mask_state & Button2Mask)) {
217 } else if (!(mask_return & Button3Mask) &&
218 (mouse_mask_state & Button3Mask)) {
220 } else if (!(mask_return & Button4Mask) &&
221 (mouse_mask_state & Button1Mask)) {
223 } else if (!(mask_return & Button5Mask) &&
224 (mouse_mask_state & Button5Mask)) {
229 fprintf (stderr, "Button %d Released\n",
232 snprintf (event_name, 22, "mouse:button:%dr", button_number);
233 /* TODO: distinguish between physical and
236 mouse_e.type = Accessibility_BUTTON_RELEASED_EVENT;
237 mouse_e.id = button_number;
238 mouse_e.hw_code = button_number;
239 mouse_e.modifiers = (CORBA_unsigned_short)
241 mouse_e.timestamp = 0;
242 mouse_e.event_string = "";
243 mouse_e.is_text = CORBA_FALSE;
245 spi_controller_notify_mouselisteners (controller,
249 e.source = BONOBO_OBJREF (registry->desktop);
250 e.detail1 = last_mouse_pos->x;
251 e.detail2 = last_mouse_pos->y;
252 spi_init_any_nil (&e.any_data);
253 CORBA_exception_init (&ev);
255 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (registry),
260 if ((mask_return & key_modifier_mask) !=
261 (mouse_mask_state & key_modifier_mask)) {
263 fprintf (stderr, "MODIFIER CHANGE EVENT!\n");
265 e.type = "keyboard:modifiers";
266 e.source = BONOBO_OBJREF (registry->desktop);
267 e.detail1 = mouse_mask_state;
268 e.detail2 = mask_return;
269 spi_init_any_nil (&e.any_data);
270 CORBA_exception_init (&ev);
271 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (registry),
275 mouse_mask_state = mask_return;
277 if (poll_count++ == poll_count_modulus) {
279 e.type = "mouse:abs";
280 e.source = BONOBO_OBJREF (registry->desktop);
283 spi_init_any_nil (&e.any_data);
284 CORBA_exception_init (&ev);
285 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (registry),
289 if (x != last_mouse_pos->x || y != last_mouse_pos->y) {
290 e.type = "mouse:rel";
291 e.source = BONOBO_OBJREF (registry->desktop);
292 e.detail1 = x - last_mouse_pos->x;
293 e.detail2 = y - last_mouse_pos->y;
294 spi_init_any_nil (&e.any_data);
295 CORBA_exception_init (&ev);
296 last_mouse_pos->x = x;
297 last_mouse_pos->y = y;
298 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (registry),
307 spi_dec_poll_mouse_idle (gpointer data)
309 if (! spi_dec_poll_mouse_moved (data))
313 g_timeout_add (20, spi_dec_poll_mouse_moving, data);
319 spi_dec_poll_mouse_moving (gpointer data)
321 if (spi_dec_poll_mouse_moved (data))
325 g_timeout_add (100, spi_dec_poll_mouse_idle, data);
331 spi_dec_ungrab_mouse (gpointer data)
333 Display *display = spi_get_display ();
336 XUngrabButton (spi_get_display (), AnyButton, AnyModifier,
337 XDefaultRootWindow (spi_get_display ()));
343 spi_dec_init_mouse_listener (SpiRegistry *registry)
345 Display *display = spi_get_display ();
346 g_timeout_add (100, spi_dec_poll_mouse_idle, registry);
350 XGrabButton (display, AnyButton, AnyModifier,
351 gdk_x11_get_default_root_xwindow (),
352 True, ButtonPressMask | ButtonReleaseMask,
353 GrabModeSync, GrabModeAsync, None, None);
354 XSync (display, False);
356 fprintf (stderr, "mouse buttons grabbed\n");
361 static DEControllerKeyListener *
362 spi_dec_key_listener_new (CORBA_Object l,
363 const Accessibility_KeySet *keys,
364 const Accessibility_ControllerEventMask mask,
365 const Accessibility_EventTypeSeq *typeseq,
366 const Accessibility_EventListenerMode *mode,
367 CORBA_Environment *ev)
369 DEControllerKeyListener *key_listener = g_new0 (DEControllerKeyListener, 1);
370 key_listener->listener.object = bonobo_object_dup_ref (l, ev);
371 key_listener->listener.type = SPI_DEVICE_TYPE_KBD;
372 key_listener->keys = ORBit_copy_value (keys, TC_Accessibility_KeySet);
373 key_listener->mask = mask;
374 key_listener->listener.typeseq = ORBit_copy_value (typeseq, TC_Accessibility_EventTypeSeq);
376 key_listener->mode = ORBit_copy_value (mode, TC_Accessibility_EventListenerMode);
378 key_listener->mode = NULL;
381 g_print ("new listener, with mask %x, is_global %d, keys %p (%d)\n",
382 (unsigned int) key_listener->mask,
383 (int) (mode ? mode->global : 0),
384 (void *) key_listener->keys,
385 (int) (key_listener->keys ? key_listener->keys->_length : 0));
391 static DEControllerListener *
392 spi_dec_listener_new (CORBA_Object l,
393 const Accessibility_EventTypeSeq *typeseq,
394 CORBA_Environment *ev)
396 DEControllerListener *listener = g_new0 (DEControllerListener, 1);
397 listener->object = bonobo_object_dup_ref (l, ev);
398 listener->type = SPI_DEVICE_TYPE_MOUSE;
399 listener->typeseq = ORBit_copy_value (typeseq, TC_Accessibility_EventTypeSeq);
403 static DEControllerListener *
404 spi_listener_clone (DEControllerListener *listener, CORBA_Environment *ev)
406 DEControllerListener *clone = g_new0 (DEControllerListener, 1);
408 CORBA_Object_duplicate (listener->object, ev);
409 clone->type = listener->type;
410 clone->typeseq = ORBit_copy_value (listener->typeseq, TC_Accessibility_EventTypeSeq);
414 static DEControllerKeyListener *
415 spi_key_listener_clone (DEControllerKeyListener *key_listener, CORBA_Environment *ev)
417 DEControllerKeyListener *clone = g_new0 (DEControllerKeyListener, 1);
418 clone->listener.object =
419 CORBA_Object_duplicate (key_listener->listener.object, ev);
420 clone->listener.type = SPI_DEVICE_TYPE_KBD;
421 clone->keys = ORBit_copy_value (key_listener->keys, TC_Accessibility_KeySet);
422 clone->mask = key_listener->mask;
423 clone->listener.typeseq = ORBit_copy_value (key_listener->listener.typeseq, TC_Accessibility_EventTypeSeq);
424 if (key_listener->mode)
425 clone->mode = ORBit_copy_value (key_listener->mode, TC_Accessibility_EventListenerMode);
432 spi_key_listener_data_free (DEControllerKeyListener *key_listener, CORBA_Environment *ev)
434 CORBA_free (key_listener->listener.typeseq);
435 CORBA_free (key_listener->keys);
436 g_free (key_listener);
440 spi_key_listener_clone_free (DEControllerKeyListener *clone, CORBA_Environment *ev)
442 CORBA_Object_release (clone->listener.object, ev);
443 spi_key_listener_data_free (clone, ev);
447 spi_listener_clone_free (DEControllerListener *clone, CORBA_Environment *ev)
449 CORBA_Object_release (clone->object, ev);
450 CORBA_free (clone->typeseq);
455 spi_dec_listener_free (DEControllerListener *listener,
456 CORBA_Environment *ev)
458 bonobo_object_release_unref (listener->object, ev);
459 if (listener->type == SPI_DEVICE_TYPE_KBD)
460 spi_key_listener_data_free ((DEControllerKeyListener *) listener, ev);
464 _register_keygrab (SpiDEController *controller,
465 DEControllerGrabMask *grab_mask)
469 l = g_list_find_custom (controller->keygrabs_list, grab_mask,
470 spi_grab_mask_compare_values);
473 DEControllerGrabMask *cur_mask = l->data;
475 cur_mask->ref_count++;
476 if (cur_mask->pending_remove)
478 cur_mask->pending_remove = FALSE;
483 controller->keygrabs_list =
484 g_list_prepend (controller->keygrabs_list,
485 spi_grab_mask_clone (grab_mask));
490 _deregister_keygrab (SpiDEController *controller,
491 DEControllerGrabMask *grab_mask)
495 l = g_list_find_custom (controller->keygrabs_list, grab_mask,
496 spi_grab_mask_compare_values);
500 DEControllerGrabMask *cur_mask = l->data;
502 cur_mask->ref_count--;
503 if (cur_mask->ref_count <= 0)
505 cur_mask->pending_remove = TRUE;
510 DBG (1, g_warning ("De-registering non-existant grab"));
515 handle_keygrab (SpiDEController *controller,
516 DEControllerKeyListener *key_listener,
517 void (*process_cb) (SpiDEController *controller,
518 DEControllerGrabMask *grab_mask))
520 DEControllerGrabMask grab_mask = { 0 };
522 grab_mask.mod_mask = key_listener->mask;
523 if (key_listener->keys->_length == 0) /* special case means AnyKey/AllKeys */
525 grab_mask.key_val = AnyKey;
527 fprintf (stderr, "AnyKey grab!");
529 process_cb (controller, &grab_mask);
535 for (i = 0; i < key_listener->keys->_length; ++i)
537 Accessibility_KeyDefinition keydef = key_listener->keys->_buffer[i];
538 long int key_val = keydef.keysym;
539 /* X Grabs require keycodes, not keysyms */
540 if (keydef.keystring && keydef.keystring[0])
542 key_val = XStringToKeysym(keydef.keystring);
546 key_val = XKeysymToKeycode (spi_get_display (), (KeySym) key_val);
550 key_val = keydef.keycode;
552 grab_mask.key_val = key_val;
553 process_cb (controller, &grab_mask);
559 spi_controller_register_global_keygrabs (SpiDEController *controller,
560 DEControllerKeyListener *key_listener)
562 handle_keygrab (controller, key_listener, _register_keygrab);
563 return spi_controller_update_key_grabs (controller, NULL);
567 spi_controller_deregister_global_keygrabs (SpiDEController *controller,
568 DEControllerKeyListener *key_listener)
570 handle_keygrab (controller, key_listener, _deregister_keygrab);
571 spi_controller_update_key_grabs (controller, NULL);
575 spi_controller_register_device_listener (SpiDEController *controller,
576 DEControllerListener *listener,
577 CORBA_Environment *ev)
579 DEControllerKeyListener *key_listener;
581 switch (listener->type) {
582 case SPI_DEVICE_TYPE_KBD:
583 key_listener = (DEControllerKeyListener *) listener;
585 controller->key_listeners = g_list_prepend (controller->key_listeners,
587 if (key_listener->mode->global)
589 return spi_controller_register_global_keygrabs (controller, key_listener);
594 case SPI_DEVICE_TYPE_MOUSE:
595 controller->mouse_listeners = g_list_prepend (controller->mouse_listeners, listener);
598 DBG (1, g_warning ("listener registration for unknown device type.\n"));
605 spi_controller_notify_mouselisteners (SpiDEController *controller,
606 const Accessibility_DeviceEvent *event,
607 CORBA_Environment *ev)
610 GSList *notify = NULL, *l2;
611 GList **listeners = &controller->mouse_listeners;
612 gboolean is_consumed;
619 for (l = *listeners; l; l = l->next)
621 DEControllerListener *listener = l->data;
623 if (spi_eventtype_seq_contains_event (listener->typeseq, event))
625 Accessibility_DeviceEventListener ls = listener->object;
627 if (ls != CORBA_OBJECT_NIL)
629 /* we clone (don't dup) the listener, to avoid refcount inc. */
630 notify = g_slist_prepend (notify,
631 spi_listener_clone (listener, ev));
636 #ifdef SPI_KEYEVENT_DEBUG
639 g_print ("no match for event\n");
644 for (l2 = notify; l2 && !is_consumed; l2 = l2->next)
646 DEControllerListener *listener = l2->data;
647 Accessibility_DeviceEventListener ls = listener->object;
649 CORBA_exception_init (ev);
650 is_consumed = Accessibility_DeviceEventListener_notifyEvent (ls, event, ev);
654 DBG (2, g_warning ("error notifying listener, removing it\n"));
655 spi_deregister_controller_device_listener (controller, listener,
657 CORBA_exception_free (ev);
660 spi_listener_clone_free ((DEControllerListener *) l2->data, ev);
663 for (; l2; l2 = l2->next)
665 DEControllerListener *listener = l2->data;
666 spi_listener_clone_free (listener, ev);
667 /* clone doesn't have its own ref, so don't use spi_device_listener_free */
670 g_slist_free (notify);
673 if (is_consumed) g_message ("consumed\n");
679 spi_device_event_controller_forward_mouse_event (SpiDEController *controller,
682 Accessibility_Event e;
683 Accessibility_DeviceEvent mouse_e;
684 CORBA_Environment ev;
685 gchar event_name[24];
686 gboolean is_consumed = FALSE;
687 gboolean xkb_mod_unlatch_occurred;
688 DEControllerPrivateData *priv;
689 XButtonEvent *xbutton_event = (XButtonEvent *) xevent;
691 int button = xbutton_event->button;
693 unsigned int mouse_button_state = xbutton_event->state;
698 mouse_button_state |= Button1Mask;
701 mouse_button_state |= Button2Mask;
704 mouse_button_state |= Button3Mask;
707 mouse_button_state |= Button4Mask;
710 mouse_button_state |= Button5Mask;
713 last_mouse_pos->x = ((XButtonEvent *) xevent)->x_root;
714 last_mouse_pos->y = ((XButtonEvent *) xevent)->y_root;
717 fprintf (stderr, "mouse button %d %s (%x)\n",
718 xbutton_event->button,
719 (xevent->type == ButtonPress) ? "Press" : "Release",
722 snprintf (event_name, 22, "mouse:button:%d%c", button,
723 (xevent->type == ButtonPress) ? 'p' : 'r');
725 /* TODO: distinguish between physical and logical buttons */
726 mouse_e.type = (xevent->type == ButtonPress) ?
727 Accessibility_BUTTON_PRESSED_EVENT :
728 Accessibility_BUTTON_RELEASED_EVENT;
730 mouse_e.hw_code = button;
731 mouse_e.modifiers = (CORBA_unsigned_short) xbutton_event->state;
732 mouse_e.timestamp = (CORBA_unsigned_long) xbutton_event->time;
733 mouse_e.event_string = "";
734 mouse_e.is_text = CORBA_FALSE;
735 is_consumed = spi_controller_notify_mouselisteners (controller, &mouse_e, &ev);
737 e.type = CORBA_string_dup (event_name);
738 e.source = BONOBO_OBJREF (controller->registry->desktop);
739 e.detail1 = last_mouse_pos->x;
740 e.detail2 = last_mouse_pos->y;
741 spi_init_any_nil (&e.any_data);
742 CORBA_exception_init (&ev);
744 Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry),
748 xkb_mod_unlatch_occurred = (xevent->type == ButtonPress ||
749 xevent->type == ButtonRelease);
751 /* if client wants to consume this event, and XKB latch state was
752 * unset by this button event, we reset it
754 if (is_consumed && xkb_mod_unlatch_occurred)
756 priv = g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
757 priv->pending_xkb_mod_relatch_mask |= priv->xkb_latch_mask;
760 XAllowEvents (spi_get_display (),
761 (is_consumed) ? SyncPointer : ReplayPointer,
765 static GdkFilterReturn
766 global_filter_fn (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
768 XEvent *xevent = gdk_xevent;
769 SpiDEController *controller;
770 DEControllerPrivateData *priv;
771 Display *display = spi_get_display ();
772 controller = SPI_DEVICE_EVENT_CONTROLLER (data);
773 priv = (DEControllerPrivateData *)
774 g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
776 if (xevent->type == KeyPress || xevent->type == KeyRelease)
778 spi_device_event_controller_forward_key_event (controller, xevent);
779 return GDK_FILTER_CONTINUE;
781 if (xevent->type == ButtonPress || xevent->type == ButtonRelease)
783 spi_device_event_controller_forward_mouse_event (controller, xevent);
785 if (xevent->type == priv->xkb_base_event_code)
787 XkbAnyEvent * xkb_ev = (XkbAnyEvent *) xevent;
789 if (xkb_ev->xkb_type == XkbStateNotify)
791 XkbStateNotifyEvent *xkb_snev =
792 (XkbStateNotifyEvent *) xkb_ev;
793 priv->xkb_latch_mask = xkb_snev->latched_mods;
794 if (priv->pending_xkb_mod_relatch_mask)
796 unsigned int feedback_mask;
798 fprintf (stderr, "relatching %x\n",
799 priv->pending_xkb_mod_relatch_mask);
801 /* temporarily turn off the latch bell, if it's on */
802 XkbGetControls (display,
803 XkbAccessXFeedbackMask,
805 feedback_mask = priv->xkb_desc->ctrls->ax_options;
806 if (feedback_mask & XkbAX_StickyKeysFBMask)
808 XkbControlsChangesRec changes = {XkbAccessXFeedbackMask,
810 priv->xkb_desc->ctrls->ax_options
811 &= ~(XkbAX_StickyKeysFBMask);
812 XkbChangeControls (display, priv->xkb_desc, &changes);
814 XkbLatchModifiers (display,
816 priv->pending_xkb_mod_relatch_mask,
817 priv->pending_xkb_mod_relatch_mask);
818 if (feedback_mask & XkbAX_StickyKeysFBMask)
820 XkbControlsChangesRec changes = {XkbAccessXFeedbackMask,
822 priv->xkb_desc->ctrls->ax_options = feedback_mask;
823 XkbChangeControls (display, priv->xkb_desc, &changes);
826 fprintf (stderr, "relatched %x\n",
827 priv->pending_xkb_mod_relatch_mask);
829 priv->pending_xkb_mod_relatch_mask = 0;
833 DBG (2, g_warning ("XKB event %d\n", xkb_ev->xkb_type));
836 return GDK_FILTER_CONTINUE;
840 _spi_controller_device_error_handler (Display *display, XErrorEvent *error)
842 if (error->error_code == BadAccess)
844 g_message ("Could not complete key grab: grab already in use.\n");
845 spi_error_code = BadAccess;
850 return (*x_default_error_handler) (display, error);
855 spi_controller_register_with_devices (SpiDEController *controller)
857 DEControllerPrivateData *priv = (DEControllerPrivateData *)
858 g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
860 priv->xkb_desc = XkbGetMap (spi_get_display (), 0, XkbUseCoreKbd);
862 /* calls to device-specific implementations and routines go here */
863 /* register with: keyboard hardware code handler */
864 /* register with: (translated) keystroke handler */
866 priv->have_xkb = XkbQueryExtension (spi_get_display (),
867 &priv->xkb_major_extension_opcode,
868 &priv->xkb_base_event_code,
869 &priv->xkb_base_error_code, NULL, NULL);
872 XkbSelectEvents (spi_get_display (),
874 XkbStateNotifyMask, XkbStateNotifyMask);
876 gdk_window_add_filter (NULL, global_filter_fn, controller);
878 gdk_window_set_events (gdk_get_default_root_window (),
879 GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
881 x_default_error_handler = XSetErrorHandler (_spi_controller_device_error_handler);
885 spi_key_set_contains_key (Accessibility_KeySet *key_set,
886 const Accessibility_DeviceEvent *key_event)
893 g_print ("null key set!");
897 len = key_set->_length;
899 if (len == 0) /* special case, means "all keys/any key" */
901 g_print ("anykey\n");
905 for (i = 0; i < len; ++i)
907 #ifdef SPI_KEYEVENT_DEBUG
908 g_print ("key_set[%d] = %d; key_event %d, code %d, string %s\n",
909 i, (int) key_set->_buffer[i].keycode,
910 (int) key_event->id, (int) key_event->hw_code,
911 key_event->event_string);
913 if (key_set->_buffer[i].keysym == (CORBA_long) key_event->id)
917 if (key_set->_buffer[i].keycode == (CORBA_long) key_event->hw_code)
921 if (key_event->event_string && key_event->event_string[0] &&
922 !strcmp (key_set->_buffer[i].keystring, key_event->event_string))
932 spi_eventtype_seq_contains_event (Accessibility_EventTypeSeq *type_seq,
933 const Accessibility_DeviceEvent *event)
941 g_print ("null type seq!");
945 len = type_seq->_length;
947 if (len == 0) /* special case, means "all events/any event" */
952 for (i = 0; i < len; ++i)
955 g_print ("type_seq[%d] = %d; event type = %d\n", i,
956 (int) type_seq->_buffer[i], (int) event->type);
958 if (type_seq->_buffer[i] == (CORBA_long) event->type)
968 spi_key_event_matches_listener (const Accessibility_DeviceEvent *key_event,
969 DEControllerKeyListener *listener,
970 CORBA_boolean is_system_global)
972 if ((key_event->modifiers == (CORBA_unsigned_short) (listener->mask & 0xFFFF)) &&
973 spi_key_set_contains_key (listener->keys, key_event) &&
974 spi_eventtype_seq_contains_event (listener->listener.typeseq, key_event) &&
975 (is_system_global == listener->mode->global))
986 spi_controller_notify_keylisteners (SpiDEController *controller,
987 const Accessibility_DeviceEvent *key_event,
988 CORBA_boolean is_system_global,
989 CORBA_Environment *ev)
992 GSList *notify = NULL, *l2;
993 GList **key_listeners = &controller->key_listeners;
994 gboolean is_consumed;
1001 for (l = *key_listeners; l; l = l->next)
1003 DEControllerKeyListener *key_listener = l->data;
1005 if (spi_key_event_matches_listener (key_event, key_listener, is_system_global))
1007 Accessibility_DeviceEventListener ls = key_listener->listener.object;
1009 if (ls != CORBA_OBJECT_NIL)
1011 /* we clone (don't dup) the listener, to avoid refcount inc. */
1012 notify = g_slist_prepend (notify,
1013 spi_key_listener_clone (key_listener, ev));
1018 #ifdef SPI_KEYEVENT_DEBUG
1021 g_print ("no match for event\n");
1025 is_consumed = FALSE;
1026 for (l2 = notify; l2 && !is_consumed; l2 = l2->next)
1028 DEControllerKeyListener *key_listener = l2->data;
1029 Accessibility_DeviceEventListener ls = key_listener->listener.object;
1031 is_consumed = Accessibility_DeviceEventListener_notifyEvent (ls, key_event, ev);
1035 is_consumed = FALSE;
1036 spi_deregister_controller_key_listener (controller, key_listener,
1038 CORBA_exception_free (ev);
1041 spi_key_listener_clone_free (key_listener, ev);
1044 for (; l2; l2 = l2->next)
1046 DEControllerKeyListener *key_listener = l2->data;
1047 spi_key_listener_clone_free (key_listener, ev);
1048 /* clone doesn't have its own ref, so don't use spi_dec_listener_free */
1051 g_slist_free (notify);
1054 if (is_consumed) g_message ("consumed\n");
1060 spi_clear_error_state ()
1062 gboolean retval = spi_error_code != 0;
1067 static Accessibility_DeviceEvent
1068 spi_keystroke_from_x_key_event (XKeyEvent *x_key_event)
1070 Accessibility_DeviceEvent key_event;
1072 const int cbuf_bytes = 20;
1073 char cbuf [cbuf_bytes];
1075 keysym = XLookupKeysym (x_key_event, 0);
1076 key_event.id = (CORBA_long)(keysym);
1077 key_event.hw_code = (CORBA_short) x_key_event->keycode;
1078 if (((XEvent *) x_key_event)->type == KeyPress)
1080 key_event.type = Accessibility_KEY_PRESSED;
1084 key_event.type = Accessibility_KEY_RELEASED;
1086 key_event.modifiers = (CORBA_unsigned_short)(x_key_event->state);
1087 key_event.is_text = CORBA_FALSE;
1091 key_event.event_string = CORBA_string_dup ("space");
1094 #ifdef SPI_KEYEVENT_DEBUG
1095 fprintf(stderr, "Tab\n");
1097 key_event.event_string = CORBA_string_dup ("Tab");
1100 key_event.event_string = CORBA_string_dup ("Backspace");
1103 key_event.event_string = CORBA_string_dup ("Return");
1106 key_event.event_string = CORBA_string_dup ("Home");
1109 key_event.event_string = CORBA_string_dup ("Page_Down");
1112 key_event.event_string = CORBA_string_dup ("Page_Up");
1115 key_event.event_string = CORBA_string_dup ("F1");
1118 key_event.event_string = CORBA_string_dup ("F2");
1121 key_event.event_string = CORBA_string_dup ("F3");
1124 key_event.event_string = CORBA_string_dup ("F4");
1127 key_event.event_string = CORBA_string_dup ("F5");
1130 key_event.event_string = CORBA_string_dup ("F6");
1133 key_event.event_string = CORBA_string_dup ("F7");
1136 key_event.event_string = CORBA_string_dup ("F8");
1139 key_event.event_string = CORBA_string_dup ("F9");
1142 key_event.event_string = CORBA_string_dup ("F10");
1145 key_event.event_string = CORBA_string_dup ("F11");
1148 key_event.event_string = CORBA_string_dup ("F12");
1151 key_event.event_string = CORBA_string_dup ("End");
1154 key_event.event_string = CORBA_string_dup ("Escape");
1157 key_event.event_string = CORBA_string_dup ("Up");
1160 key_event.event_string = CORBA_string_dup ("Down");
1163 key_event.event_string = CORBA_string_dup ("Left");
1166 key_event.event_string = CORBA_string_dup ("Right");
1169 if (XLookupString (x_key_event, cbuf, cbuf_bytes, &keysym, NULL) > 0)
1171 key_event.event_string = CORBA_string_dup (cbuf);
1172 if (isgraph (keysym))
1174 key_event.is_text = CORBA_TRUE; /* FIXME: incorrect for some composed chars? */
1179 key_event.event_string = CORBA_string_dup ("");
1183 key_event.timestamp = (CORBA_unsigned_long) x_key_event->time;
1184 #ifdef SPI_KEYEVENT_DEBUG
1186 "Key %lu pressed (%c), modifiers %d\n",
1187 (unsigned long) keysym,
1188 keysym ? (int) keysym : '*',
1189 (int) x_key_event->state);
1192 fprintf (stderr, "%s%c",
1193 (x_key_event->state & Mod1Mask)?"Alt-":"",
1194 ((x_key_event->state & ShiftMask)^(x_key_event->state & LockMask))?
1195 g_ascii_toupper (keysym) : g_ascii_tolower (keysym));
1196 #endif /* SPI_DEBUG */
1201 spi_controller_update_key_grabs (SpiDEController *controller,
1202 Accessibility_DeviceEvent *recv)
1205 gboolean update_failed = FALSE;
1207 g_return_val_if_fail (controller != NULL, FALSE);
1210 * masks known to work with default RH 7.1+:
1211 * 0 (no mods), LockMask, Mod1Mask, Mod2Mask, ShiftMask,
1212 * ShiftMask|LockMask, Mod1Mask|LockMask, Mod2Mask|LockMask,
1213 * ShiftMask|Mod1Mask, ShiftMask|Mod2Mask, Mod1Mask|Mod2Mask,
1214 * ShiftMask|LockMask|Mod1Mask, ShiftMask|LockMask|Mod2Mask,
1216 * ControlMask grabs are broken, must be in use already
1218 for (l = controller->keygrabs_list; l; l = next)
1221 gboolean re_issue_grab;
1222 DEControllerGrabMask *grab_mask = l->data;
1226 re_issue_grab = recv &&
1227 /* (recv->type == Accessibility_KEY_RELEASED) && - (?) */
1228 (recv->modifiers & grab_mask->mod_mask) &&
1229 (grab_mask->key_val == keycode_for_keysym (recv->id));
1232 fprintf (stderr, "mask=%lx %lx (%c%c) %s\n",
1233 (long int) grab_mask->key_val,
1234 (long int) grab_mask->mod_mask,
1235 grab_mask->pending_add ? '+' : '.',
1236 grab_mask->pending_remove ? '-' : '.',
1237 re_issue_grab ? "re-issue": "");
1242 if (grab_mask->pending_add && grab_mask->pending_remove)
1246 else if (grab_mask->pending_remove)
1249 fprintf (stderr, "ungrabbing, mask=%x\n", grab_mask->mod_mask);
1251 XUngrabKey (spi_get_display (),
1253 grab_mask->mod_mask,
1254 gdk_x11_get_default_root_xwindow ());
1258 else if (grab_mask->pending_add || re_issue_grab)
1262 fprintf (stderr, "grab %d with mask %x\n", grab_mask->key_val, grab_mask->mod_mask);
1264 XGrabKey (spi_get_display (),
1266 grab_mask->mod_mask,
1267 gdk_x11_get_default_root_xwindow (),
1271 XSync (spi_get_display (), False);
1272 update_failed = spi_clear_error_state ();
1273 if (update_failed) {
1274 while (grab_mask->ref_count > 0) --grab_mask->ref_count;
1279 grab_mask->pending_add = FALSE;
1280 grab_mask->pending_remove = FALSE;
1284 g_assert (grab_mask->ref_count <= 0);
1286 controller->keygrabs_list = g_list_delete_link (
1287 controller->keygrabs_list, l);
1289 spi_grab_mask_free (grab_mask);
1294 return ! update_failed;
1298 * Implemented GObject::finalize
1301 spi_device_event_controller_object_finalize (GObject *object)
1303 SpiDEController *controller;
1304 DEControllerPrivateData *private;
1305 controller = SPI_DEVICE_EVENT_CONTROLLER (object);
1308 fprintf(stderr, "spi_device_event_controller_object_finalize called\n");
1310 /* disconnect any special listeners, get rid of outstanding keygrabs */
1311 XUngrabKey (spi_get_display (), AnyKey, AnyModifier, DefaultRootWindow (spi_get_display ()));
1313 private = g_object_get_data (G_OBJECT (controller), "spi-dec-private");
1314 if (private->xkb_desc)
1315 XkbFreeKeyboard (private->xkb_desc, 0, True);
1317 spi_device_event_controller_parent_class->finalize (object);
1321 * CORBA Accessibility::DEController::registerKeystrokeListener
1322 * method implementation
1324 static CORBA_boolean
1325 impl_register_keystroke_listener (PortableServer_Servant servant,
1326 const Accessibility_DeviceEventListener l,
1327 const Accessibility_KeySet *keys,
1328 const Accessibility_ControllerEventMask mask,
1329 const Accessibility_EventTypeSeq *type,
1330 const Accessibility_EventListenerMode *mode,
1331 CORBA_Environment *ev)
1333 SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1334 bonobo_object_from_servant (servant));
1335 DEControllerKeyListener *dec_listener;
1337 fprintf (stderr, "registering keystroke listener %p with maskVal %lu\n",
1338 (void *) l, (unsigned long) mask);
1340 dec_listener = spi_dec_key_listener_new (l, keys, mask, type, mode, ev);
1341 return spi_controller_register_device_listener (
1342 controller, (DEControllerListener *) dec_listener, ev);
1347 * CORBA Accessibility::DEController::registerDeviceEventListener
1348 * method implementation
1350 static CORBA_boolean
1351 impl_register_device_listener (PortableServer_Servant servant,
1352 const Accessibility_DeviceEventListener l,
1353 const Accessibility_EventTypeSeq *event_types,
1354 CORBA_Environment *ev)
1356 SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1357 bonobo_object_from_servant (servant));
1358 DEControllerListener *dec_listener;
1360 dec_listener = spi_dec_listener_new (l, event_types, ev);
1361 return spi_controller_register_device_listener (
1362 controller, (DEControllerListener *) dec_listener, ev);
1366 CORBA_Environment *ev;
1367 DEControllerListener *listener;
1368 } RemoveListenerClosure;
1370 static SpiReEntrantContinue
1371 remove_listener_cb (GList * const *list,
1374 DEControllerListener *listener = (*list)->data;
1375 RemoveListenerClosure *ctx = user_data;
1377 if (CORBA_Object_is_equivalent (ctx->listener->object,
1378 listener->object, ctx->ev))
1380 spi_re_entrant_list_delete_link (list);
1381 spi_dec_listener_free (listener, ctx->ev);
1384 return SPI_RE_ENTRANT_CONTINUE;
1387 static SpiReEntrantContinue
1388 copy_key_listener_cb (GList * const *list,
1391 DEControllerKeyListener *key_listener = (*list)->data;
1392 RemoveListenerClosure *ctx = user_data;
1394 if (CORBA_Object_is_equivalent (ctx->listener->object,
1395 key_listener->listener.object, ctx->ev))
1397 /* TODO: FIXME aggregate keys in case the listener is registered twice */
1398 DEControllerKeyListener *ctx_key_listener =
1399 (DEControllerKeyListener *) ctx->listener;
1400 CORBA_free (ctx_key_listener->keys);
1401 ctx_key_listener->keys = ORBit_copy_value (key_listener->keys, TC_Accessibility_KeySet);
1404 return SPI_RE_ENTRANT_CONTINUE;
1408 spi_deregister_controller_device_listener (SpiDEController *controller,
1409 DEControllerListener *listener,
1410 CORBA_Environment *ev)
1412 RemoveListenerClosure ctx;
1415 ctx.listener = listener;
1417 spi_re_entrant_list_foreach (&controller->mouse_listeners,
1418 remove_listener_cb, &ctx);
1422 spi_deregister_controller_key_listener (SpiDEController *controller,
1423 DEControllerKeyListener *key_listener,
1424 CORBA_Environment *ev)
1426 RemoveListenerClosure ctx;
1429 ctx.listener = (DEControllerListener *) key_listener;
1431 /* special case, copy keyset from existing controller list entry */
1432 if (key_listener->keys->_length == 0)
1434 spi_re_entrant_list_foreach (&controller->key_listeners,
1435 copy_key_listener_cb, &ctx);
1438 spi_controller_deregister_global_keygrabs (controller, key_listener);
1440 spi_re_entrant_list_foreach (&controller->key_listeners,
1441 remove_listener_cb, &ctx);
1446 * CORBA Accessibility::DEController::deregisterKeystrokeListener
1447 * method implementation
1450 impl_deregister_keystroke_listener (PortableServer_Servant servant,
1451 const Accessibility_DeviceEventListener l,
1452 const Accessibility_KeySet *keys,
1453 const Accessibility_ControllerEventMask mask,
1454 const Accessibility_EventTypeSeq *type,
1455 CORBA_Environment *ev)
1457 DEControllerKeyListener *key_listener;
1458 SpiDEController *controller;
1460 controller = SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
1462 key_listener = spi_dec_key_listener_new (l, keys, mask, type, NULL, ev);
1464 #ifdef SPI_DEREGISTER_DEBUG
1465 fprintf (stderr, "deregistering keystroke listener %p with maskVal %lu\n",
1466 (void *) l, (unsigned long) mask->value);
1469 spi_deregister_controller_key_listener (controller, key_listener, ev);
1471 spi_dec_listener_free ((DEControllerListener *) key_listener, ev);
1475 * CORBA Accessibility::DEController::deregisterDeviceEventListener
1476 * method implementation
1479 impl_deregister_device_listener (PortableServer_Servant servant,
1480 const Accessibility_DeviceEventListener l,
1481 const Accessibility_EventTypeSeq *event_types,
1482 CORBA_Environment *ev)
1484 SpiDEController *controller;
1485 DEControllerListener *listener =
1486 spi_dec_listener_new (l, event_types, ev);
1488 controller = SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
1490 spi_deregister_controller_device_listener (controller, listener, ev);
1492 spi_dec_listener_free (listener, ev);
1495 static unsigned int dec_xkb_get_slowkeys_delay (SpiDEController *controller)
1497 unsigned int retval = 0;
1498 DEControllerPrivateData *priv = (DEControllerPrivateData *)
1499 g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
1501 #ifdef XKB_HAS_GET_SLOW_KEYS_DELAY
1502 retval = XkbGetSlowKeysDelay (spi_get_display (),
1503 XkbUseCoreKbd, &bounce_delay);
1505 if (!(priv->xkb_desc == (XkbDescPtr) BadAlloc || priv->xkb_desc == NULL))
1507 Status s = XkbGetControls (spi_get_display (),
1508 XkbAllControlsMask, priv->xkb_desc);
1511 if (priv->xkb_desc->ctrls->enabled_ctrls & XkbSlowKeysMask)
1512 retval = priv->xkb_desc->ctrls->slow_keys_delay;
1517 #ifdef SPI_XKB_DEBUG
1518 fprintf (stderr, "SlowKeys delay: %d\n", (int) retval);
1523 static unsigned int dec_xkb_get_bouncekeys_delay (SpiDEController *controller)
1525 unsigned int retval = 0;
1526 DEControllerPrivateData *priv = (DEControllerPrivateData *)
1527 g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
1529 #ifdef XKB_HAS_GET_BOUNCE_KEYS_DELAY
1530 retval = XkbGetBounceKeysDelay (spi_get_display (),
1531 XkbUseCoreKbd, &bounce_delay);
1533 if (!(priv->xkb_desc == (XkbDescPtr) BadAlloc || priv->xkb_desc == NULL))
1535 Status s = XkbGetControls (spi_get_display (),
1536 XkbAllControlsMask, priv->xkb_desc);
1539 if (priv->xkb_desc->ctrls->enabled_ctrls & XkbBounceKeysMask)
1540 retval = priv->xkb_desc->ctrls->debounce_delay;
1545 #ifdef SPI_XKB_DEBUG
1546 fprintf (stderr, "BounceKeys delay: %d\n", (int) retval);
1552 dec_synth_keycode_press (SpiDEController *controller,
1553 unsigned int keycode)
1555 unsigned int time = CurrentTime;
1556 unsigned int bounce_delay;
1557 unsigned int elapsed_msec;
1559 DEControllerPrivateData *priv =
1560 (DEControllerPrivateData *) g_object_get_qdata (G_OBJECT (controller),
1561 spi_dec_private_quark);
1562 if (keycode == priv->last_release_keycode)
1564 bounce_delay = dec_xkb_get_bouncekeys_delay (controller);
1567 gettimeofday (&tv, NULL);
1569 (tv.tv_sec - priv->last_release_time.tv_sec) * 1000
1570 + (tv.tv_usec - priv->last_release_time.tv_usec) / 1000;
1571 #ifdef SPI_XKB_DEBUG
1572 fprintf (stderr, "%d ms elapsed (%ld usec)\n", elapsed_msec,
1573 (long) (tv.tv_usec - priv->last_release_time.tv_usec));
1575 #ifdef THIS_IS_BROKEN
1576 if (elapsed_msec < bounce_delay)
1577 time = bounce_delay - elapsed_msec + 1;
1579 time = bounce_delay + 10;
1580 /* fudge for broken XTest */
1582 #ifdef SPI_XKB_DEBUG
1583 fprintf (stderr, "waiting %d ms\n", time);
1587 XTestFakeKeyEvent (spi_get_display (), keycode, True, time);
1588 priv->last_press_keycode = keycode;
1589 XSync (spi_get_display (), False);
1590 gettimeofday (&priv->last_press_time, NULL);
1595 dec_synth_keycode_release (SpiDEController *controller,
1596 unsigned int keycode)
1598 unsigned int time = CurrentTime;
1599 unsigned int slow_delay;
1600 unsigned int elapsed_msec;
1602 DEControllerPrivateData *priv =
1603 (DEControllerPrivateData *) g_object_get_qdata (G_OBJECT (controller),
1604 spi_dec_private_quark);
1605 if (keycode == priv->last_press_keycode)
1607 slow_delay = dec_xkb_get_slowkeys_delay (controller);
1610 gettimeofday (&tv, NULL);
1612 (tv.tv_sec - priv->last_press_time.tv_sec) * 1000
1613 + (tv.tv_usec - priv->last_press_time.tv_usec) / 1000;
1614 #ifdef SPI_XKB_DEBUG
1615 fprintf (stderr, "%d ms elapsed (%ld usec)\n", elapsed_msec,
1616 (long) (tv.tv_usec - priv->last_press_time.tv_usec));
1618 #ifdef THIS_IS_BROKEN_DUNNO_WHY
1619 if (elapsed_msec < slow_delay)
1620 time = slow_delay - elapsed_msec + 1;
1622 time = slow_delay + 10;
1623 /* our XTest seems broken, we have to add slop as above */
1625 #ifdef SPI_XKB_DEBUG
1626 fprintf (stderr, "waiting %d ms\n", time);
1630 XTestFakeKeyEvent (spi_get_display (), keycode, False, time);
1631 priv->last_release_keycode = keycode;
1632 XSync (spi_get_display (), False);
1633 gettimeofday (&priv->last_release_time, NULL);
1638 * CORBA Accessibility::DEController::registerKeystrokeListener
1639 * method implementation
1642 impl_generate_keyboard_event (PortableServer_Servant servant,
1643 const CORBA_long keycode,
1644 const CORBA_char *keystring,
1645 const Accessibility_KeySynthType synth_type,
1646 CORBA_Environment *ev)
1648 SpiDEController *controller =
1649 SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
1650 long key_synth_code;
1651 unsigned int slow_keys_delay;
1652 unsigned int press_time;
1653 unsigned int release_time;
1656 fprintf (stderr, "synthesizing keystroke %ld, type %d\n",
1657 (long) keycode, (int) synth_type);
1659 /* TODO: hide/wrap/remove X dependency */
1662 * TODO: when initializing, query for XTest extension before using,
1663 * and fall back to XSendEvent() if XTest is not available.
1666 /* TODO: implement keystring mode also */
1667 gdk_error_trap_push ();
1671 case Accessibility_KEY_PRESS:
1672 dec_synth_keycode_press (controller, keycode);
1674 case Accessibility_KEY_PRESSRELEASE:
1675 dec_synth_keycode_press (controller, keycode);
1676 case Accessibility_KEY_RELEASE:
1677 dec_synth_keycode_release (controller, keycode);
1679 case Accessibility_KEY_SYM:
1680 #ifdef SPI_XKB_DEBUG
1681 fprintf (stderr, "KeySym synthesis\n");
1683 key_synth_code = keycode_for_keysym (keycode);
1684 dec_synth_keycode_press (controller, key_synth_code);
1685 dec_synth_keycode_release (controller, key_synth_code);
1687 case Accessibility_KEY_STRING:
1688 fprintf (stderr, "Not yet implemented\n");
1691 if (gdk_error_trap_pop ())
1693 DBG (-1, g_warning ("Error emitting keystroke"));
1697 /* Accessibility::DEController::generateMouseEvent */
1699 impl_generate_mouse_event (PortableServer_Servant servant,
1702 const CORBA_char *eventName,
1703 CORBA_Environment *ev)
1706 gboolean error = FALSE;
1707 Display *display = spi_get_display ();
1709 fprintf (stderr, "generating mouse %s event at %ld, %ld\n",
1710 eventName, (long int) x, (long int) y);
1712 switch (eventName[0])
1715 switch (eventName[1])
1717 /* TODO: check number of buttons before parsing */
1732 if (x != -1 && y != -1)
1734 XTestFakeMotionEvent (display, DefaultScreen (display),
1737 XTestFakeButtonEvent (display, button, !(eventName[2] == 'r'), 0);
1738 if (eventName[2] == 'c')
1739 XTestFakeButtonEvent (display, button, FALSE, 1);
1740 else if (eventName[2] == 'd')
1742 XTestFakeButtonEvent (display, button, FALSE, 1);
1743 XTestFakeButtonEvent (display, button, TRUE, 2);
1744 XTestFakeButtonEvent (display, button, FALSE, 3);
1748 case 'r': /* relative motion */
1749 XTestFakeRelativeMotionEvent (display, x, y, 0);
1751 case 'a': /* absolute motion */
1752 XTestFakeMotionEvent (display, DefaultScreen (display),
1758 /* Accessibility::DEController::notifyListenersSync */
1759 static CORBA_boolean
1760 impl_notify_listeners_sync (PortableServer_Servant servant,
1761 const Accessibility_DeviceEvent *event,
1762 CORBA_Environment *ev)
1764 SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1765 bonobo_object_from_servant (servant));
1767 g_print ("notifylistening listeners synchronously: controller %p, event id %d\n",
1768 controller, (int) event->id);
1770 return spi_controller_notify_keylisteners (controller, event, CORBA_FALSE, ev) ?
1771 CORBA_TRUE : CORBA_FALSE;
1774 /* Accessibility::DEController::notifyListenersAsync */
1776 impl_notify_listeners_async (PortableServer_Servant servant,
1777 const Accessibility_DeviceEvent *event,
1778 CORBA_Environment *ev)
1780 SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1781 bonobo_object_from_servant (servant));
1783 fprintf (stderr, "notifying listeners asynchronously\n");
1785 spi_controller_notify_keylisteners (controller, event, CORBA_FALSE, ev);
1789 spi_device_event_controller_class_init (SpiDEControllerClass *klass)
1791 GObjectClass * object_class = (GObjectClass *) klass;
1792 POA_Accessibility_DeviceEventController__epv *epv = &klass->epv;
1794 spi_device_event_controller_parent_class = g_type_class_peek_parent (klass);
1796 object_class->finalize = spi_device_event_controller_object_finalize;
1798 epv->registerKeystrokeListener = impl_register_keystroke_listener;
1799 epv->deregisterKeystrokeListener = impl_deregister_keystroke_listener;
1800 epv->registerDeviceEventListener = impl_register_device_listener;
1801 epv->deregisterDeviceEventListener = impl_deregister_device_listener;
1802 epv->generateKeyboardEvent = impl_generate_keyboard_event;
1803 epv->generateMouseEvent = impl_generate_mouse_event;
1804 epv->notifyListenersSync = impl_notify_listeners_sync;
1805 epv->notifyListenersAsync = impl_notify_listeners_async;
1807 if (!spi_dec_private_quark)
1808 spi_dec_private_quark = g_quark_from_static_string ("spi-dec-private");
1812 spi_device_event_controller_init (SpiDEController *device_event_controller)
1814 DEControllerPrivateData *private;
1815 device_event_controller->key_listeners = NULL;
1816 device_event_controller->mouse_listeners = NULL;
1817 device_event_controller->keygrabs_list = NULL;
1820 * TODO: fixme, this module makes the foolish assumptions that
1821 * registryd uses the same display as the apps, and that the
1822 * DISPLAY environment variable is set.
1824 gdk_init (NULL, NULL);
1826 private = g_new0 (DEControllerPrivateData, 1);
1827 gettimeofday (&private->last_press_time, NULL);
1828 gettimeofday (&private->last_release_time, NULL);
1829 g_object_set_qdata (G_OBJECT (device_event_controller),
1830 spi_dec_private_quark,
1833 spi_controller_register_with_devices (device_event_controller);
1837 spi_device_event_controller_forward_key_event (SpiDEController *controller,
1838 const XEvent *event)
1840 gboolean is_consumed = FALSE;
1841 CORBA_Environment ev;
1842 Accessibility_DeviceEvent key_event;
1844 g_assert (event->type == KeyPress || event->type == KeyRelease);
1846 CORBA_exception_init (&ev);
1848 key_event = spi_keystroke_from_x_key_event ((XKeyEvent *) event);
1850 spi_controller_update_key_grabs (controller, &key_event);
1852 /* relay to listeners, and decide whether to consume it or not */
1853 is_consumed = spi_controller_notify_keylisteners (
1854 controller, &key_event, CORBA_TRUE, &ev);
1858 XAllowEvents (spi_get_display (), AsyncKeyboard, CurrentTime);
1862 XAllowEvents (spi_get_display (), ReplayKeyboard, CurrentTime);
1867 spi_device_event_controller_new (SpiRegistry *registry)
1869 SpiDEController *retval = g_object_new (
1870 SPI_DEVICE_EVENT_CONTROLLER_TYPE, NULL);
1871 DEControllerPrivateData *private;
1873 retval->registry = SPI_REGISTRY (bonobo_object_ref (
1874 BONOBO_OBJECT (registry)));
1876 spi_dec_init_mouse_listener (registry);
1877 /* TODO: kill mouse listener on finalize */
1881 BONOBO_TYPE_FUNC_FULL (SpiDEController,
1882 Accessibility_DeviceEventController,
1884 spi_device_event_controller);