d35ade7cf174bd8f41cc65f9f69a2d5ceb2035f8
[platform/core/uifw/at-spi2-atk.git] / test / simple-at.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 #include <stdlib.h>
24 #include <ctype.h>
25 #include <unistd.h>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <sys/un.h>
29 #include "../util/mag_client.h"
30 #include "../cspi/spi-private.h" /* A hack for now */
31
32 #undef PRINT_TREE
33
34 static void report_focus_event    (const AccessibleEvent *event, void *user_data);
35 static void report_generic_event  (const AccessibleEvent *event, void *user_data);
36 static void report_text_event     (const AccessibleEvent *event, void *user_data);
37 static void report_button_press   (const AccessibleEvent *event, void *user_data);
38 static void check_property_change (const AccessibleEvent *event, void *user_data);
39 static SPIBoolean report_command_key_event  (const AccessibleKeystroke *stroke, void *user_data);
40 static SPIBoolean report_ordinary_key_event (const AccessibleKeystroke *stroke, void *user_data);
41 static void get_environment_vars (void);
42
43 static int _festival_init ();
44 static void _festival_say (const char *text, const char *voice, SPIBoolean shutup);
45 static void _festival_write (const char *buff, int fd);
46
47 #ifdef PRINT_TREE
48 static void print_accessible_tree (Accessible *accessible, char *prefix);
49 #endif
50
51 static SPIBoolean use_magnifier = FALSE;
52 static SPIBoolean use_festival = FALSE;
53 static SPIBoolean festival_chatty = FALSE;
54 static SPIBoolean name_changed = FALSE;
55
56 static AccessibleEventListener *focus_listener;
57 static AccessibleEventListener *property_listener;
58 static AccessibleEventListener *generic_listener;
59 static AccessibleEventListener *button_listener;
60 static AccessibleEventListener *text_listener;
61 static AccessibleKeystrokeListener *command_key_listener;
62 static AccessibleKeystrokeListener *ordinary_key_listener;
63 static AccessibleKeySet            *command_keyset;
64
65 int
66 main (int argc, char **argv)
67 {
68   int i, j;
69   int n_desktops;
70   int n_apps;
71   char *s;
72   Accessible *desktop;
73   Accessible *application;
74   const char *modules;
75
76   if ((argc > 1) && (!strncmp (argv[1], "-h", 2)))
77     {
78       printf ("Usage: simple-at\n");
79       printf ("\tEnvironment variables used:\n\t\tFESTIVAL\n\t\tMAGNIFIER\n\t\tFESTIVAL_CHATTY\n");
80       exit (0);
81     }
82
83   modules = g_getenv ("GTK_MODULES");
84   if (!modules || modules [0] == '\0')
85     {
86       putenv ("GTK_MODULES=");
87     }
88   modules = NULL;
89
90   SPI_init ();
91
92   focus_listener = SPI_createAccessibleEventListener (report_focus_event, NULL);
93   property_listener = SPI_createAccessibleEventListener (check_property_change, NULL); 
94   generic_listener = SPI_createAccessibleEventListener (report_generic_event, NULL); 
95   text_listener = SPI_createAccessibleEventListener (report_text_event, NULL); 
96   button_listener = SPI_createAccessibleEventListener (report_button_press, NULL);
97   SPI_registerGlobalEventListener (focus_listener, "focus:");
98   SPI_registerGlobalEventListener (property_listener, "object:property-change");
99 /* :accessible-selection"); */
100   SPI_registerGlobalEventListener (property_listener, "object:property-change:accessible-name");
101   SPI_registerGlobalEventListener (generic_listener, "object:selection-changed"); 
102   SPI_registerGlobalEventListener (generic_listener, "object:children-changed"); 
103   SPI_registerGlobalEventListener (generic_listener, "object:visible-data-changed"); 
104   SPI_registerGlobalEventListener (generic_listener, "object:text-selection-changed"); 
105   SPI_registerGlobalEventListener (text_listener, "object:text-caret-moved"); 
106   SPI_registerGlobalEventListener (generic_listener, "object:text-changed"); 
107   SPI_registerGlobalEventListener (button_listener, "Gtk:GtkWidget:button-press-event");
108   n_desktops = SPI_getDesktopCount ();
109
110   for (i=0; i<n_desktops; ++i)
111     {
112       desktop = SPI_getDesktop (i);
113       s = Accessible_getName (desktop);
114       fprintf (stderr, "desktop %d name: %s\n", i, s);
115       SPI_freeString (s);
116       n_apps = Accessible_getChildCount (desktop);
117       for (j=0; j<n_apps; ++j)
118         {
119           application = Accessible_getChildAtIndex (desktop, j);
120           s = Accessible_getName (application);
121           fprintf (stderr, "app %d name: %s\n", j, s);
122 #ifdef PRINT_TREE
123           print_accessible_tree (application, "*");
124 #endif
125           SPI_freeString (s);
126           Accessible_unref (application);
127         }
128       Accessible_unref (desktop);
129     }
130
131   /* prepare the keyboard snoopers */
132   command_key_listener = SPI_createAccessibleKeystrokeListener (report_command_key_event, NULL);
133   ordinary_key_listener = SPI_createAccessibleKeystrokeListener (report_ordinary_key_event, NULL);
134
135   command_keyset = SPI_createAccessibleKeySet (11, "qmf23456789", NULL, NULL);
136   
137   /* will listen only to Control-Alt-q KeyPress events */
138   SPI_registerAccessibleKeystrokeListener(command_key_listener,
139                                           command_keyset,
140                                           SPI_KEYMASK_ALT | SPI_KEYMASK_CONTROL,
141                                           (unsigned long) ( SPI_KEY_PRESSED ),
142                                           SPI_KEYLISTENER_ALL_WINDOWS);
143
144   /* will listen only to CAPSLOCK key events, both press and release */
145   SPI_registerAccessibleKeystrokeListener(ordinary_key_listener,
146                                           (AccessibleKeySet *) SPI_KEYSET_ALL_KEYS,
147                                           SPI_KEYMASK_SHIFTLOCK,
148                                           (unsigned long) ( SPI_KEY_PRESSED | SPI_KEY_RELEASED ),
149                                           SPI_KEYLISTENER_NOSYNC);
150
151   get_environment_vars ();
152
153   SPI_event_main ();
154
155   putenv ("AT_BRIDGE_SHUTDOWN=1");
156
157   return SPI_exit ();
158 }
159
160 static void
161 get_environment_vars (void)
162 {
163   if (g_getenv ("FESTIVAL"))
164     {
165       fprintf (stderr, "Using festival\n");
166       use_festival = TRUE;
167       if (g_getenv ("FESTIVAL_CHATTY"))
168         {
169           festival_chatty = TRUE;
170         }
171     }
172   if (g_getenv ("MAGNIFIER"))
173     {
174       fprintf (stderr, "Using magnifier\n");
175       use_magnifier = TRUE;
176     }  
177   else
178     {
179       fprintf (stderr, "Not using magnifier\n");
180     }
181
182   if (!use_festival)
183     {
184       fprintf (stderr, "No speech output\n");
185     }
186 }
187
188 #ifdef PRINT_TREE
189 static void
190 print_accessible_tree (Accessible *accessible, char *prefix)
191 {
192         int n_children;
193         int i;
194         char *name;
195         char *role_name;
196         char *parent_name;
197         char *parent_role;
198         char child_prefix[100];
199         Accessible *child;
200         Accessible *parent;
201         
202         strncpy (child_prefix, prefix, 98);
203         strcat (child_prefix, "*");
204         parent = Accessible_getParent (accessible);
205         if (parent)
206           {
207                 parent_name = Accessible_getName (parent);
208                 parent_role = Accessible_getRoleName (parent);
209           }
210         Accessible_unref (parent);
211         name = Accessible_getName (accessible);
212         role_name = Accessible_getRoleName (accessible);
213         fprintf (stdout, "%sAccessible [%s] \"%s\"; parent [%s] %s\n",
214                  prefix, role_name, name, parent_role, parent_name);
215         SPI_freeString (name);
216         SPI_freeString (role_name);
217         SPI_freeString (parent_name);
218         n_children = Accessible_getChildCount (accessible);
219         for (i = 0; i < n_children; ++i)
220                 {
221                         child = Accessible_getChildAtIndex (accessible, i);
222                         print_accessible_tree (child, child_prefix);
223                         Accessible_unref (child);
224                 }
225 }
226 #endif
227
228 void
229 report_focussed_accessible (Accessible *obj, SPIBoolean shutup_previous_speech)
230 {
231   char *s;
232   int len;
233   long x, y, width, height;
234   /* hack for GUADEC demo, to make sure name changes are spoken */
235   shutup_previous_speech = (shutup_previous_speech && !name_changed);
236
237   if (use_festival)
238     {
239       if (festival_chatty)          
240         {
241           s = Accessible_getRoleName (obj);     
242           _festival_say (s, "voice_don_diphone", shutup_previous_speech);
243           SPI_freeString (s);
244         }
245       fprintf (stderr, "getting Name\n");
246       s = Accessible_getName (obj);
247       _festival_say (s, "voice_kal_diphone",
248                      shutup_previous_speech || festival_chatty);
249       SPI_freeString (s);
250     }
251   
252   if (Accessible_isComponent (obj))
253     {
254       AccessibleComponent *component = Accessible_getComponent (obj);
255       AccessibleComponent_getExtents (component, &x, &y, &width, &height,
256                                       SPI_COORD_TYPE_SCREEN);
257       fprintf (stderr, "Bounding box: (%ld, %ld) ; (%ld, %ld)\n",
258                x, y, x+width, y+height);
259       if (Accessible_isText (obj))
260         {
261           long x0, y0, xN, yN, w0, h0, wN, hN, nchars;
262           AccessibleText *text = Accessible_getText (obj);
263           nchars = AccessibleText_getCharacterCount (text);
264           if (nchars > 0) 
265             {
266               AccessibleText_getCharacterExtents (text, 0, &x0, &y0, &w0, &h0,
267                                               SPI_COORD_TYPE_SCREEN);
268               AccessibleText_getCharacterExtents (text, nchars-1, &xN, &yN, &wN, &hN, 
269                                                   SPI_COORD_TYPE_SCREEN);
270               x = MIN (x0, xN);
271               width = MAX (x0 + w0, xN + wN) - x;
272               fprintf (stderr, "Text bounding box: (%ld, %ld) ; (%ld, %ld)\n",
273                        x, y, x+width, y+height);
274             }
275         }
276       if (use_magnifier) {
277         magnifier_set_roi ((short) 0, x, y, width, height);
278       }
279     }
280
281   if (Accessible_isValue (obj))
282     {
283       AccessibleValue *value = Accessible_getValue (obj);
284       fprintf (stderr, "Current value = %f, min = %f; max = %f\n",
285                AccessibleValue_getCurrentValue (value),
286                AccessibleValue_getMinimumValue (value),
287                AccessibleValue_getMaximumValue (value));
288     }
289   /* if this is a text object, speak the first sentence. */
290
291   if (Accessible_isText(obj))
292
293   {
294      AccessibleText *text_interface;
295      long start_offset, end_offset;
296      char *first_sentence = "empty";
297      text_interface = Accessible_getText (obj);
298      first_sentence = AccessibleText_getTextAtOffset (
299                text_interface, (long) 0, SPI_TEXT_BOUNDARY_SENTENCE_START, &start_offset, &end_offset);
300      if (first_sentence && use_festival)
301        {
302          _festival_say(first_sentence, "voice_don_diphone", FALSE);
303          SPI_freeString (first_sentence);
304        }
305      len = AccessibleText_getCharacterCount (text_interface);
306      s = AccessibleText_getText (text_interface, 0, len);
307      fprintf (stderr, "done reporting on focussed object, text=%s\n", s);
308   }
309 }
310
311 void
312 report_focus_event (const AccessibleEvent *event, void *user_data)
313 {
314   char *s;
315
316   g_return_if_fail (event->source != NULL);
317   s = Accessible_getName (event->source);
318   if (s)
319     {
320       fprintf (stderr, "%s event from %s\n", event->type, s);
321       SPI_freeString (s);
322       report_focussed_accessible (event->source, TRUE);
323     }
324   Accessible_getParent (event->source);
325   name_changed = FALSE;
326 }
327
328 void
329 report_generic_event (const AccessibleEvent *event, void *user_data)
330 {
331   fprintf (stderr, "%s event received\n", event->type);
332 }
333
334 void
335 report_text_event (const AccessibleEvent *event, void *user_data)
336 {
337   AccessibleText *text = Accessible_getText (event->source);
338   fprintf (stderr, "%s event received\n", event->type);
339   if (use_magnifier && strcmp (event->type, "object:text-changed"))
340     {
341       long offset = AccessibleText_getCaretOffset (text);
342       long x, y, w, h;
343       fprintf (stderr, "offset %d\n", (int) offset);
344       AccessibleText_getCharacterExtents (text, offset, &x, &y, &w, &h, 
345                                           SPI_COORD_TYPE_SCREEN);
346       fprintf (stderr, "new roi %d %d %d %d\n", (int) x, (int) y, (int) w, (int) h);
347       magnifier_set_roi ((short) 0, x, y, w, h);
348     }
349   if (!strcmp (event->type, "object:text-changed"))
350     {
351       long start, end;
352       char *new_text = AccessibleText_getTextAtOffset (text, (long) 0, SPI_TEXT_BOUNDARY_SENTENCE_START, &start, &end);
353       _festival_say (new_text, "voice_kal_diphone", FALSE);
354       SPI_freeString (new_text);
355     }
356 }
357
358 void
359 report_button_press (const AccessibleEvent *event, void *user_data)
360 {
361   char *s;
362
363   g_return_if_fail (event->source != NULL);
364
365   s = Accessible_getName (event->source);
366
367   fprintf (stderr, "%s event from %s\n", event->type, s);
368   SPI_freeString (s);
369   s = Accessible_getDescription (event->source);
370   fprintf (stderr, "Object description %s\n", s);
371   SPI_freeString (s);
372 }
373
374 void
375 check_property_change (const AccessibleEvent *event, void *user_data)
376 {
377   AccessibleSelection *selection = Accessible_getSelection (event->source);
378   int n_selections;
379   int i;
380   char *s;
381   fprintf (stderr, "property change event!\n");
382   if (selection)
383   {
384     n_selections = (int) AccessibleSelection_getNSelectedChildren (selection);
385     s = Accessible_getName (event->source);
386     fprintf (stderr, "(Property) %s event from %s, %d selected children\n",
387              event->type, s, n_selections);
388     SPI_freeString (s);
389   /* for now, speak entire selection set */
390     for (i=0; i<n_selections; ++i)
391       {
392         Accessible *obj = AccessibleSelection_getSelectedChild (selection, (long) i);
393         g_return_if_fail (obj);
394         s = Accessible_getName (obj);
395         fprintf (stderr, "Child %d, name=%s\n", i, s);
396         SPI_freeString (s);
397         report_focussed_accessible (obj, i==0);
398     }
399   }
400   else if (!strcmp (event->type, "object:property-change:accessible-name"))
401     {
402       name_changed = TRUE;          
403       report_focussed_accessible (event->source, TRUE);
404     }
405   else
406     {
407       fprintf (stderr, "Property change %s received\n", event->type);
408     }
409 }
410
411 static void
412 simple_at_exit ()
413 {
414   SPI_deregisterGlobalEventListenerAll (focus_listener);
415   AccessibleEventListener_unref        (focus_listener);
416
417   SPI_deregisterGlobalEventListenerAll (property_listener);
418   AccessibleEventListener_unref        (property_listener);
419
420   SPI_deregisterGlobalEventListenerAll (generic_listener);
421   AccessibleEventListener_unref        (generic_listener);
422
423   SPI_deregisterGlobalEventListenerAll (text_listener);
424   AccessibleEventListener_unref        (text_listener);
425
426   SPI_deregisterGlobalEventListenerAll (button_listener);
427   AccessibleEventListener_unref        (button_listener);
428
429   SPI_deregisterAccessibleKeystrokeListener (command_key_listener, SPI_KEYMASK_ALT | SPI_KEYMASK_CONTROL);
430   AccessibleKeystrokeListener_unref         (command_key_listener);
431   SPI_freeAccessibleKeySet                  (command_keyset);
432
433   SPI_deregisterAccessibleKeystrokeListener (ordinary_key_listener, SPI_KEYMASK_SHIFTLOCK);
434   AccessibleKeystrokeListener_unref         (ordinary_key_listener);
435
436   SPI_event_quit ();
437 }
438
439 static SPIBoolean
440 is_command_key (const AccessibleKeystroke *key)
441 {
442   switch (key->keyID)
443     {
444     case 'Q':
445     case 'q':
446             simple_at_exit(); 
447             return TRUE; /* not reached */
448     case 'M':
449     case 'm':
450             use_magnifier = ! use_magnifier;
451             fprintf (stderr, "%ssing magnifier\n", use_magnifier ? "U" : "Not u");
452             return TRUE;
453     case 'F':
454     case 'f':
455             use_festival = ! use_festival;
456             fprintf (stderr, "%speech output\n", use_festival ? "S" : "No s");
457             return TRUE;
458     default:
459             return FALSE;
460     }
461 }
462
463 static SPIBoolean
464 report_command_key_event (const AccessibleKeystroke *key, void *user_data)
465 {
466   fprintf (stderr, "Command KeyEvent %s%c (keycode %d); string=%s; time=%lx\n",
467           (key->modifiers & SPI_KEYMASK_ALT)?"Alt-":"",
468           ((key->modifiers & SPI_KEYMASK_SHIFT)^(key->modifiers & SPI_KEYMASK_SHIFTLOCK))?
469           (char) toupper((int) key->keyID) : (char) tolower((int) key->keyID),
470           (int) key->keycode,
471           key->keystring,
472           (long int) key->timestamp);
473   return is_command_key (key);
474 }
475
476
477 static SPIBoolean
478 report_ordinary_key_event (const AccessibleKeystroke *key, void *user_data)
479 {
480   fprintf (stderr, "Received key event:\tsym %ld\n\tmods %x\n\tcode %d\n\tstring=\'%s\'\n\ttime %lx\n",
481            (long) key->keyID,
482            (unsigned int) key->modifiers,
483            (int) key->keycode,
484            key->keystring,
485            (long int) key->timestamp);
486   return FALSE;
487 }
488
489 static int
490 _festival_init ()
491 {
492   int fd;
493   struct sockaddr_in name;
494   int tries = 2;
495
496   name.sin_family = AF_INET;
497   name.sin_port = htons (1314);
498   name.sin_addr.s_addr = htonl(INADDR_ANY);
499   fd = socket (PF_INET, SOCK_STREAM, 0);
500
501   while (connect(fd, (struct sockaddr *) &name, sizeof (name)) < 0) {
502     if (!tries--) {
503       perror ("connect");
504       return -1;
505     }
506   }
507
508   _festival_write ("(audio_mode'async)\n", fd);
509   _festival_write ("(Parameter.set 'Duration_Model 'Tree_ZScore)\n", fd);
510   _festival_write ("(Parameter.set 'Duration_Stretch 0.75)\n", fd);
511   return fd;
512 }
513
514 static void 
515 _festival_say (const char *text, const char *voice, SPIBoolean shutup)
516 {
517   static int fd = 0;
518   gchar *quoted;
519   gchar *p;
520   gchar prefix[50];
521   static gchar voice_spec[32];
522   
523   if (!fd)
524     {
525       fd = _festival_init ();
526     }
527
528   fprintf (stderr, "saying text: %s\n", text);
529   
530   quoted = g_malloc(64+strlen(text)*2);
531
532   sprintf (prefix, "(SayText \"");
533
534   strncpy(quoted, prefix, 10);
535   p = quoted+strlen(prefix);
536   while (*text) {
537     if ( *text == '\\' || *text == '"' )
538       *p = '\\';
539     *p++ = *text++;
540   }
541   *p++ = '"';
542   *p++ = ')';
543   *p++ = '\n';
544   *p = 0;
545
546   if (shutup) _festival_write ("(audio_mode'shutup)\n", fd);
547   if (voice && (strncmp (voice, (char *) (voice_spec+1), strlen(voice))))
548     {
549       snprintf (voice_spec, 32, "(%s)\n", voice); 
550       _festival_write (voice_spec, fd);
551       _festival_write ("(Parameter.set 'Duration_Model 'Tree_ZScore)\n", fd);
552       _festival_write ("(Parameter.set 'Duration_Stretch 0.75)\n", fd);
553     }
554
555   _festival_write (quoted, fd);
556
557   g_free(quoted);
558 }
559
560 static void
561 _festival_write (const gchar *command_string, int fd)
562 {
563   fprintf(stderr, command_string);
564   if (fd < 0) {
565     perror("socket");
566     return;
567   }
568   write(fd, command_string, strlen(command_string));
569 }
570