2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5 * Copyright 2001 Sun Microsystems Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
24 * listener.c: test for accessibility implementation
34 #include <gdk/gdkx.h> /* TODO: hide dependency (wrap in single porting file) */
35 #include <gdk/gdkwindow.h>
36 #include <bonobo/Bonobo.h>
37 #include <libspi/Accessibility.h>
40 * This pulls the definition for the BonoboObject (GType)
42 #include "deviceeventcontroller.h"
45 * Our parent Gtk object type
47 #define PARENT_TYPE BONOBO_OBJECT_TYPE
50 * A pointer to our parent object class
52 static GObjectClass *device_event_controller_parent_class;
54 static gboolean kbd_registered = FALSE;
59 DEVICE_TYPE_LAST_DEFINED
62 static gboolean _controller_register_with_devices (DeviceEventController *controller);
63 static gboolean _controller_grab_keyboard (DeviceEventController *controller);
65 static void _controller_register_device_listener (DeviceEventController *controller,
67 const Accessibility_ControllerEventMask *mask,
68 DeviceTypeCategory type,
69 CORBA_Environment *ev);
76 _compare_corba_objects (gconstpointer p1, gconstpointer p2)
80 retval = !CORBA_Object_is_equivalent ((CORBA_Object) p1, (CORBA_Object) p2, &ev);
83 fprintf (stderr, "comparing %p to %p; result %d\n",
91 _eventmask_compare_value (gconstpointer p1, gconstpointer p2)
94 return (gint) (p1?1:(p2?-1:0));
96 return ((long)((Accessibility_ControllerEventMask*)p2)->value) -
97 ((long)((Accessibility_ControllerEventMask*)p1)->value);
101 _controller_register_device_listener (DeviceEventController *controller,
102 const CORBA_Object l,
103 const Accessibility_ControllerEventMask *mask,
104 DeviceTypeCategory type,
105 CORBA_Environment *ev)
107 Accessibility_ControllerEventMask *mask_ptr;
110 case DEVICE_TYPE_KBD:
111 controller->key_listeners = g_list_append (controller->key_listeners,
112 CORBA_Object_duplicate (l, ev));
114 mask_ptr = (Accessibility_ControllerEventMask *)
115 g_list_find_custom (controller->keymask_list, (gpointer) mask,
116 _eventmask_compare_value);
118 ++(mask_ptr->refcount);
121 if (mask->refcount != (CORBA_unsigned_short) 1)
122 fprintf (stderr, "mask initial refcount is not 1!\n");
123 if (mask->value > (CORBA_unsigned_long) 2048)
124 fprintf (stderr, "mask value looks invalid (%lu)\n",
125 (unsigned long) mask->value);
127 fprintf (stderr, "appending mask with val=%lu\n",
128 (unsigned long) mask->value);
129 mask_ptr = Accessibility_ControllerEventMask__alloc();
130 mask_ptr->value = mask->value;
131 mask_ptr->refcount = (CORBA_unsigned_short) 1;
132 controller->keymask_list = g_list_append (controller->keymask_list,
133 (gpointer) mask_ptr);
136 case DEVICE_TYPE_MOUSE:
137 /* controller->mouse_listeners = g_list_append (controller->mouse_listeners,
138 CORBA_Object_duplicate (l, ev));*/
140 /* possibly this interface should NOT be used for mouse events ? */
146 _controller_deregister_device_listener (DeviceEventController *controller,
147 const CORBA_Object l,
148 const Accessibility_ControllerEventMask *mask,
149 DeviceTypeCategory type,
150 CORBA_Environment *ev)
152 Accessibility_ControllerEventMask *mask_ptr;
155 case DEVICE_TYPE_KBD:
156 list_ptr = g_list_find_custom (controller->key_listeners, l, _compare_corba_objects);
158 controller->key_listeners = g_list_remove (controller->key_listeners, list_ptr);
160 mask_ptr = (Accessibility_ControllerEventMask *)
161 g_list_find_custom (controller->keymask_list, (gpointer) mask,
162 _eventmask_compare_value);
164 --mask_ptr->refcount;
165 if (!mask_ptr->refcount)
167 controller->keymask_list = g_list_remove (controller->keymask_list, mask_ptr);
168 ; /* release any key grabs that are in place for this key mask */
171 case DEVICE_TYPE_MOUSE:
172 /* controller->mouse_listeners = g_list_append (controller->mouse_listeners,
173 CORBA_Object_duplicate (l, ev));*/
175 /* possibly this interface should NOT be used for mouse events ? */
181 _controller_register_with_devices (DeviceEventController *controller)
183 gboolean retval = FALSE;
184 Display *default_display;
187 default_display = GDK_DISPLAY();
188 root_window = GDK_ROOT_WINDOW();
189 /* calls to device-specific implementations and routines go here */
190 /* register with: keyboard hardware code handler */
191 /* register with: (translated) keystroke handler */
193 fprintf (stderr, "About to request events on window %ld of display %p\n",
194 (unsigned long) root_window, default_display);
196 XSelectInput (default_display,
199 XSelectInput (default_display,
202 /* register with: mouse hardware device handler? */
203 /* register with: mouse event handler */
207 static gboolean _check_key_event (DeviceEventController *controller)
210 static Accessibility_ControllerEventMask shiftlock_mask =
211 {(CORBA_unsigned_long) LockMask, (CORBA_unsigned_short) 1};
213 static gboolean initialized = FALSE;
214 static gboolean is_active = FALSE;
215 XEvent *x_event = g_new0 (XEvent, 1);
216 XKeyEvent *x_key_event;
218 gboolean is_consumed = FALSE;
221 int n_listeners = g_list_length (controller->key_listeners);
222 Accessibility_KeyStroke key_event;
223 static CORBA_Environment ev;
228 CORBA_exception_init (&ev);
231 /* if (!XPending(GDK_DISPLAY())) return TRUE; */
234 * the call to XPending seemed like a good idea, why did it
238 XPeekEvent (GDK_DISPLAY(), x_event);
239 if (x_event->type == KeyPress)
241 x_key_event = (XKeyEvent *)x_event;
242 keysym = XLookupKeysym (x_key_event, 0);
243 key_event.keyID = (CORBA_long)(keysym);
244 key_event.type = Accessibility_KEY_PRESSED;
245 key_event.modifiers = (CORBA_unsigned_short)(x_key_event->state);
246 #if defined SPI_KEYEVENT_DEBUG
248 "Key %lu pressed (%c), modifiers %d\n",
249 (unsigned long) keysym,
251 (int) x_key_event->state);
252 #elif defined SPI_DEBUG
253 fprintf(stderr, "%s%c",
254 (x_key_event->state & Mod1Mask)?"Alt-":"",
255 ((x_key_event->state & ShiftMask)^(x_key_event->state & LockMask))?
256 (char) toupper((int) keysym) : (char) tolower((int)keysym));
257 #endif /* SPI_DEBUG */
261 #ifdef SPI_KEYEVENT_DEBUG
262 fprintf (stderr, "other event, type %d\n", (int) x_event->type);
265 /* relay to listeners, and decide whether to consume it or not */
266 for (i=0; i<n_listeners && !is_consumed; ++i)
268 Accessibility_KeystrokeListener ls;
269 ls = (Accessibility_KeystrokeListener)
270 g_list_nth_data (controller->key_listeners, i);
271 if (!CORBA_Object_is_nil(ls, &ev))
273 is_consumed = Accessibility_KeystrokeListener_keyEvent (ls, &key_event, &ev);
276 if (is_consumed) XNextEvent (GDK_DISPLAY(), x_event);
277 XAllowEvents (GDK_DISPLAY(), ReplayKeyboard, CurrentTime);
279 * I haven't figure out how to make this work correctly yet :-(
281 * XGrabKeyboard (GDK_DISPLAY(), GDK_ROOT_WINDOW(), True,
282 * GrabModeAsync, GrabModeSync, CurrentTime);
283 * XAllowEvents (GDK_DISPLAY(), SyncKeyboard, CurrentTime);
286 * ControlMask grabs are broken, must be in use already.
290 /* Always grab ShiftLock in DEBUG mode */
292 if (!controller->keymask_list)
293 controller->keymask_list =
294 g_list_append (controller->keymask_list, &shiftlock_mask);
296 return _controller_grab_keyboard (controller);
300 _controller_grab_keyboard (DeviceEventController *controller)
302 Display *display = GDK_DISPLAY();
303 Window root_window = GDK_ROOT_WINDOW();
304 GList *maskList = controller->keymask_list;
306 int last_mask = g_list_length (maskList);
309 * masks known to work with default RH 7.1:
310 * 0 (no mods), LockMask, Mod1Mask, Mod2Mask, ShiftMask,
311 * ShiftMask|LockMask, Mod1Mask|LockMask, Mod2Mask|LockMask,
312 * ShiftMask|Mod1Mask, ShiftMask|Mod2Mask, Mod1Mask|Mod2Mask,
313 * ShiftMask|LockMask|Mod1Mask, ShiftMask|LockMask|Mod2Mask,
315 * ControlMask grabs are broken, must be in use already
318 for (i=0; i < last_mask; ++i)
320 Accessibility_ControllerEventMask *mask
321 = (Accessibility_ControllerEventMask *)g_list_nth_data (maskList, i);
322 unsigned long maskVal = 0xFFFFFFFF;
323 if (mask) maskVal = (unsigned long) mask->value;
324 #ifdef SPI_KEYEVENT_DEBUG
325 fprintf (stderr, "mask=%lx\n", maskVal);
327 if (!(maskVal & ControlMask))
329 #ifdef SPI_KEYEVENT_DEBUG
330 fprintf (stderr, "grabbing for mod %lu\n", (unsigned long) maskVal);
339 /* TODO: check call for errors and return FALSE if error occurs */
341 return FALSE; /* can't do control key yet */
348 * Implemented GObject::finalize
351 device_event_controller_object_finalize (GObject *object)
355 fprintf(stderr, "device_event_controller_object_finalize called\n");
357 device_event_controller_parent_class->finalize (object);
361 * CORBA Accessibility::DeviceEventController::registerKeystrokeListener
362 * method implementation
365 impl_register_keystroke_listener (PortableServer_Servant servant,
366 const Accessibility_KeystrokeListener l,
367 const Accessibility_ControllerEventMask *mask,
368 CORBA_Environment *ev)
370 DeviceEventController *controller = DEVICE_EVENT_CONTROLLER (
371 bonobo_object_from_servant (servant));
373 fprintf (stderr, "registering keystroke listener %p with maskVal %lu\n",
374 (void *) l, (unsigned long) mask->value);
376 _controller_register_device_listener(controller, l, mask, DEVICE_TYPE_KBD, ev);
380 * CORBA Accessibility::DeviceEventController::registerMouseListener
381 * method implementation
385 impl_register_mouse_listener (PortableServer_Servant servant,
386 const Accessibility_MouseListener *l,
387 CORBA_Environment *ev)
389 DeviceEventController *controller = DEVICE_EVENT_CONTROLLER (
390 bonobo_object_from_servant (servant));
392 fprintf (stderr, "registering mouse listener %p\n", l);
394 _controller_register_device_listener(controller, l, mask, DEVICE_TYPE_MOUSE, ev);
399 * CORBA Accessibility::DeviceEventController::registerKeystrokeListener
400 * method implementation
403 impl_generate_key_event (PortableServer_Servant servant,
404 const CORBA_long keyEventID,
405 CORBA_Environment *ev)
408 fprintf (stderr, "synthesizing keystroke %ld\n", (long) keyEventID);
413 * CORBA Accessibility::DeviceEventController::generateMouseEvent
414 * method implementation
417 impl_generate_mouse_event (PortableServer_Servant servant,
420 const CORBA_char * eventName,
421 CORBA_Environment *ev)
424 fprintf (stderr, "generating mouse %s event at %ld, %ld\n", eventName, x, y);
429 device_event_controller_class_init (DeviceEventControllerClass *klass)
431 GObjectClass * object_class = (GObjectClass *) klass;
432 POA_Accessibility_DeviceEventController__epv *epv = &klass->epv;
433 device_event_controller_parent_class = g_type_class_ref (BONOBO_OBJECT_TYPE);
435 object_class->finalize = device_event_controller_object_finalize;
437 epv->registerKeystrokeListener = impl_register_keystroke_listener;
438 /* epv->registerMouseListener = impl_register_mouse_listener; */
439 epv->generateKeyEvent = impl_generate_key_event;
440 epv->generateMouseEvent = impl_generate_mouse_event;
441 klass->check_key_event = _check_key_event;
445 device_event_controller_init (DeviceEventController *device_event_controller)
447 device_event_controller->key_listeners = NULL;
448 device_event_controller->key_listeners = NULL;
449 device_event_controller->keymask_list = NULL;
450 kbd_registered = _controller_register_with_devices (device_event_controller);
453 gboolean device_event_controller_check_key_event (DeviceEventController *controller)
455 DeviceEventControllerClass *klass = DEVICE_EVENT_CONTROLLER_GET_CLASS (controller);
456 if (klass->check_key_event)
457 return (klass->check_key_event) (controller);
461 device_event_controller_get_type (void)
463 static GType type = 0;
466 static const GTypeInfo tinfo = {
467 sizeof (DeviceEventControllerClass),
468 (GBaseInitFunc) NULL,
469 (GBaseFinalizeFunc) NULL,
470 (GClassInitFunc) device_event_controller_class_init,
471 (GClassFinalizeFunc) NULL,
472 NULL, /* class data */
473 sizeof (DeviceEventController),
475 (GInstanceInitFunc) device_event_controller_init,
476 NULL /* value table */
479 * Here we use bonobo_type_unique instead of
480 * gtk_type_unique, this auto-generates a load of
481 * CORBA structures for us. All derived types must
482 * use bonobo_type_unique.
484 type = bonobo_type_unique (
486 POA_Accessibility_DeviceEventController__init,
488 G_STRUCT_OFFSET (DeviceEventControllerClass, epv),
490 "DeviceEventController");