Bugfix for test-simple, reinstated key event listener tests.
[platform/core/uifw/at-spi2-atk.git] / cspi / spi_registry.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2001 Sun Microsystems Inc.
6  *
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.
11  *
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.
16  *
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.
21  */
22
23 /* spi_registry.c: Global functions wrapping the registry */
24
25 #include <cspi/spi-private.h>
26
27 /**
28  * SPI_registerGlobalEventListener:
29  * @listener: the #AccessibleEventListener to be registered against an
30  *            event type.
31  * @eventType: a character string indicating the type of events for which
32  *            notification is requested.  Format is
33  *            EventClass:major_type:minor_type:detail
34  *            where all subfields other than EventClass are optional.
35  *            EventClasses include "object", "window", "mouse",
36  *            and toolkit events (e.g. "Gtk", "AWT").
37  *            Examples: "focus:", "Gtk:GtkWidget:button_press_event".
38  *
39  * Legal object event types:
40  *
41  *    (property change events)
42  *
43  *            object:property-change
44  *            object:property-change:accessible-name
45  *            object:property-change:accessible-description
46  *            object:property-change:accessible-parent
47  *            object:property-change:accessible-value
48  *            object:property-change:accessible-role
49  *            object:property-change:accessible-table-caption
50  *            object:property-change:accessible-table-column-description
51  *            object:property-change:accessible-table-column-header
52  *            object:property-change:accessible-table-row-description
53  *            object:property-change:accessible-table-row-header
54  *            object:property-change:accessible-table-summary
55  *
56  *    (other object events)
57  *
58  *            object:state-changed 
59  *            object:children-changed
60  *            object:visible-data-changed
61  *            object:selection-changed
62  *            object:text-selection-changed
63  *            object:text-changed
64  *            object:text-caret-moved
65  *            object:row-inserted
66  *            object:row-reordered
67  *            object:row-deleted
68  *            object:column-inserted
69  *            object:column-reordered
70  *            object:column-deleted
71  *            object:model-changed
72  *
73  *  (window events)
74  *
75  *            window:minimize
76  *            window:maximize
77  *            window:restore
78  *            window:close
79  *            window:create
80  *            window:reparent
81  *            window:desktop-create
82  *            window:desktop-destroy
83  *            window:activate
84  *            window:deactivate
85  *            window:raise
86  *            window:lower
87  *            window:move
88  *            window:resize
89  *            window:shade
90  *            window:unshade
91  *            window:restyle
92  *
93  * NOTE: this string may be UTF-8, but should not contain byte value 56
94  *            (ascii ':'), except as a delimiter, since non-UTF-8 string
95  *            delimiting functions are used internally.
96  *            In general, listening to
97  *            toolkit-specific events is not recommended.
98  *
99  * Add an in-process callback function to an existing AccessibleEventListener.
100  *
101  * Returns: #TRUE if successful, otherwise #FALSE.
102  **/
103 SPIBoolean
104 SPI_registerGlobalEventListener (AccessibleEventListener *listener,
105                                  const char              *eventType)
106 {
107   if (!listener)
108     {
109       return FALSE;
110     }
111
112   Accessibility_Registry_registerGlobalEventListener (
113     cspi_registry (),
114     cspi_event_listener_get_corba (listener),
115     eventType, cspi_ev ());
116
117   return  !cspi_exception ();
118 }
119
120 /**
121  * SPI_deregisterGlobalEventListenerAll:
122  * @listener: the #AccessibleEventListener to be registered against
123  *            an event type.
124  *
125  * deregisters an AccessibleEventListener from the registry, for all
126  *            event types it may be listening to. Use
127  *            AccessibleEventListener_unref to release the
128  *            listener reference.
129  *
130  * Returns: #TRUE if successful, otherwise #FALSE.
131  **/
132 SPIBoolean
133 SPI_deregisterGlobalEventListenerAll (AccessibleEventListener *listener)
134 {
135   if (!listener)
136     {
137       return FALSE;
138     }
139
140   Accessibility_Registry_deregisterGlobalEventListenerAll (
141     cspi_registry (),
142     cspi_event_listener_get_corba (listener),
143     cspi_ev ());
144
145   return !cspi_exception ();
146 }
147
148 /**
149  * SPI_deregisterGlobalEventListener:
150  * @listener: the #AccessibleEventListener registered against an event type.
151  * @eventType: a string specifying the event type for which this
152  *             listener is to be deregistered.
153  *
154  * deregisters an AccessibleEventListener from the registry, for a specific
155  *             event type.
156  *
157  * Returns: #TRUE if successful, otherwise #FALSE.
158  **/
159 SPIBoolean
160 SPI_deregisterGlobalEventListener (AccessibleEventListener *listener,
161                                    const char              *eventType)
162 {
163   if (!listener)
164     {
165       return FALSE;
166     }
167
168   Accessibility_Registry_deregisterGlobalEventListener (
169     cspi_registry (), 
170     cspi_event_listener_get_corba (listener),
171     eventType, cspi_ev ());
172
173   return !cspi_exception ();
174 }
175
176 /**
177  * SPI_getDesktopCount:
178  *
179  * Get the number of virtual desktops.
180  * NOTE: currently multiple virtual desktops are not implemented, this
181  *       function always returns '1'.
182  *
183  * Returns: an integer indicating the number of active virtual desktops.
184  **/
185 int
186 SPI_getDesktopCount ()
187 {
188   int retval;
189
190   retval = Accessibility_Registry_getDesktopCount (
191     cspi_registry (), cspi_ev ());
192
193   cspi_return_val_if_ev ("getDesktopCount", -1);
194
195   return retval;
196 }
197
198 /**
199  * SPI_getDesktop:
200  * @i: an integer indicating which of the accessible desktops is to be returned.
201  *
202  * Get the virtual desktop indicated by index @i.
203  * NOTE: currently multiple virtual desktops are not implemented, this
204  *       function always returns '1'.
205  *
206  * Returns: a pointer to the 'i-th' virtual desktop's #Accessible representation.
207  **/
208 Accessible*
209 SPI_getDesktop (int i)
210 {
211   return cspi_object_add (
212     Accessibility_Registry_getDesktop (
213       cspi_registry (), i, cspi_ev ()));
214 }
215
216 /**
217  * SPI_getDesktopList:
218  * @desktop_list: a pointer to an array of #Accessible references.
219  *
220  * Get the list of virtual desktops.  On return, @list will point
221  *     to a newly-created, NULL terminated array of virtual desktop
222  *     pointers.
223  *     It is the responsibility of the caller to free this array when
224  *     it is no longer needed.
225  *
226  * Not Yet Implemented : this implementation always returns a single
227  * #Accessible desktop.
228  *
229  * Returns: an integer indicating how many virtual desktops have been
230  *          placed in the list pointed to by parameter @list.
231  **/
232 int
233 SPI_getDesktopList (Accessible ***desktop_list)
234 {
235   int i;
236   Accessible **list;
237   Accessibility_DesktopSeq *desktops;
238
239   if (!desktop_list)
240           return 0;
241
242   *desktop_list = NULL;
243
244   desktops = Accessibility_Registry_getDesktopList (cspi_registry (),
245                                                     cspi_ev ());
246
247   cspi_return_val_if_ev ("getDesktopList", 0);
248
249   list = g_new0 (Accessible *, desktops->_length + 1);
250
251   for (i = 0; i < desktops->_length; i++)
252     {
253       list [i] = cspi_object_add (
254               CORBA_Object_duplicate (desktops->_buffer [i], cspi_ev ()));
255     }
256   list [i] = NULL;
257
258   CORBA_free (desktops);
259
260   *desktop_list = list;
261
262   return i;
263 }
264
265 /**
266  * SPI_freeDesktopList:
267  * @desktop_list: a pointer to an array of #Accessible objects
268  * as returned from @SPI_getDesktopList
269  * 
270  * This routine frees the memory associated with the list.
271  **/
272 void
273 SPI_freeDesktopList (Accessible **desktop_list)
274 {
275   Accessible **p;
276   
277   for (p = desktop_list; p && *p; p++)
278     {
279       cspi_object_unref (*p);
280     }
281   g_free (desktop_list);
282 }
283
284 /**
285  * SPI_KEYSET_ALL_KEYS:
286  * @SPI_KEYSET_ALL_KEYS: A special value for an AccessibleKeySet type, which tacitly
287  *                       includes all keycodes and keyvals for the specified modifier set.
288  **/
289
290 /**
291  * SPI_registerAccessibleKeystrokeListener:
292  * @listener:  a pointer to the #AccessibleKeystrokeListener for which
293  *             keystroke events are requested.
294  * @keys:      a pointer to the #AccessibleKeySet indicating which
295  *             keystroke events are requested, or #CSPI_KEYSET_ALL_KEYS.
296  * @modmask:   an #AccessibleKeyMaskType mask indicating which
297  *             key event modifiers must be set in combination with @keys,
298  *             events will only be reported for key events for which all
299  *             modifiers in @modmask are set.  If you wish to listen for
300  *             events with multiple modifier combinations you must call
301  *             registerAccessibleKeystrokeListener() once for each combination.
302  * @eventmask: an #AccessibleKeyMaskType mask indicating which
303  *             types of key events are requested (#SPI_KEY_PRESSED, etc.).
304  * @sync_type: a #AccessibleKeyListenerSyncType parameter indicating
305  *             the behavior of the notification/listener transaction.
306  *             
307  * Register a listener for keystroke events, either pre-emptively for
308  *             all windows (CSPI_KEYLISTENER_ALL_WINDOWS), or
309  *             non-preemptively (CSPI_KEYLISTENER_NOSYNC).
310  *             ( Other sync_type values may be available in the future.)
311  *
312  * Returns: #TRUE if successful, otherwise #FALSE.
313  **/
314 SPIBoolean
315 SPI_registerAccessibleKeystrokeListener (AccessibleKeystrokeListener  *listener,
316                                          AccessibleKeySet             *keys,
317                                          AccessibleKeyMaskType         modmask,
318                                          AccessibleKeyEventMask        eventmask,
319                                          AccessibleKeyListenerSyncType sync_type)
320 {
321   gint                                i, mask;
322   Accessibility_KeySet                key_set;
323   Accessibility_KeyEventTypeSeq       key_events;
324   Accessibility_ControllerEventMask   controller_event_mask;
325   Accessibility_DeviceEventController device_event_controller;
326   Accessibility_EventListenerMode     listener_mode;
327   SPIBoolean                          retval = FALSE;
328
329   if (!listener)
330     {
331       return retval;
332     }
333
334   device_event_controller = 
335     Accessibility_Registry_getDeviceEventController (cspi_registry (), cspi_ev ());
336
337   cspi_return_val_if_ev ("getting event controller", FALSE);
338
339   /* copy the keyval filter values from the C api into the CORBA KeySet */
340   if (keys)
341     {
342       key_set._length = keys->len;
343       key_set._buffer = Accessibility_KeySet_allocbuf (keys->len);
344       for (i = 0; i < key_set._length; ++i)
345         {
346           key_set._buffer[i].keycode = keys->keycodes[i];
347           key_set._buffer[i].keysym = keys->keysyms[i];
348           if (keys->keystrings && keys->keystrings[i]) 
349             {
350               key_set._buffer[i].keystring = keys->keystrings[i];
351             } 
352           else 
353             {
354               key_set._buffer[i].keystring = CORBA_string_dup("");
355             }
356         }
357     }
358   else
359     {
360       key_set._length = 0;
361       key_set._buffer = NULL;
362     }
363         
364   /* copy the event filter values from the C api into the CORBA KeyEventTypeSeq */
365   mask = 1;
366   i = 0;
367   do
368     {
369       if (mask & eventmask)
370         {
371           ++i; 
372         }
373       mask <<= 1;
374     }
375   while (mask & 0xFFFF);
376   
377   key_events._buffer = Accessibility_KeyEventTypeSeq_allocbuf (i);
378   i = 0;
379   if (eventmask & SPI_KEY_PRESSED)
380     {
381       key_events._buffer[i++] = Accessibility_KEY_PRESSED;
382     }
383   if (eventmask & SPI_KEY_RELEASED)
384     {
385       key_events._buffer[i++] = Accessibility_KEY_RELEASED;
386     }
387   key_events._length = i;
388   
389   controller_event_mask = (CORBA_unsigned_long) modmask;
390
391   listener_mode.synchronous =
392           (CORBA_boolean) ((sync_type & SPI_KEYLISTENER_SYNCHRONOUS)!=0);
393   listener_mode.preemptive =
394           (CORBA_boolean) ((sync_type & SPI_KEYLISTENER_CANCONSUME)!=0);
395   listener_mode.global =
396           (CORBA_boolean) ((sync_type & SPI_KEYLISTENER_ALL_WINDOWS)!=0);
397
398   retval = Accessibility_DeviceEventController_registerKeystrokeListener (
399     device_event_controller,
400     cspi_event_listener_get_corba (listener),
401     &key_set,
402     controller_event_mask,
403     &key_events,
404     &listener_mode,
405     cspi_ev ());
406
407   cspi_return_val_if_ev ("registering keystroke listener", FALSE);
408
409   cspi_release_unref (device_event_controller);
410
411   return retval;
412 }
413
414 /**
415  * SPI_deregisterAccessibleKeystrokeListener:
416  * @listener: a pointer to the #AccessibleKeystrokeListener for which
417  *            keystroke events are requested.
418  * @modmask:  the key modifier mask for which this listener is to be
419  *            'deregistered' (of type #AccessibleeyMaskType).
420  *
421  * Removes a keystroke event listener from the registry's listener queue,
422  *            ceasing notification of events with modifiers matching @modmask.
423  *
424  * Returns: #TRUE if successful, otherwise #FALSE.
425  **/
426 SPIBoolean
427 SPI_deregisterAccessibleKeystrokeListener (AccessibleKeystrokeListener *listener,
428                                            AccessibleKeyMaskType        modmask)
429 {
430   Accessibility_ControllerEventMask   controller_event_mask;
431   Accessibility_KeySet                key_set;
432   Accessibility_KeyEventTypeSeq       key_events;
433   Accessibility_DeviceEventController device_event_controller;
434
435   if (!listener)
436     {
437       return FALSE;
438     }
439
440   device_event_controller = 
441     Accessibility_Registry_getDeviceEventController (cspi_registry (), cspi_ev ());
442
443   cspi_return_val_if_ev ("getting keystroke listener", FALSE);
444
445   controller_event_mask = (CORBA_unsigned_long) modmask;
446
447   key_events._buffer = NULL;
448   key_events._length = 0;
449
450   key_set._buffer = NULL;
451   key_set._length = 0;
452
453   Accessibility_DeviceEventController_deregisterKeystrokeListener (
454     device_event_controller,
455     cspi_event_listener_get_corba (listener),
456     &key_set,
457     controller_event_mask,
458     &key_events,
459     cspi_ev ());
460
461   cspi_release_unref (device_event_controller);
462
463   return TRUE;
464 }
465
466 /**
467  * SPI_generateKeyboardEvent:
468  * @keyval: a long integer indicating the keycode or keysym of the key event
469  *           being synthesized.
470  * @keystring: an (optional) UTF-8 string which, if @keyval is NULL,
471  *           indicates a 'composed' keyboard input string which is 
472  *           being synthesized; this type of keyboard event synthesis does
473  *           not emulate hardware keypresses but injects the string 
474  *           as though a composing input method (such as XIM) were used.
475  * @synth_type: a #AccessibleKeySynthType flag indicating whether @keyval
476  *           is to be interpreted as a keysym rather than a keycode
477  *           (CSPI_KEYSYM), or whether to synthesize
478  *           SPI_KEY_PRESS, SPI_KEY_RELEASE, or both (SPI_KEY_PRESSRELEASE).
479  *
480  * Synthesize a keyboard event (as if a hardware keyboard event occurred in the
481  * current UI context).
482  *
483  * Returns: #TRUE if successful, otherwise #FALSE.
484  **/
485 SPIBoolean
486 SPI_generateKeyboardEvent (long int keyval,
487                            char *keystring,
488                            AccessibleKeySynthType synth_type)
489 {
490 /* TODO: check current modifier status and
491  *  send keycode to alter, if necessary
492  */
493         
494   /* TODO: implement keystring use case */
495   Accessibility_KeySynthType keysynth_type;
496   Accessibility_DeviceEventController device_event_controller = 
497           Accessibility_Registry_getDeviceEventController (cspi_registry (), cspi_ev ());
498
499   cspi_return_val_if_ev ("getting event controller for key event gen", FALSE);
500
501   switch (synth_type)
502     {
503       case SPI_KEY_PRESS:
504           keysynth_type = Accessibility_KEY_PRESS;
505           break;
506       case SPI_KEY_RELEASE:
507           keysynth_type = Accessibility_KEY_RELEASE;
508           break;
509       case SPI_KEY_PRESSRELEASE:
510           keysynth_type = Accessibility_KEY_PRESSRELEASE;
511           break;
512       case SPI_KEY_SYM:
513           keysynth_type = Accessibility_KEY_SYM;
514           break;
515       case SPI_KEY_STRING:
516           keysynth_type = Accessibility_KEY_STRING;
517           break;
518       default:
519           return FALSE;
520     }
521
522   Accessibility_DeviceEventController_generateKeyboardEvent (device_event_controller,
523                                                              keyval,
524                                                              "",
525                                                              keysynth_type,
526                                                              cspi_ev ());
527
528   cspi_return_val_if_ev ("generating keyboard event", FALSE);
529
530   cspi_release_unref (device_event_controller);
531
532   return TRUE;
533 }
534
535 /**
536  * SPI_generateMouseEvent:
537  * @x: a #long indicating the screen x coordinate of the mouse event.
538  * @y: a #long indicating the screen y coordinate of the mouse event.
539  * @name: a string indicating which mouse event to be synthesized
540  *        (e.g. "b1p", "b1c", "b2r", "rel", "abs").
541  *
542  * Synthesize a mouse event at a specific screen coordinate.
543  * Most AT clients should use the #AccessibleAction interface when
544  * tempted to generate mouse events, rather than this method.
545  * Event names: b1p = button 1 press; b2r = button 2 release;
546  *              b3c = button 3 click; b2d = button 2 double-click;
547  *              abs = absolute motion; rel = relative motion.
548  *
549  * Returns: #TRUE if successful, otherwise #FALSE.
550  **/
551 SPIBoolean
552 SPI_generateMouseEvent (long x, long y, char *name)
553 {
554   Accessibility_DeviceEventController device_event_controller = 
555           Accessibility_Registry_getDeviceEventController (cspi_registry (), cspi_ev ());
556
557   cspi_return_val_if_ev ("getting event controller for mouse event gen", FALSE);
558
559   Accessibility_DeviceEventController_generateMouseEvent (device_event_controller,
560                                                           x, y, name, cspi_ev ());
561   cspi_return_val_if_ev ("generating mouse event", FALSE);
562
563   cspi_release_unref (device_event_controller);
564
565   return TRUE;
566 }
567