b603f24a249d65f4611bdb3e731c1a3c0d75c58a
[platform/upstream/at-spi2-core.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 <sys/un.h>
28 #include <cspi/spi.h>
29 #include "../util/mag_client.h"
30 #include "../cspi/spi-private.h" /* A hack for now */
31
32 static void report_focus_event    (AccessibleEvent *event, void *user_data);
33 static void report_button_press   (AccessibleEvent *event, void *user_data);
34 static void check_property_change (AccessibleEvent *event, void *user_data);
35 static SPIBoolean report_command_key_event  (AccessibleKeystroke *stroke, void *user_data);
36 static SPIBoolean report_ordinary_key_event (AccessibleKeystroke *stroke, void *user_data);
37 static void get_environment_vars (void);
38
39 static int _festival_init ();
40 static void _festival_say (const char *text, const char *voice, SPIBoolean shutup);
41 static void _festival_write (const char *buff, int fd);
42
43 static SPIBoolean use_magnifier = FALSE;
44 static SPIBoolean use_festival = FALSE;
45 static SPIBoolean festival_chatty = FALSE;
46
47 static AccessibleEventListener *focus_listener;
48 static AccessibleEventListener *property_listener;
49 static AccessibleEventListener *button_listener;
50 static AccessibleKeystrokeListener *command_key_listener;
51 static AccessibleKeystrokeListener *ordinary_key_listener;
52
53 int
54 main (int argc, char **argv)
55 {
56   int i, j;
57   int n_desktops;
58   int n_apps;
59   Accessible *desktop;
60   Accessible *application;
61   char *s;
62
63   if ((argc > 1) && (!strncmp(argv[1],"-h",2)))
64   {
65     printf ("Usage: simple-at\n");
66     printf ("\tEnvironment variables used:\n\t\tFESTIVAL\n\t\tMAGNIFIER\n\t\tFESTIVAL_CHATTY\n");
67     exit(0);
68   }
69
70   SPI_init(TRUE);
71
72   focus_listener = createAccessibleEventListener (report_focus_event, NULL);
73   property_listener = createAccessibleEventListener (check_property_change, NULL); 
74   button_listener = createAccessibleEventListener (report_button_press, NULL);
75   registerGlobalEventListener (focus_listener, "focus:");
76   registerGlobalEventListener (property_listener, "object:property-change:accessible-selection"); 
77   registerGlobalEventListener (button_listener, "Gtk:GtkWidget:button-press-event");
78   n_desktops = getDesktopCount ();
79
80   for (i=0; i<n_desktops; ++i)
81     {
82       desktop = getDesktop (i);
83       s = Accessible_getName (desktop);
84       fprintf (stderr, "desktop %d name: %s\n", i, s);
85       SPI_freeString (s);
86       n_apps = Accessible_getChildCount (desktop);
87       for (j=0; j<n_apps; ++j)
88         {
89           application = Accessible_getChildAtIndex (desktop, j);
90           s = Accessible_getName (application);
91           fprintf (stderr, "app %d name: %s\n", j, s);
92           SPI_freeString (s);
93           Accessible_unref (application);
94         }
95       Accessible_unref (desktop);
96     }
97
98   /* prepare the keyboard snoopers */
99   command_key_listener = createAccessibleKeystrokeListener (report_command_key_event, NULL);
100   ordinary_key_listener = createAccessibleKeystrokeListener (report_ordinary_key_event, NULL);
101   
102   /* will listen only to Alt-key combinations, and only to KeyPress events */
103   registerAccessibleKeystrokeListener(command_key_listener,
104                                       (AccessibleKeySet *) SPI_KEYSET_ALL_KEYS,
105                                       SPI_KEYMASK_ALT,
106                                       (unsigned long) ( KeyPress ),
107                                       SPI_KEYLISTENER_ALL_WINDOWS);
108   
109   /* will listen only to unshifted key events, both press and release */
110   registerAccessibleKeystrokeListener(ordinary_key_listener,
111                                       (AccessibleKeySet *) SPI_KEYSET_ALL_KEYS,
112                                       SPI_KEYMASK_UNMODIFIED,
113                                       (unsigned long) ( KeyPress | KeyRelease),
114                                       SPI_KEYLISTENER_NOSYNC);
115                                       
116   /* will listen only to shifted key events, both press and release */
117   registerAccessibleKeystrokeListener(ordinary_key_listener,
118                                       (AccessibleKeySet *) SPI_KEYSET_ALL_KEYS,
119                                       SPI_KEYMASK_SHIFT,
120                                       (unsigned long) ( KeyPress | KeyRelease),
121                                       SPI_KEYLISTENER_NOSYNC);
122
123   get_environment_vars();
124
125   SPI_event_main();
126 }
127
128 static void
129 get_environment_vars (void)
130 {
131   if (g_getenv ("FESTIVAL"))
132     {
133       fprintf (stderr, "Using festival\n");
134       use_festival = TRUE;
135       if (g_getenv ("FESTIVAL_CHATTY"))
136         {
137           festival_chatty = TRUE;
138         }
139     }
140   if (g_getenv ("MAGNIFIER"))
141     {
142       fprintf (stderr, "Using magnifier\n");
143       use_magnifier = TRUE;
144     }  
145 }
146
147 void
148 report_focussed_accessible (Accessible *obj, SPIBoolean shutup_previous_speech)
149 {
150   char *s;
151   int len;
152
153   g_warning ("Report focused !");
154
155   if (use_festival)
156     {
157     if (festival_chatty)            
158       {
159         _festival_say (Accessible_getRole (obj), "voice_don_diphone", shutup_previous_speech);
160       }
161       fprintf (stderr, "getting Name\n");
162       s = Accessible_getName (obj);
163       _festival_say (s, "voice_kal_diphone",
164                      shutup_previous_speech || festival_chatty);
165       SPI_freeString (s);
166     }
167   
168   if (Accessible_isComponent (obj))
169     {
170       long x, y, width, height;
171       AccessibleComponent *component = Accessible_getComponent (obj);
172       AccessibleComponent_getExtents (component, &x, &y, &width, &height,
173                                       SPI_COORD_TYPE_SCREEN);
174       fprintf (stderr, "Bounding box: (%ld, %ld) ; (%ld, %ld)\n",
175                x, y, x+width, y+height);
176       if (use_magnifier) {
177               magnifier_set_roi ((short) 0, x, y, width, height);
178       }
179     }
180   /* if this is a text object, speak the first sentence. */
181
182   if (Accessible_isText(obj))
183
184   {
185      AccessibleText *text_interface;
186      long start_offset, end_offset;
187      char *first_sentence = "empty";
188      text_interface = Accessible_getText (obj);
189      first_sentence = AccessibleText_getTextAtOffset (
190                text_interface, (long) 0, SPI_TEXT_BOUNDARY_SENTENCE_START, &start_offset, &end_offset);
191      if (first_sentence)
192        {
193          _festival_say(first_sentence, "voice_don_diphone", FALSE);
194          SPI_freeString (first_sentence);
195        }
196      len = AccessibleText_getCharacterCount (text_interface);
197      s = AccessibleText_getText (text_interface, 0, len);
198      fprintf (stderr, "done reporting on focussed object, text=%s\n", s);
199   }
200 }
201
202 void
203 report_focus_event (AccessibleEvent *event, void *user_data)
204 {
205   char *s;
206
207   g_warning ("report focus event");
208
209   g_return_if_fail (event->source != NULL);
210
211   s = Accessible_getName (event->source);
212   if (cspi_warn_ev (cspi_ev (), "Foobar"))
213     {
214       fprintf (stderr, "%s event from %s\n", event->type, s);
215       SPI_freeString (s);
216       report_focussed_accessible (event->source, TRUE);
217     }
218   Accessible_getParent (event->source);
219 }
220
221 void
222 report_button_press (AccessibleEvent *event, void *user_data)
223 {
224   char *s;
225
226   g_return_if_fail (event->source != NULL);
227
228   s = Accessible_getName (event->source);
229
230   fprintf (stderr, "%s event from %s\n", event->type, s);
231   SPI_freeString (s);
232   s = Accessible_getDescription (event->source);
233   fprintf (stderr, "Object description %s\n", s);
234   SPI_freeString (s);
235 }
236
237 void
238 check_property_change (AccessibleEvent *event, void *user_data)
239 {
240   AccessibleSelection *selection = Accessible_getSelection (event->source);
241   int n_selections;
242   int i;
243   char *s;
244   if (selection)
245   {
246     n_selections = (int) AccessibleSelection_getNSelectedChildren (selection);
247     s = Accessible_getName (event->source);
248     fprintf (stderr, "(Property) %s event from %s, %d selected children\n",
249              event->type, s, n_selections);
250     SPI_freeString (s);
251   /* for now, speak entire selection set */
252     for (i=0; i<n_selections; ++i)
253       {
254         Accessible *obj = AccessibleSelection_getSelectedChild (selection, (long) i);
255         g_return_if_fail (obj);
256         s = Accessible_getName (obj);
257         fprintf (stderr, "Child %d, name=%s\n", i, s);
258         SPI_freeString (s);
259         report_focussed_accessible (obj, i==0);
260     }
261   }
262 }
263
264 static void
265 simple_at_exit ()
266 {
267   deregisterGlobalEventListenerAll (focus_listener);
268   deregisterGlobalEventListenerAll (property_listener);
269   deregisterGlobalEventListenerAll (button_listener);
270
271   deregisterAccessibleKeystrokeListener (command_key_listener, SPI_KEYMASK_ALT );
272   deregisterAccessibleKeystrokeListener (ordinary_key_listener, SPI_KEYMASK_UNMODIFIED );
273   deregisterAccessibleKeystrokeListener (ordinary_key_listener, SPI_KEYMASK_SHIFT );
274   AccessibleKeystrokeListener_unref (command_key_listener);
275   AccessibleKeystrokeListener_unref (ordinary_key_listener);
276   
277   SPI_exit ();
278 }
279
280 static SPIBoolean
281 is_command_key (AccessibleKeystroke *key)
282 {
283   switch (key->keyID)
284     {
285     case 'Q':
286     case 'q':
287             simple_at_exit(); 
288             return TRUE; /* not reached */
289     case 'M':
290     case 'm':
291             use_magnifier = ! use_magnifier;
292             return TRUE;
293     case 'F':
294     case 'f':
295             use_festival = ! use_festival;
296             return TRUE;
297     default:
298             return FALSE;
299     }
300 }
301
302 static SPIBoolean
303 report_command_key_event (AccessibleKeystroke *key, void *user_data)
304 {
305   fprintf (stderr, "Command KeyEvent %s%c (keycode %d)\n",
306           (key->modifiers & SPI_KEYMASK_ALT)?"Alt-":"",
307           ((key->modifiers & SPI_KEYMASK_SHIFT)^(key->modifiers & SPI_KEYMASK_SHIFTLOCK))?
308           (char) toupper((int) key->keyID) : (char) tolower((int) key->keyID),
309           (int) key->keycode);
310   return is_command_key (key);
311 }
312
313
314 static SPIBoolean
315 report_ordinary_key_event (AccessibleKeystroke *key, void *user_data)
316 {
317   fprintf (stderr, "Received key event:\tsym %ld\n\tmods %x\n\tcode %d\n\ttime %ld\n",
318            (long) key->keyID,
319            (unsigned int) key->modifiers,
320            (int) key->keycode,
321            (long int) key->timestamp);
322   return FALSE;
323 }
324
325 static int
326 _festival_init ()
327 {
328   int fd;
329   struct sockaddr_in name;
330   int tries = 2;
331
332   name.sin_family = AF_INET;
333   name.sin_port = htons (1314);
334   name.sin_addr.s_addr = htonl(INADDR_ANY);
335   fd = socket (PF_INET, SOCK_STREAM, 0);
336
337   while (connect(fd, (struct sockaddr *) &name, sizeof (name)) < 0) {
338     if (!tries--) {
339       perror ("connect");
340       return -1;
341     }
342   }
343
344   _festival_write ("(audio_mode'async)\n", fd);
345   _festival_write ("(Parameter.set 'Duration_Model 'Tree_ZScore)\n", fd);
346   _festival_write ("(Parameter.set 'Duration_Stretch 0.75)\n", fd);
347   return fd;
348 }
349
350 static void 
351 _festival_say (const char *text, const char *voice, SPIBoolean shutup)
352 {
353   static int fd = 0;
354   gchar *quoted;
355   gchar *p;
356   gchar prefix[50];
357   static gchar voice_spec[32];
358   
359   if (!fd)
360     {
361       fd = _festival_init ();
362     }
363
364   fprintf (stderr, "saying text: %s\n", text);
365   
366   quoted = g_malloc(64+strlen(text)*2);
367
368   sprintf (prefix, "(SayText \"");
369
370   strncpy(quoted, prefix, 10);
371   p = quoted+strlen(prefix);
372   while (*text) {
373     if ( *text == '\\' || *text == '"' )
374       *p = '\\';
375     *p++ = *text++;
376   }
377   *p++ = '"';
378   *p++ = ')';
379   *p++ = '\n';
380   *p = 0;
381
382   if (shutup) _festival_write ("(audio_mode'shutup)\n", fd);
383   if (voice && (strncmp (voice, (char *) (voice_spec+1), strlen(voice))))
384     {
385       snprintf (voice_spec, 32, "(%s)\n", voice); 
386       _festival_write (voice_spec, fd);
387       _festival_write ("(Parameter.set 'Duration_Model 'Tree_ZScore)\n", fd);
388       _festival_write ("(Parameter.set 'Duration_Stretch 0.75)\n", fd);
389     }
390
391   _festival_write (quoted, fd);
392
393   g_free(quoted);
394 }
395
396 static void
397 _festival_write (const gchar *command_string, int fd)
398 {
399   fprintf(stderr, command_string);
400   if (fd < 0) {
401     perror("socket");
402     return;
403   }
404   write(fd, command_string, strlen(command_string));
405 }
406