1 /*
2  * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 /*
27  * A sample Assistive Technology which queries the JavaVM to get the Java
28  * Accessibility information available for a Java UI object, using the Java
29  * Access Bridge.
30  */
31 
32 #include <windows.h>  // includes basic windows functionality
33 #include <jni.h>
34 
35 #include "jaccessinspectorResource.h"
36 #include "AccessBridgeCalls.h"
37 #include "AccessBridgeCallbacks.h"
38 
39 #include <stdio.h>
40 #include <time.h>
41 #include <string.h>
42 
43 #include "jaccessinspector.h"
44 #include "AccessInfo.h"
45 #include "MessageHistory.h"
46 
47 #define TIMER_ID 1
48 #define DISPLAY_INFO_MESSAGE WM_USER+1
49 #define DISPLAY_HWND_INFO_MESSAGE WM_USER+2
50 
51 HWND theDialogWindow;
52 HWND theGoToDialogWindow;
53 HINSTANCE theInstance;
54 BOOL theAccessBridgeLoadedFlag;
55 
56 HHOOK prevKbdHook;
57 HHOOK prevMouseHook;
58 
59 BOOL updateMouse;
60 BOOL updateF1;
61 BOOL updateF2;
62 
63 BOOL trackMouse;
64 BOOL trackMouseExited;
65 BOOL trackMouseClicked;
66 BOOL trackMousePressed;
67 BOOL trackMouseReleased;
68 
69 BOOL trackFocus;
70 BOOL trackFocusLost;
71 BOOL trackCaret;
72 BOOL trackShutdown;
73 
74 BOOL trackMenuSelected;
75 BOOL trackMenuDeselected;
76 BOOL trackMenuCanceled;
77 
78 BOOL trackPopupVisible;
79 BOOL trackPopupInvisible;
80 BOOL trackPopupCanceled;
81 
82 //BOOL trackPropertyChange;
83 
84 BOOL trackPropertyNameChange;
85 BOOL trackPropertyDescriptionChange;
86 BOOL trackPropertyStateChange;
87 BOOL trackPropertyValueChange;
88 BOOL trackPropertySelectionChange;
89 BOOL trackPropertyTextChange;
90 BOOL trackPropertyCaretChange;
91 BOOL trackPropertyVisibleDataChange;
92 BOOL trackPropertyChildChange;
93 BOOL trackPropertyActiveDescendentChange;
94 BOOL trackPropertyTableModelChange;
95 
96 
97 FILE *logfile = NULL;
98 
99 MessageHistory g_MessageHistory;
100 
101 /**
102  * WinMain
103  *
104  */
WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nShowCmd)105 int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShowCmd) {
106     MSG msg;
107 
108     g_LogStringCallback = AddToMessageHistory;
109     theInstance = hInst;
110     theDialogWindow = NULL;
111     theGoToDialogWindow = NULL;
112 
113     updateF1 = FALSE;
114     updateF2 = FALSE;
115     updateMouse = FALSE;
116 
117     theAccessBridgeLoadedFlag = FALSE;
118 
119     ReadActiveEventOptionsFromRegistry ();
120 
121     if (InitWindow(hInst)) {
122         if (initializeAccessBridge() == TRUE) {
123             theAccessBridgeLoadedFlag = TRUE;
124             ApplyEventOptions(theDialogWindow);
125             EnableMessageNavButtons();
126             HACCEL hAccel =
127                 ::LoadAccelerators (theInstance, MAKEINTRESOURCE(IDR_ACCELERATOR));
128 
129             while (GetMessage(&msg, NULL, 0, 0)) {
130                 if ( FALSE == TranslateAccelerator(theDialogWindow, hAccel, &msg) ) {
131                     if ( ( ( NULL == theDialogWindow ) ||
132                            ( FALSE == IsDialogMessage(theDialogWindow, &msg) ) ) &&
133                          ( ( NULL == theGoToDialogWindow ) ||
134                            ( FALSE == IsDialogMessage(theGoToDialogWindow, &msg) ) ) ) {
135                         TranslateMessage(&msg);
136                         DispatchMessage(&msg);
137                     }
138                 }
139             }
140             if (theAccessBridgeLoadedFlag == TRUE) {
141                 shutdownAccessBridge();
142             }
143             SaveActiveEventOptionsToRegistry ();
144         }
145     }
146     return(0);
147 }
148 
149 char szAppName [] = "JACCESSINSPECTORWINDOW";
150 
151 /**
152  * Real(tm) MS-Windows window initialization
153  *
154  */
InitWindow(HANDLE hInstance)155 BOOL InitWindow (HANDLE hInstance) {
156     theDialogWindow = CreateDialog((struct HINSTANCE__ *)hInstance,
157                                    szAppName,
158                                    NULL,
159                                    jaccessinspectorDialogProc);
160 
161     // If window could not be created, return "failure".
162     if (!theDialogWindow)
163         return FALSE;
164 
165     if (logfile == null) {
166         logfile = fopen(JACCESSINSPECTOR_LOG, "w"); // overwrite existing log file
167         logString(logfile, "Starting jaccessinspector.exe %s\n", getTimeAndDate());
168     }
169 
170     // Make the window visible, update its client area, & return "success".
171     SetWindowText(theDialogWindow, "jaccessinspector");
172     ShowWindow(theDialogWindow, SW_SHOWNORMAL);
173     UpdateWindow(theDialogWindow);
174 
175     return TRUE;
176 }
177 
178 /**
179  * Display Accessible information about the object under the mouse
180  */
displayAccessibleInfo(long vmID,AccessibleContext ac,int x,int y)181 void displayAccessibleInfo(long vmID, AccessibleContext ac, int x, int y) {
182     char buffer[HUGE_BUFSIZE];
183 
184     getAccessibleInfo(vmID, ac, x, y, buffer, (int)(sizeof(buffer)));
185     displayAndLog(theDialogWindow, cjaccessinspectorText, logfile, (char *)buffer);
186 }
187 
188 /**
189  * Display Java event info
190  */
displayJavaEvent(long vmID,AccessibleContext ac,char * announcement)191 void displayJavaEvent(long vmID, AccessibleContext ac, char *announcement) {
192     char buffer[HUGE_BUFSIZE];
193     char *bufOffset;
194 
195     strncpy(buffer, announcement, sizeof(buffer));
196 
197     bufOffset = (char *)(buffer + strlen(buffer));
198     getAccessibleInfo( vmID, ac, -1, -1, bufOffset,
199                        (int)(sizeof(buffer) - strlen(buffer)) );
200     displayAndLog(theDialogWindow, cjaccessinspectorText, logfile, (char *)buffer);
201 }
202 
203 
204 /**
205  * Display Accessible propertyChange event info
206  */
displayAccessiblePropertyChange(long vmID,AccessibleContext ac,char * announcement)207 void displayAccessiblePropertyChange(long vmID, AccessibleContext ac,
208                                      char *announcement) {
209     char buffer[HUGE_BUFSIZE];
210     char *bufOffset;
211 
212     strncpy(buffer, announcement, sizeof(buffer));
213 
214     bufOffset = (char *) (buffer + strlen(buffer));
215     getAccessibleInfo( vmID, ac, -1, -1, bufOffset,
216                        (int)(sizeof(buffer) - strlen(buffer)) );
217     displayAndLog(theDialogWindow, cjaccessinspectorText, logfile, (char *)buffer);
218 }
219 
220 
221 /**
222  * Update display under mouse when it moves
223  */
echoMouseObject()224 void echoMouseObject() {
225     long vmID;
226     AccessibleContext acParent;
227     AccessibleContext ac;
228     POINT p;
229     HWND hwnd;
230     RECT windowRect;
231 
232     GetCursorPos(&p);
233     hwnd = WindowFromPoint(p);
234     if (GetAccessibleContextFromHWND(hwnd, &vmID, &acParent)) {
235         GetWindowRect(hwnd, &windowRect);
236         // send the point in global coordinates; Java will handle it!
237         if (GetAccessibleContextAt(vmID, acParent, (jint) p.x, (jint) p.y, &ac)) {
238             displayAccessibleInfo(vmID, ac, p.x, p.y);  // can handle null
239             ReleaseJavaObject(vmID, ac);
240         }
241     }
242 }
243 
244 
245 /**
246  * Update display under HWND the mouse is in
247  */
echoMouseHWNDObject()248 void echoMouseHWNDObject() {
249     long vmID;
250     AccessibleContext ac;
251     POINT p;
252     HWND hwnd;
253 
254     GetCursorPos(&p);
255     hwnd = WindowFromPoint(p);
256 
257     if (GetAccessibleContextFromHWND(hwnd, &vmID, &ac)) {
258         displayAccessibleInfo(vmID, ac, 0, 0);  // can handle null
259         ReleaseJavaObject(vmID, ac);
260     }
261 }
262 
263 /**
264  * Display Accessible information about the object that has focus in
265  * the topmost Java HWND
266  *
267  */
displayFocusedObject()268 void displayFocusedObject() {
269     HWND hWnd;
270     long vmID;
271     AccessibleContext ac;
272 
273     hWnd = GetTopWindow(NULL);
274     while (hWnd != NULL) {
275         if (IsJavaWindow(hWnd)) {
276             if (GetAccessibleContextWithFocus(hWnd, &vmID, &ac) == TRUE) {
277                 displayAccessibleInfo(vmID, ac, 0, 0);
278                 ReleaseJavaObject(vmID, ac);
279             }
280             return;
281         } else {
282             hWnd = GetNextWindow(hWnd, GW_HWNDNEXT);
283         }
284     }
285 }
286 
287 /*
288  * Handle notification of the Java application shutting down
289  */
HandleJavaShutdown(long vmID)290 void HandleJavaShutdown(long vmID) {
291     char s[1024];
292     wsprintf(s, "Java VM 0x%X terminated\r\n\r\n", vmID);
293 
294     displayJavaEvent(vmID, null, s); // intentially passing null AccessibleContext
295     displayAndLog(theDialogWindow, cjaccessinspectorText, logfile, (char *)s);
296 }
297 
298 /**
299  * Handle a FocusGained event
300  */
HandleJavaFocusGained(long vmID,FocusEvent event,AccessibleContext ac)301 void HandleJavaFocusGained(long vmID, FocusEvent event, AccessibleContext ac) {
302 
303     char s[1024];
304     wsprintf(s, "FocusGained\r\n\r\n");
305 
306     if (ac != (AccessibleContext) 0) {
307         displayJavaEvent(vmID, ac, s);
308     }
309 
310     ReleaseJavaObject(vmID, ac);     // must always release, to stave off memory leaks
311     ReleaseJavaObject(vmID, event);  // must always release, to stave off memory leaks
312 }
313 
314 /**
315  * Handle a FocusLost event
316  */
HandleJavaFocusLost(long vmID,FocusEvent event,AccessibleContext ac)317 void HandleJavaFocusLost(long vmID, FocusEvent event, AccessibleContext ac) {
318 
319     // NOTE: calling GetAccessibleContextWithFocus() after a FocusLost event
320     //       would result in a null AccessibleContext being returned, since
321     //       at that point, no object has the focus.  If the topmost window
322     //       does not belong to a JavaVM, then no component within a JavaVM
323     //       will have the focus (and again, GetAccessibleContextWithFocus()
324     //       will return a null AccessibleContext).  You should always get
325     //       a FocusLost event when a window not belonging to a JavaVM becomes
326     //       topmost.
327 
328     char s[1024];
329     wsprintf(s, "FocusLost\r\n\r\n");
330 
331     if (ac != (AccessibleContext) 0) {
332         displayJavaEvent(vmID, ac, s);
333     }
334     /*
335     if (ac != (AccessibleContext) 0) {
336         displayAccessibleInfo(vmID, ac, 0, 0);
337     }
338     */
339     ReleaseJavaObject(vmID, ac);     // must always release, to stave off memory leaks
340     ReleaseJavaObject(vmID, event);  // must always release, to stave off memory leaks
341 }
342 
343 /**
344  * Handle a CaretUpdate event
345  */
HandleJavaCaretUpdate(long vmID,CaretEvent event,AccessibleContext ac)346 void HandleJavaCaretUpdate(long vmID, CaretEvent event, AccessibleContext ac) {
347     if (ac != (AccessibleContext) 0) {
348         displayAccessibleInfo(vmID, ac, 0, 0);
349     }
350     ReleaseJavaObject(vmID, ac);     // must always release, to stave off memory leaks
351     ReleaseJavaObject(vmID, event);  // must always release, to stave off memory leaks
352 }
353 
354 /**
355  * Handle a MouseClicked event
356  */
HandleMouseClicked(long vmID,MouseEvent event,AccessibleContext ac)357 void HandleMouseClicked(long vmID, MouseEvent event, AccessibleContext ac) {
358     if (ac != (AccessibleContext) 0) {
359         displayAccessibleInfo(vmID, ac, 0, 0);
360     }
361     ReleaseJavaObject(vmID, ac);     // must always release, to stave off memory leaks
362     ReleaseJavaObject(vmID, event);  // must always release, to stave off memory leaks
363 }
364 
365 /**
366  * Handle a MouseEntered event
367  */
HandleMouseEntered(long vmID,MouseEvent event,AccessibleContext ac)368 void HandleMouseEntered(long vmID, MouseEvent event, AccessibleContext ac) {
369     if (ac != (AccessibleContext) 0) {
370         displayAccessibleInfo(vmID, ac, 0, 0);
371     }
372 
373     ReleaseJavaObject(vmID, ac);     // must always release, to stave off memory leaks
374     ReleaseJavaObject(vmID, event);  // must always release, to stave off memory leaks
375 }
376 
377 /**
378  * Handle a MouseExited event
379  */
HandleMouseExited(long vmID,MouseEvent event,AccessibleContext ac)380 void HandleMouseExited(long vmID, MouseEvent event, AccessibleContext ac) {
381     if (ac != (AccessibleContext) 0) {
382         displayAccessibleInfo(vmID, ac, 0, 0);
383     }
384     ReleaseJavaObject(vmID, ac);     // must always release, to stave off memory leaks
385     ReleaseJavaObject(vmID, event);  // must always release, to stave off memory leaks
386 }
387 
388 /**
389  * Handle a MousePressed event
390  */
HandleMousePressed(long vmID,MouseEvent event,AccessibleContext ac)391 void HandleMousePressed(long vmID, MouseEvent event, AccessibleContext ac) {
392     if (ac != (AccessibleContext) 0) {
393         displayAccessibleInfo(vmID, ac, 0, 0);
394     }
395     ReleaseJavaObject(vmID, ac);     // must always release, to stave off memory leaks
396     ReleaseJavaObject(vmID, event);  // must always release, to stave off memory leaks
397 }
398 
399 /**
400  * Handle a MouseReleased event
401  */
HandleMouseReleased(long vmID,MouseEvent event,AccessibleContext ac)402 void HandleMouseReleased(long vmID, MouseEvent event, AccessibleContext ac) {
403     if (ac != (AccessibleContext) 0) {
404         displayAccessibleInfo(vmID, ac, 0, 0);
405     }
406     ReleaseJavaObject(vmID, ac);     // must always release, to stave off memory leaks
407     ReleaseJavaObject(vmID, event);  // must always release, to stave off memory leaks
408 }
409 
410 /**
411  * Handle a MenuCanceled event
412  */
HandleMenuCanceled(long vmID,MenuEvent event,AccessibleContext ac)413 void HandleMenuCanceled(long vmID, MenuEvent event, AccessibleContext ac) {
414     if (ac != (AccessibleContext) 0) {
415         displayAccessibleInfo(vmID, ac, 0, 0);
416     }
417     ReleaseJavaObject(vmID, ac);    // must always release, to stave off memory leaks
418     ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks
419 }
420 
421 /**
422  * Handle a MenuDeselected event
423  */
HandleMenuDeselected(long vmID,MenuEvent event,AccessibleContext ac)424 void HandleMenuDeselected(long vmID, MenuEvent event, AccessibleContext ac) {
425     if (ac != (AccessibleContext) 0) {
426         displayAccessibleInfo(vmID, ac, 0, 0);
427     }
428     ReleaseJavaObject(vmID, ac);     // must always release, to stave off memory leaks
429     ReleaseJavaObject(vmID, event);  // must always release, to stave off memory leaks
430 }
431 
432 /**
433  * Handle a MenuSelected event
434  */
HandleMenuSelected(long vmID,MenuEvent event,AccessibleContext ac)435 void HandleMenuSelected(long vmID, MenuEvent event, AccessibleContext ac) {
436     if (ac != (AccessibleContext) 0) {
437         displayAccessibleInfo(vmID, ac, 0, 0);
438     }
439     ReleaseJavaObject(vmID, ac);     // must always release, to stave off memory leaks
440     ReleaseJavaObject(vmID, event);  // must always release, to stave off memory leaks
441 }
442 
443 /**
444  * Handle a PopupMenuCanceled event
445  */
HandlePopupMenuCanceled(long vmID,MenuEvent event,AccessibleContext ac)446 void HandlePopupMenuCanceled(long vmID, MenuEvent event, AccessibleContext ac) {
447     if (ac != (AccessibleContext) 0) {
448         displayAccessibleInfo(vmID, ac, 0, 0);
449     }
450     ReleaseJavaObject(vmID, ac);     // must always release, to stave off memory leaks
451     ReleaseJavaObject(vmID, event);  // must always release, to stave off memory leaks
452 }
453 
454 /**
455  * Handle a PopupMenuWillBecomeInvisible event
456  */
HandlePopupMenuWillBecomeInvisible(long vmID,MenuEvent event,AccessibleContext ac)457 void HandlePopupMenuWillBecomeInvisible(long vmID, MenuEvent event, AccessibleContext ac) {
458     if (ac != (AccessibleContext) 0) {
459         displayAccessibleInfo(vmID, ac, 0, 0);
460     }
461     ReleaseJavaObject(vmID, ac);     // must always release, to stave off memory leaks
462     ReleaseJavaObject(vmID, event);  // must always release, to stave off memory leaks
463 }
464 
465 /**
466  * Handle a PopupMenuWillBecomeVisible event
467  */
HandlePopupMenuWillBecomeVisible(long vmID,MenuEvent event,AccessibleContext ac)468 void HandlePopupMenuWillBecomeVisible(long vmID, MenuEvent event, AccessibleContext ac) {
469     if (ac != (AccessibleContext) 0) {
470         displayAccessibleInfo(vmID, ac, 0, 0);
471     }
472     ReleaseJavaObject(vmID, ac);     // must always release, to stave off memory leaks
473     ReleaseJavaObject(vmID, event);  // must always release, to stave off memory leaks
474 }
475 
476 
477 
478 
479 /**
480  * Handle a HandlePropertyNameChange event
481  */
HandlePropertyNameChange(long vmID,PropertyChangeEvent event,AccessibleContext ac,wchar_t * oldName,wchar_t * newName)482 void HandlePropertyNameChange(long vmID, PropertyChangeEvent event, AccessibleContext ac,
483                               wchar_t *oldName, wchar_t *newName) {
484     char s[1024];
485     wsprintf(s, "Name changed event: old = %ls; new = %ls\r\n\r\n", oldName, newName);
486 
487     if (ac != (AccessibleContext) 0) {
488         displayAccessiblePropertyChange(vmID, ac, s);
489     }
490     ReleaseJavaObject(vmID, ac);     // must always release, to stave off memory leaks
491     ReleaseJavaObject(vmID, event);  // must always release, to stave off memory leaks
492 }
493 
494 /**
495  * Handle a HandlePropertyDescriptionChange event
496  */
HandlePropertyDescriptionChange(long vmID,PropertyChangeEvent event,AccessibleContext ac,wchar_t * oldDescription,wchar_t * newDescription)497 void HandlePropertyDescriptionChange( long vmID,
498                                       PropertyChangeEvent event,
499                                       AccessibleContext ac,
500                                       wchar_t *oldDescription,
501                                       wchar_t *newDescription ) {
502     char s[1024];
503     wsprintf( s, "Description changed event: old = %ls; new = %ls\r\n\r\n",
504               oldDescription, newDescription );
505 
506     if (ac != (AccessibleContext) 0) {
507         displayAccessiblePropertyChange(vmID, ac, s);
508     }
509     ReleaseJavaObject(vmID, ac);     // must always release, to stave off memory leaks
510     ReleaseJavaObject(vmID, event);  // must always release, to stave off memory leaks
511 }
512 
513 /**
514  * Handle a HandlePropertyStateChange event
515  */
HandlePropertyStateChange(long vmID,PropertyChangeEvent event,AccessibleContext ac,wchar_t * oldState,wchar_t * newState)516 void HandlePropertyStateChange( long vmID, PropertyChangeEvent event,
517                                 AccessibleContext ac,
518                                 wchar_t *oldState, wchar_t *newState ) {
519     char s[1024];
520     wsprintf( s, "State changed event: old = %ls; new = %ls\r\n\r\n",
521               oldState, newState );
522 
523     if (ac != (AccessibleContext) 0) {
524         displayAccessiblePropertyChange(vmID, ac, s);
525     }
526     ReleaseJavaObject(vmID, ac);     // must always release, to stave off memory leaks
527     ReleaseJavaObject(vmID, event);  // must always release, to stave off memory leaks
528 }
529 
530 /**
531  * Handle a HandlePropertyValueChange event
532  */
HandlePropertyValueChange(long vmID,PropertyChangeEvent event,AccessibleContext ac,wchar_t * oldValue,wchar_t * newValue)533 void HandlePropertyValueChange( long vmID, PropertyChangeEvent event,
534                                 AccessibleContext ac,
535                                 wchar_t *oldValue, wchar_t *newValue ) {
536     char s[1024];
537     wsprintf( s, "Value changed event: old = %ls; new = %ls\r\n\r\n",
538               oldValue, newValue );
539 
540     if (ac != (AccessibleContext) 0) {
541         displayAccessiblePropertyChange(vmID, ac, s);
542     }
543     ReleaseJavaObject(vmID, ac);     // must always release, to stave off memory leaks
544     ReleaseJavaObject(vmID, event);  // must always release, to stave off memory leaks
545 }
546 
547 /**
548  * Handle a HandlePropertySelectionChange event
549  */
HandlePropertySelectionChange(long vmID,PropertyChangeEvent event,AccessibleContext ac)550 void HandlePropertySelectionChange( long vmID, PropertyChangeEvent event,
551                                     AccessibleContext ac ) {
552     if (ac != (AccessibleContext) 0) {
553         displayAccessiblePropertyChange( vmID, ac,
554                                          "Selection changed event\r\n\r\n" );
555     }
556     ReleaseJavaObject(vmID, ac);     // must always release, to stave off memory leaks
557     ReleaseJavaObject(vmID, event);  // must always release, to stave off memory leaks
558 }
559 
560 /**
561  * Handle a HandlePropertyTextChange event
562  */
HandlePropertyTextChange(long vmID,PropertyChangeEvent event,AccessibleContext ac)563 void HandlePropertyTextChange( long vmID, PropertyChangeEvent event,
564                                AccessibleContext ac ) {
565     if (ac != (AccessibleContext) 0) {
566         displayAccessiblePropertyChange(vmID, ac, "Text changed event\r\n\r\n");
567     }
568     ReleaseJavaObject(vmID, ac);     // must always release, to stave off memory leaks
569     ReleaseJavaObject(vmID, event);  // must always release, to stave off memory leaks
570 }
571 
572 /**
573  * Handle a HandlePropertyCaretChange event
574  */
HandlePropertyCaretChange(long vmID,PropertyChangeEvent event,AccessibleContext ac,int oldPosition,int newPosition)575 void HandlePropertyCaretChange( long vmID, PropertyChangeEvent event,
576                                 AccessibleContext ac,
577                                 int oldPosition, int newPosition ) {
578     char s[1024];
579 
580     wsprintf( s, "Caret changed event: oldPosition = %d; newPosition = %d\r\n\r\n",
581               oldPosition, newPosition );
582 
583     if (ac != (AccessibleContext) 0) {
584         displayAccessiblePropertyChange(vmID, ac, s);
585     }
586     ReleaseJavaObject(vmID, ac);     // must always release, to stave off memory leaks
587     ReleaseJavaObject(vmID, event);  // must always release, to stave off memory leaks
588 }
589 
590 /**
591  * Handle a HandlePropertyVisibleDataChange event
592  */
HandlePropertyVisibleDataChange(long vmID,PropertyChangeEvent event,AccessibleContext ac)593 void HandlePropertyVisibleDataChange( long vmID, PropertyChangeEvent event,
594                                       AccessibleContext ac ) {
595     if (ac != (AccessibleContext) 0) {
596         displayAccessiblePropertyChange( vmID, ac,
597                                          "VisibleData changed event\r\n\r\n" );
598     }
599     ReleaseJavaObject(vmID, ac);     // must always release, to stave off memory leaks
600     ReleaseJavaObject(vmID, event);  // must always release, to stave off memory leaks
601 }
602 
603 /**
604  * Handle a HandlePropertyChildChange event
605  */
HandlePropertyChildChange(long vmID,PropertyChangeEvent event,AccessibleContext ac,JOBJECT64 oldChild,JOBJECT64 newChild)606 void HandlePropertyChildChange( long vmID, PropertyChangeEvent event,
607                                 AccessibleContext ac,
608                                 JOBJECT64 oldChild, JOBJECT64 newChild ) {
609     char buffer[HUGE_BUFSIZE];
610     char *bufOffset;
611 
612     sprintf( buffer,
613              "Child property changed event:\r\n=======================\r\n\r\n" );
614 
615     if (oldChild != 0) {
616         strncat(buffer, "Old Accessible Child info:\r\n\r\n", sizeof(buffer));
617         bufOffset = (char *) (buffer + strlen(buffer));
618         getAccessibleInfo( vmID, oldChild, 0, 0, bufOffset,
619                            (int)(sizeof(buffer) - strlen(buffer)) );
620         strncat(buffer, "\r\n\r\n", sizeof(buffer));
621     }
622 
623     if (newChild != 0) {
624         strncat(buffer, "New Accessible Child info:\r\n\r\n", sizeof(buffer));
625         bufOffset = (char *) (buffer + strlen(buffer));
626         getAccessibleInfo( vmID, newChild, 0, 0, bufOffset,
627                           (int)(sizeof(buffer) - strlen(buffer)) );
628         strncat(buffer, "\r\n\r\n", sizeof(buffer));
629     }
630 
631     if (ac != (AccessibleContext) 0) {
632         displayAccessiblePropertyChange(vmID, ac, buffer);
633     }
634 
635     ReleaseJavaObject(vmID, ac);        // must always release, to stave off memory leaks
636     ReleaseJavaObject(vmID, event);     // must always release, to stave off memory leaks
637     ReleaseJavaObject(vmID, oldChild);  // must always release, to stave off memory leaks
638     ReleaseJavaObject(vmID, newChild);  // must always release, to stave off memory leaks
639 }
640 
641 /**
642  * Handle a HandlePropertyActiveDescendentChange event
643  */
HandlePropertyActiveDescendentChange(long vmID,PropertyChangeEvent event,AccessibleContext ac,JOBJECT64 oldActiveDescendent,JOBJECT64 newActiveDescendent)644 void HandlePropertyActiveDescendentChange( long vmID, PropertyChangeEvent event,
645                                            AccessibleContext ac,
646                                            JOBJECT64 oldActiveDescendent,
647                                            JOBJECT64 newActiveDescendent ) {
648     char buffer[HUGE_BUFSIZE];
649 
650     sprintf( buffer,
651              "ActiveDescendent property changed event:\r\n=======================\r\n\r\n" );
652 
653 #ifdef _notdef
654     char *bufOffset;
655     if (oldActiveDescendent != 0) {
656         strncat(buffer, "Old Accessible ActiveDescendent info:\r\n\r\n", sizeof(buffer));
657         bufOffset = (char *) (buffer + strlen(buffer));
658         getAccessibleInfo( vmID, oldActiveDescendent, 0, 0, bufOffset,
659                            (int)(sizeof(buffer) - strlen(buffer)) );
660         strncat(buffer, "\r\n\r\n", sizeof(buffer));
661     }
662 
663     if (newActiveDescendent != 0) {
664         strncat( buffer, "New Accessible ActiveDescendent info:\r\n\r\n",
665                  sizeof(buffer) );
666         bufOffset = (char *) (buffer + strlen(buffer));
667         getAccessibleInfo( vmID, newActiveDescendent, 0, 0, bufOffset,
668                            (int)(sizeof(buffer) - strlen(buffer)) );
669         strncat(buffer, "\r\n\r\n", sizeof(buffer));
670     }
671 #endif _notdef
672 
673     if (newActiveDescendent != (AccessibleContext) 0) {
674         displayAccessiblePropertyChange(vmID, newActiveDescendent, buffer);
675     }
676 
677     ReleaseJavaObject(vmID, ac);  // must always release, to stave off memory leaks
678     ReleaseJavaObject(vmID, event);  // must always release, to stave off memory leaks
679     ReleaseJavaObject(vmID, oldActiveDescendent);  // must always release, to stave off memory leaks
680     ReleaseJavaObject(vmID, newActiveDescendent);  // must always release, to stave off memory leaks
681 }
682 
683 
684 /**
685  * Handle a HandlePropertyTableModelChange event
686  */
HandlePropertyTableModelChange(long vmID,PropertyChangeEvent event,AccessibleContext ac,wchar_t * oldValue,wchar_t * newValue)687 void HandlePropertyTableModelChange( long vmID, PropertyChangeEvent event,
688                                      AccessibleContext ac,
689                                      wchar_t *oldValue, wchar_t *newValue ) {
690 
691     char s[1024];
692     wsprintf( s, "Table Model Change: old = %ls; new = %ls\r\n\r\n",
693               oldValue, newValue );
694 
695     if (ac != (AccessibleContext) 0) {
696         displayAccessiblePropertyChange(vmID, ac, s);
697     }
698     ReleaseJavaObject(vmID, ac);     // must always release, to stave off memory leaks
699     ReleaseJavaObject(vmID, event);  // must always release, to stave off memory leaks
700 }
701 
702 
703 
704 #define DOWN_UP_FLAG 1<<31
705 
TimerProc(HWND hWnd,UINT uTimerMsg,UINT uTimerID,DWORD dwTime)706 void CALLBACK TimerProc(HWND hWnd, UINT uTimerMsg, UINT uTimerID, DWORD dwTime) {
707     // when mouse settles from movement
708     KillTimer(hWnd, uTimerID);
709     if (updateMouse == TRUE) {
710         PostMessage(theDialogWindow, DISPLAY_INFO_MESSAGE, 0, 0);
711     }
712 }
713 
KeyboardProc(int code,WPARAM wParam,LPARAM lParam)714 LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam) {
715     // on mouse-up of F1
716     if (code < 0) {
717         CallNextHookEx(prevKbdHook, code, wParam, lParam);
718     } else if (wParam == VK_F1 && lParam & DOWN_UP_FLAG && updateF1) {
719         PostMessage(theDialogWindow, DISPLAY_INFO_MESSAGE, wParam, lParam);
720     } else if (wParam == VK_F2 && lParam & DOWN_UP_FLAG && updateF2) {
721         PostMessage(theDialogWindow, DISPLAY_HWND_INFO_MESSAGE, wParam, lParam);
722     }
723     return 0;
724 }
725 
MouseProc(int code,WPARAM wParam,LPARAM lParam)726 LRESULT CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam) {
727     // when mouse settles from movement
728     if (code < 0) {
729         CallNextHookEx(prevMouseHook, code, wParam, lParam);
730     } else {
731         // reset the timer every time the mouse moves
732         KillTimer(theDialogWindow, TIMER_ID);
733         SetTimer(theDialogWindow, TIMER_ID, 1000, (TIMERPROC)TimerProc);
734     }
735     return 0;
736 }
737 
exitjaccessinspector(HWND hWnd)738 void exitjaccessinspector(HWND hWnd) {
739     EndDialog(hWnd, TRUE);
740     PostQuitMessage (0);
741 }
742 
743 #define INSTALL_EVENT_LISTENER(toggleVal, setFP, handler)   \
744     if (toggleVal) {                                        \
745         setFP(handler);                                     \
746     }
747 
reinstallEventListeners()748 void reinstallEventListeners() {
749     INSTALL_EVENT_LISTENER(trackMouse, SetMouseEntered, HandleMouseEntered);
750     INSTALL_EVENT_LISTENER(trackMouseExited, SetMouseExited, HandleMouseExited);
751     INSTALL_EVENT_LISTENER(trackMouseClicked, SetMouseClicked, HandleMouseClicked);
752     INSTALL_EVENT_LISTENER(trackMousePressed, SetMousePressed, HandleMousePressed);
753     INSTALL_EVENT_LISTENER(trackMouseReleased, SetMouseReleased, HandleMouseReleased);
754     INSTALL_EVENT_LISTENER(trackShutdown, SetJavaShutdown, HandleJavaShutdown);
755     INSTALL_EVENT_LISTENER(trackFocus, SetFocusGained, HandleJavaFocusGained);
756     INSTALL_EVENT_LISTENER(trackFocusLost, SetFocusLost, HandleJavaFocusLost);
757     INSTALL_EVENT_LISTENER(trackCaret, SetCaretUpdate, HandleJavaCaretUpdate);
758 
759     INSTALL_EVENT_LISTENER(trackMenuSelected, SetMenuSelected, HandleMenuSelected);
760     INSTALL_EVENT_LISTENER(trackMenuDeselected, SetMenuDeselected, HandleMenuDeselected);
761     INSTALL_EVENT_LISTENER(trackMenuCanceled, SetMenuCanceled, HandleMenuCanceled);
762 
763     INSTALL_EVENT_LISTENER( trackPopupVisible, SetPopupMenuWillBecomeVisible,
764                             HandlePopupMenuWillBecomeVisible );
765     INSTALL_EVENT_LISTENER( trackPopupInvisible, SetPopupMenuWillBecomeInvisible,
766                             HandlePopupMenuWillBecomeInvisible );
767     INSTALL_EVENT_LISTENER( trackPopupCanceled, SetPopupMenuCanceled,
768                             HandlePopupMenuCanceled );
769 
770     INSTALL_EVENT_LISTENER( trackPropertyNameChange, SetPropertyNameChange,
771                             HandlePropertyNameChange);
772     INSTALL_EVENT_LISTENER( trackPropertyDescriptionChange,
773                             SetPropertyDescriptionChange,
774                             HandlePropertyDescriptionChange );
775     INSTALL_EVENT_LISTENER( trackPropertyStateChange, SetPropertyStateChange,
776                             HandlePropertyStateChange );
777     INSTALL_EVENT_LISTENER( trackPropertyValueChange, SetPropertyValueChange,
778                             HandlePropertyValueChange );
779     INSTALL_EVENT_LISTENER( trackPropertySelectionChange,
780                             SetPropertySelectionChange,
781                             HandlePropertySelectionChange );
782     INSTALL_EVENT_LISTENER( trackPropertyTextChange, SetPropertyTextChange,
783                             HandlePropertyTextChange );
784     INSTALL_EVENT_LISTENER( trackPropertyCaretChange, SetPropertyCaretChange,
785                             HandlePropertyCaretChange );
786     INSTALL_EVENT_LISTENER( trackPropertyVisibleDataChange,
787                             SetPropertyVisibleDataChange,
788                             HandlePropertyVisibleDataChange );
789     INSTALL_EVENT_LISTENER( trackPropertyChildChange, SetPropertyChildChange,
790                             HandlePropertyChildChange );
791     INSTALL_EVENT_LISTENER( trackPropertyActiveDescendentChange,
792                             SetPropertyActiveDescendentChange,
793                             HandlePropertyActiveDescendentChange );
794     INSTALL_EVENT_LISTENER( trackPropertyTableModelChange,
795                             SetPropertyTableModelChange,
796                             HandlePropertyTableModelChange );
797 }
798 
799 
800 #define TRACK_EVENT_TOGGLE(menuItem, toggleVal, setFP, handler) \
801     case menuItem:                                              \
802         menu = GetMenu(hWnd);                                   \
803         if (toggleVal) {                                        \
804             toggleVal = FALSE;                                  \
805             CheckMenuItem(menu, menuItem,                       \
806                           MF_BYCOMMAND | MF_UNCHECKED);         \
807             setFP(NULL);                                        \
808         } else {                                                \
809             toggleVal = TRUE;                                   \
810             CheckMenuItem(menu, menuItem,                       \
811                           MF_BYCOMMAND | MF_CHECKED);           \
812             setFP(handler);                                     \
813         }                                                       \
814         MaybeCheckMonitorTheSameEventsAsJAWS(menu);             \
815         MaybeCheckMonitorAllEvents(menu);                       \
816         return TRUE
817 
jaccessinspectorDialogProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)818 INT_PTR CALLBACK jaccessinspectorDialogProc( HWND hWnd, UINT message,
819                                              WPARAM wParam, LPARAM lParam ) {
820     const int minWindowWidth = 540;
821     const int minWindowHeight = 300;
822     static int titleBarHeight = ::GetSystemMetrics(SM_CYSIZE);
823     static int menuBarHeight = ::GetSystemMetrics(SM_CYMENU);
824     static int borderHeight = ::GetSystemMetrics(SM_CYBORDER);
825     static int borderWidth = ::GetSystemMetrics(SM_CXBORDER);
826     static int verticalScrollBarWidth = ::GetSystemMetrics(SM_CXVSCROLL);
827     int command;
828     short width, height;
829     HWND dlgItem;
830     RECT dlgItemRect;
831     RECT dialogBoxRect;
832     LONG lT;
833     HMENU menu;
834     DWORD lastError = 0;
835 
836     switch (message) {
837 
838     case WM_CREATE:
839         return 0;
840 
841     case WM_INITDIALOG:
842         CheckMenuItem(GetMenu(hWnd), cAccessBridgeDLLLoaded, MF_BYCOMMAND | MF_CHECKED);
843         return TRUE;
844 
845     case WM_CLOSE:
846         exitjaccessinspector(hWnd);
847         return TRUE;
848 
849     case WM_SIZE:
850         width = LOWORD(lParam);
851         height = HIWORD(lParam);
852         dlgItem = GetDlgItem(theDialogWindow, cjaccessinspectorText);
853         ::GetWindowRect(dlgItem, &dlgItemRect);
854         ::GetWindowRect(theDialogWindow, &dialogBoxRect);
855         lT = dlgItemRect.top - dialogBoxRect.top - titleBarHeight -
856              menuBarHeight + (borderHeight * 4);
857         SetWindowPos( dlgItem, NULL, 0, 0,
858                       width - (borderWidth * 2) - verticalScrollBarWidth,
859                       height - lT, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
860         return FALSE;  // let windows finish handling this
861 
862     case WM_GETMINMAXINFO:
863         {
864             LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam;
865             lpMMI->ptMinTrackSize.x = minWindowWidth;
866             lpMMI->ptMinTrackSize.y = minWindowHeight;
867             return TRUE;
868         }
869         break;
870 
871     case WM_COMMAND:
872         command = LOWORD(wParam);
873 
874         switch(command) {
875         case cAccessBridgeDLLLoaded:    // toggle; unload or load AccessBridge
876             if (theAccessBridgeLoadedFlag) {
877                 shutdownAccessBridge();
878                 theAccessBridgeLoadedFlag = FALSE;
879                 CheckMenuItem( GetMenu(hWnd), cAccessBridgeDLLLoaded,
880                                MF_BYCOMMAND | MF_UNCHECKED );
881             } else {
882                 theAccessBridgeLoadedFlag = initializeAccessBridge();
883                 if (theAccessBridgeLoadedFlag) {
884                     CheckMenuItem( GetMenu(hWnd), cAccessBridgeDLLLoaded,
885                                    MF_BYCOMMAND | MF_CHECKED );
886                     reinstallEventListeners();
887                 }
888             }
889             return TRUE;
890 
891         case cExitMenuItem:
892             exitjaccessinspector(hWnd);
893             return TRUE;
894 
895         TRACK_EVENT_TOGGLE( cTrackMouseMenuItem, trackMouse, SetMouseEntered,
896                             HandleMouseEntered );
897         TRACK_EVENT_TOGGLE( cTrackMouseExitedMenuItem, trackMouseExited,
898                             SetMouseExited, HandleMouseExited );
899         TRACK_EVENT_TOGGLE( cTrackMouseClickedMenuItem, trackMouseClicked,
900                             SetMouseClicked, HandleMouseClicked );
901         TRACK_EVENT_TOGGLE( cTrackMousePressedMenuItem, trackMousePressed,
902                             SetMousePressed, HandleMousePressed );
903         TRACK_EVENT_TOGGLE( cTrackMouseReleasedMenuItem, trackMouseReleased,
904                             SetMouseReleased, HandleMouseReleased );
905         TRACK_EVENT_TOGGLE( cTrackShutdownMenuItem, trackShutdown,
906                             SetJavaShutdown, HandleJavaShutdown );
907         TRACK_EVENT_TOGGLE( cTrackFocusMenuItem, trackFocus, SetFocusGained,
908                             HandleJavaFocusGained );
909         TRACK_EVENT_TOGGLE( cTrackFocusLostMenuItem, trackFocusLost,
910                             SetFocusLost, HandleJavaFocusLost );
911         TRACK_EVENT_TOGGLE( cTrackCaretMenuItem, trackCaret, SetCaretUpdate,
912                             HandleJavaCaretUpdate );
913 
914         TRACK_EVENT_TOGGLE( cTrackMenuSelectedMenuItem, trackMenuSelected,
915                             SetMenuSelected, HandleMenuSelected );
916         TRACK_EVENT_TOGGLE( cTrackMenuDeselectedMenuItem, trackMenuDeselected,
917                             SetMenuDeselected, HandleMenuDeselected );
918         TRACK_EVENT_TOGGLE( cTrackMenuCanceledItem, trackMenuCanceled,
919                             SetMenuCanceled, HandleMenuCanceled );
920 
921         TRACK_EVENT_TOGGLE( cTrackPopupBecomeVisibleMenuItem, trackPopupVisible,
922                             SetPopupMenuWillBecomeVisible,
923                             HandlePopupMenuWillBecomeVisible );
924         TRACK_EVENT_TOGGLE( cTrackPopupBecomeInvisibleMenuItem,
925                             trackPopupInvisible,
926                             SetPopupMenuWillBecomeInvisible,
927                             HandlePopupMenuWillBecomeInvisible );
928         TRACK_EVENT_TOGGLE( cTrackPopupCanceledItem, trackPopupCanceled,
929                             SetPopupMenuCanceled, HandlePopupMenuCanceled );
930 
931         TRACK_EVENT_TOGGLE( cTrackPropertyNameItem, trackPropertyNameChange,
932                             SetPropertyNameChange, HandlePropertyNameChange );
933         TRACK_EVENT_TOGGLE( cTrackPropertyDescriptionItem,
934                             trackPropertyDescriptionChange,
935                             SetPropertyDescriptionChange,
936                             HandlePropertyDescriptionChange );
937         TRACK_EVENT_TOGGLE( cTrackPropertyStateItem, trackPropertyStateChange,
938                             SetPropertyStateChange, HandlePropertyStateChange );
939         TRACK_EVENT_TOGGLE( cTrackPropertyValueItem, trackPropertyValueChange,
940                             SetPropertyValueChange, HandlePropertyValueChange );
941         TRACK_EVENT_TOGGLE( cTrackPropertySelectionItem,
942                             trackPropertySelectionChange,
943                             SetPropertySelectionChange,
944                             HandlePropertySelectionChange );
945         TRACK_EVENT_TOGGLE( cTrackPropertyTextItem, trackPropertyTextChange,
946                             SetPropertyTextChange, HandlePropertyTextChange );
947         TRACK_EVENT_TOGGLE( cTrackPropertyCaretItem, trackPropertyCaretChange,
948                             SetPropertyCaretChange, HandlePropertyCaretChange );
949         TRACK_EVENT_TOGGLE( cTrackPropertyVisibleDataItem,
950                             trackPropertyVisibleDataChange,
951                             SetPropertyVisibleDataChange,
952                             HandlePropertyVisibleDataChange );
953         TRACK_EVENT_TOGGLE( cTrackPropertyChildItem, trackPropertyChildChange,
954                             SetPropertyChildChange, HandlePropertyChildChange );
955         TRACK_EVENT_TOGGLE( cTrackPropertyActiveDescendentItem,
956                             trackPropertyActiveDescendentChange,
957                             SetPropertyActiveDescendentChange,
958                             HandlePropertyActiveDescendentChange );
959         TRACK_EVENT_TOGGLE( cTrackPropertyTableModelChangeItem,
960                             trackPropertyTableModelChange,
961                             SetPropertyTableModelChange,
962                             HandlePropertyTableModelChange );
963 
964         case cUpdateFromMouseMenuItem:
965             menu = GetMenu(hWnd);
966             if (updateMouse) {
967                 updateMouse = FALSE;
968                 CheckMenuItem( menu, cUpdateFromMouseMenuItem,
969                                MF_BYCOMMAND | MF_UNCHECKED );
970                 UnhookWindowsHookEx((HHOOK)MouseProc);
971                 KillTimer(hWnd, TIMER_ID);
972             } else {
973                 updateMouse = TRUE;
974                 CheckMenuItem( menu, cUpdateFromMouseMenuItem,
975                                MF_BYCOMMAND | MF_CHECKED );
976                 prevMouseHook = SetWindowsHookEx( WH_MOUSE, MouseProc,
977                                                   theInstance,
978                                                   ::GetCurrentThreadId() );
979                 if (! prevMouseHook) {
980                     lastError = ::GetLastError();
981                 }
982             }
983             return TRUE;
984 
985         case cUpdateWithF1Item:
986             menu = GetMenu(hWnd);
987             if (updateF1) {
988                 updateF1 = FALSE;
989                 CheckMenuItem( menu, cUpdateWithF1Item,
990                                MF_BYCOMMAND | MFS_UNCHECKED );
991                 UnhookWindowsHookEx((HHOOK)KeyboardProc);
992             } else {
993                 updateF1 = TRUE;
994                 CheckMenuItem( menu, cUpdateWithF1Item,
995                                MF_BYCOMMAND | MFS_CHECKED );
996                 prevKbdHook = SetWindowsHookEx( WH_KEYBOARD, KeyboardProc,
997                                                 theInstance,
998                                                 ::GetCurrentThreadId() );
999                 if (! prevKbdHook) {
1000                     lastError = ::GetLastError();
1001                 }
1002             }
1003             return TRUE;
1004 
1005         case cUpdateWithF2Item:
1006             menu = GetMenu(hWnd);
1007             if (updateF2) {
1008                 updateF2 = FALSE;
1009                 CheckMenuItem( menu, cUpdateWithF2Item,
1010                                MF_BYCOMMAND | MFS_UNCHECKED );
1011                 UnhookWindowsHookEx((HHOOK)KeyboardProc);
1012             } else {
1013                 updateF2 = TRUE;
1014                 CheckMenuItem(menu, cUpdateWithF2Item,
1015                               MF_BYCOMMAND | MFS_CHECKED);
1016                 prevKbdHook = SetWindowsHookEx( WH_KEYBOARD, KeyboardProc,
1017                                                 theInstance, ::GetCurrentThreadId() );
1018                 if (! prevKbdHook) {
1019                     lastError = ::GetLastError();
1020                 }
1021             }
1022             return TRUE;
1023 
1024         case cMonitorTheSameEventsAsJAWS:
1025             /*
1026             Causes jaccessinspetor to monitor the same events as JAWS.  Useful
1027             when testing to determine if a bug is specific to JAWS or if it can
1028             be reproduced in jaccessinspector as well.
1029             */
1030             trackMouse = FALSE;
1031             trackMouseExited = FALSE;
1032             trackMouseClicked = FALSE;
1033             trackMousePressed = FALSE;
1034             trackMouseReleased = FALSE;
1035             trackFocus = TRUE;
1036             trackFocusLost = TRUE;
1037             trackCaret = FALSE;
1038             trackShutdown = FALSE;
1039 
1040             trackMenuSelected = FALSE;
1041             trackMenuDeselected = FALSE;
1042             trackMenuCanceled = FALSE;
1043 
1044             trackPopupVisible = FALSE;
1045             trackPopupInvisible = FALSE;
1046             trackPopupCanceled = FALSE;
1047 
1048             trackPropertyNameChange = TRUE;
1049             trackPropertyDescriptionChange = TRUE;
1050             trackPropertyStateChange = TRUE;
1051             trackPropertyValueChange = TRUE;
1052             trackPropertySelectionChange = TRUE;
1053             trackPropertyTextChange = TRUE;
1054             trackPropertyCaretChange = TRUE;
1055             trackPropertyVisibleDataChange = FALSE;
1056             trackPropertyChildChange = TRUE;
1057             trackPropertyActiveDescendentChange = TRUE;
1058             trackPropertyTableModelChange = FALSE;
1059 
1060             ApplyEventOptions(hWnd);
1061 
1062             return TRUE;
1063 
1064         case cMonitorAllEvents:
1065             /*
1066             Causes jaccessinspector to monitor all Java Events and all
1067             Accessibility Events.
1068             */
1069             trackMouse = TRUE;
1070             trackMouseExited = TRUE;
1071             trackMouseClicked = TRUE;
1072             trackMousePressed = TRUE;
1073             trackMouseReleased = TRUE;
1074             trackFocus = TRUE;
1075             trackFocusLost = TRUE;
1076             trackCaret = TRUE;
1077             trackShutdown = TRUE;
1078 
1079             trackMenuSelected = TRUE;
1080             trackMenuDeselected = TRUE;
1081             trackMenuCanceled = TRUE;
1082 
1083             trackPopupVisible = TRUE;
1084             trackPopupInvisible = TRUE;
1085             trackPopupCanceled = TRUE;
1086 
1087             trackPropertyNameChange = TRUE;
1088             trackPropertyDescriptionChange = TRUE;
1089             trackPropertyStateChange = TRUE;
1090             trackPropertyValueChange = TRUE;
1091             trackPropertySelectionChange = TRUE;
1092             trackPropertyTextChange = TRUE;
1093             trackPropertyCaretChange = TRUE;
1094             trackPropertyVisibleDataChange = TRUE;
1095             trackPropertyChildChange = TRUE;
1096             trackPropertyActiveDescendentChange = TRUE;
1097             trackPropertyTableModelChange = TRUE;
1098 
1099             ApplyEventOptions(hWnd);
1100 
1101             return TRUE;
1102 
1103         case cFirstMessage:
1104             {
1105                 const char * messageText = g_MessageHistory.GetFirstMessage ();
1106                 if ( ( NULL != messageText ) && ( 0 != messageText [0] ) ) {
1107                     ::SetDlgItemText( theDialogWindow, cjaccessinspectorText,
1108                                       messageText );
1109                 }
1110                 EnableMessageNavButtons();
1111                 UpdateMessageNumber();
1112                 return TRUE;
1113             }
1114             break;
1115 
1116         case cPreviousMessage:
1117             {
1118                 const char * messageText = g_MessageHistory.GetPreviousMessage ();
1119                 if ( ( NULL != messageText ) && ( 0 != messageText [0] ) ) {
1120                     ::SetDlgItemText( theDialogWindow, cjaccessinspectorText,
1121                                       messageText );
1122                 }
1123                 EnableMessageNavButtons();
1124                 UpdateMessageNumber();
1125                 return TRUE;
1126             }
1127             break;
1128 
1129         case cNextMessage:
1130             {
1131                 const char * messageText = g_MessageHistory.GetNextMessage ();
1132                 if ( ( NULL != messageText ) && ( 0 != messageText [0] ) ) {
1133                     ::SetDlgItemText( theDialogWindow, cjaccessinspectorText,
1134                                       messageText );
1135                 }
1136                 EnableMessageNavButtons();
1137                 UpdateMessageNumber();
1138                 return TRUE;
1139             }
1140             break;
1141 
1142         case cLastMessage:
1143             {
1144                 const char * messageText = g_MessageHistory.GetLastMessage();
1145                 if ( ( NULL != messageText ) && ( 0 != messageText [0] ) ) {
1146                     ::SetDlgItemText( theDialogWindow, cjaccessinspectorText,
1147                                       messageText );
1148                 }
1149                 EnableMessageNavButtons();
1150                 UpdateMessageNumber();
1151                 return TRUE;
1152             }
1153             break;
1154 
1155         case cResetAllEvents:
1156             trackMouse = FALSE;
1157             trackMouseExited = FALSE;
1158             trackMouseClicked = FALSE;
1159             trackMousePressed = FALSE;
1160             trackMouseReleased = FALSE;
1161             trackFocus = FALSE;
1162             trackFocusLost = FALSE;
1163             trackCaret = FALSE;
1164             trackShutdown = FALSE;
1165 
1166             trackMenuSelected = FALSE;
1167             trackMenuDeselected = FALSE;
1168             trackMenuCanceled = FALSE;
1169 
1170             trackPopupVisible = FALSE;
1171             trackPopupInvisible = FALSE;
1172             trackPopupCanceled = FALSE;
1173 
1174             trackPropertyNameChange = FALSE;
1175             trackPropertyDescriptionChange = FALSE;
1176             trackPropertyStateChange = FALSE;
1177             trackPropertyValueChange = FALSE;
1178             trackPropertySelectionChange = FALSE;
1179             trackPropertyTextChange = FALSE;
1180             trackPropertyCaretChange = FALSE;
1181             trackPropertyVisibleDataChange = FALSE;
1182             trackPropertyChildChange = FALSE;
1183             trackPropertyActiveDescendentChange = FALSE;
1184             trackPropertyTableModelChange = FALSE;
1185 
1186             ApplyEventOptions(hWnd);
1187 
1188             return TRUE;
1189 
1190         case cGoToMessage:
1191             InitGoToMessageDialogBox(theInstance);
1192             break;
1193 
1194         case cClearMessageHistory:
1195             g_MessageHistory.clear();
1196             ::SetDlgItemText(theDialogWindow, cjaccessinspectorText, NULL);
1197             EnableMessageNavButtons();
1198             UpdateMessageNumber();
1199             break;
1200         }
1201         break;
1202 
1203     case DISPLAY_INFO_MESSAGE:
1204         echoMouseObject();
1205         return TRUE;
1206 
1207     case DISPLAY_HWND_INFO_MESSAGE:
1208         echoMouseHWNDObject();
1209         return TRUE;
1210     }
1211 
1212     return FALSE;
1213 }
1214 
1215 #define SaveOptionToRegistry(optionVar) { \
1216     SetValue = RegSetValueEx( hKey, #optionVar, 0, REG_DWORD, \
1217                               (LPBYTE)(&optionVar), sizeof(DWORD)); \
1218     if ( ERROR_SUCCESS != SetValue ) { \
1219         ++ failureCount; \
1220     } \
1221 }
1222 
SaveActiveEventOptionsToRegistry()1223 BOOL SaveActiveEventOptionsToRegistry() {
1224     LONG CreateKey = ERROR_SUCCESS;
1225     HKEY hKey = NULL;
1226     DWORD Disposition = 0;
1227 
1228     CreateKey = ::RegCreateKeyEx( HKEY_CURRENT_USER,
1229                                   jaccessinspectorOptionsRegistryKey, 0, 0, 0,
1230                                   KEY_READ|KEY_WRITE, 0, &hKey, &Disposition );
1231     if ( ( ERROR_SUCCESS != CreateKey ) || ( NULL == hKey ) ) {
1232         return FALSE;
1233     }
1234 
1235     LONG SetValue = ERROR_SUCCESS;
1236     unsigned long failureCount = 0;
1237 
1238     SaveOptionToRegistry(trackMouse);
1239     SaveOptionToRegistry(trackMouseExited);
1240     SaveOptionToRegistry(trackMouseClicked);
1241     SaveOptionToRegistry(trackMousePressed);
1242     SaveOptionToRegistry(trackMouseReleased);
1243     SaveOptionToRegistry(trackShutdown);
1244     SaveOptionToRegistry(trackFocus);
1245     SaveOptionToRegistry(trackFocusLost);
1246     SaveOptionToRegistry(trackCaret);
1247     SaveOptionToRegistry(trackMenuSelected);
1248     SaveOptionToRegistry(trackMenuDeselected);
1249     SaveOptionToRegistry(trackMenuCanceled);
1250     SaveOptionToRegistry(trackPopupVisible);
1251     SaveOptionToRegistry(trackPopupInvisible);
1252     SaveOptionToRegistry(trackPopupCanceled);
1253     SaveOptionToRegistry(trackPropertyNameChange);
1254     SaveOptionToRegistry(trackPropertyDescriptionChange);
1255     SaveOptionToRegistry(trackPropertyStateChange);
1256     SaveOptionToRegistry(trackPropertyValueChange);
1257     SaveOptionToRegistry(trackPropertySelectionChange);
1258     SaveOptionToRegistry(trackPropertyTextChange);
1259     SaveOptionToRegistry(trackPropertyCaretChange);
1260     SaveOptionToRegistry(trackPropertyVisibleDataChange);
1261     SaveOptionToRegistry(trackPropertyChildChange);
1262     SaveOptionToRegistry(trackPropertyActiveDescendentChange);
1263     SaveOptionToRegistry(trackPropertyTableModelChange);
1264 
1265     ::RegFlushKey(hKey);
1266     ::RegCloseKey(hKey);
1267 
1268     if ( 0 == failureCount ) {
1269         return TRUE;
1270     }
1271     return FALSE;
1272 }
1273 
1274 #define ReadOptionFromRegistry(optionVar) { \
1275     Type = Value = 0; \
1276     ValueSize = sizeof(DWORD); \
1277     QueryValue = ::RegQueryValueEx( hKey, #optionVar, NULL, &Type, \
1278                                    (LPBYTE)(&Value), &ValueSize); \
1279     if ( ( ERROR_SUCCESS == QueryValue ) && ( REG_DWORD == Type ) ) { \
1280         optionVar = static_cast<BOOL>(Value); \
1281     } else { \
1282         ++ failureCount; \
1283     } \
1284 }
1285 
ReadActiveEventOptionsFromRegistry()1286 BOOL ReadActiveEventOptionsFromRegistry() {
1287 
1288     trackMouse = FALSE;
1289     trackMouseExited = FALSE;
1290     trackMouseClicked = FALSE;
1291     trackMousePressed = FALSE;
1292     trackMouseReleased = FALSE;
1293 
1294     trackShutdown = FALSE;
1295     trackFocus = FALSE;
1296     trackFocusLost = FALSE;
1297     trackCaret = FALSE;
1298     trackMenuSelected = FALSE;
1299     trackMenuDeselected = FALSE;
1300     trackMenuCanceled = FALSE;
1301     trackPopupVisible = FALSE;
1302     trackPopupInvisible = FALSE;
1303     trackPopupCanceled = FALSE;
1304 
1305     trackPropertyNameChange = FALSE;
1306     trackPropertyDescriptionChange = FALSE;
1307     trackPropertyStateChange = FALSE;
1308     trackPropertyValueChange = FALSE;
1309     trackPropertySelectionChange = FALSE;
1310     trackPropertyTextChange = FALSE;
1311     trackPropertyCaretChange = FALSE;
1312     trackPropertyVisibleDataChange = FALSE;
1313     trackPropertyChildChange = FALSE;
1314     trackPropertyActiveDescendentChange = FALSE;
1315     trackPropertyTableModelChange = FALSE;
1316 
1317     LONG OpenKey = ERROR_SUCCESS;
1318     HKEY hKey = NULL;
1319     OpenKey = ::RegOpenKeyEx( HKEY_CURRENT_USER,
1320                               jaccessinspectorOptionsRegistryKey, 0,
1321                               KEY_READ, &hKey );
1322     if ( ( ERROR_SUCCESS != OpenKey ) || ( NULL == hKey ) ) {
1323         return FALSE;
1324     }
1325 
1326     LONG QueryValue = ERROR_SUCCESS;
1327     unsigned long failureCount = 0;
1328     DWORD Type, Value, ValueSize;
1329 
1330     ReadOptionFromRegistry(trackMouse);
1331     ReadOptionFromRegistry(trackMouseExited);
1332     ReadOptionFromRegistry(trackMouseClicked);
1333     ReadOptionFromRegistry(trackMousePressed);
1334     ReadOptionFromRegistry(trackMouseReleased);
1335     ReadOptionFromRegistry(trackShutdown);
1336     ReadOptionFromRegistry(trackFocus);
1337     ReadOptionFromRegistry(trackFocusLost);
1338     ReadOptionFromRegistry(trackCaret);
1339     ReadOptionFromRegistry(trackMenuSelected);
1340     ReadOptionFromRegistry(trackMenuDeselected);
1341     ReadOptionFromRegistry(trackMenuCanceled);
1342     ReadOptionFromRegistry(trackPopupVisible);
1343     ReadOptionFromRegistry(trackPopupInvisible);
1344     ReadOptionFromRegistry(trackPopupCanceled);
1345     ReadOptionFromRegistry(trackPropertyNameChange);
1346     ReadOptionFromRegistry(trackPropertyDescriptionChange);
1347     ReadOptionFromRegistry(trackPropertyStateChange);
1348     ReadOptionFromRegistry(trackPropertyValueChange);
1349     ReadOptionFromRegistry(trackPropertySelectionChange);
1350     ReadOptionFromRegistry(trackPropertyTextChange);
1351     ReadOptionFromRegistry(trackPropertyCaretChange);
1352     ReadOptionFromRegistry(trackPropertyVisibleDataChange);
1353     ReadOptionFromRegistry(trackPropertyChildChange);
1354     ReadOptionFromRegistry(trackPropertyActiveDescendentChange);
1355     ReadOptionFromRegistry(trackPropertyTableModelChange);
1356 
1357     ::RegCloseKey(hKey);
1358 
1359     if ( 0 == failureCount ) {
1360         return TRUE;
1361     }
1362     return FALSE;
1363 }
1364 
1365 #define APPLY_EVENT_OPTION(menuItem, optionVar, setFP, handler) \
1366 { \
1367     if ( optionVar ) { \
1368         ::CheckMenuItem(menu, menuItem, MF_BYCOMMAND | MF_CHECKED); \
1369         setFP (handler); \
1370     } else { \
1371         ::CheckMenuItem(menu, menuItem, MF_BYCOMMAND | MF_UNCHECKED); \
1372         setFP (NULL); \
1373     } \
1374 }
1375 
ApplyEventOptions(HWND hWnd)1376 void ApplyEventOptions (HWND hWnd) {
1377 
1378     HMENU menu = ::GetMenu (hWnd);
1379     APPLY_EVENT_OPTION( cTrackMouseMenuItem, trackMouse, SetMouseEntered,
1380                         HandleMouseEntered );
1381     APPLY_EVENT_OPTION( cTrackMouseExitedMenuItem, trackMouseExited,
1382                         SetMouseExited, HandleMouseExited );
1383     APPLY_EVENT_OPTION( cTrackMouseClickedMenuItem, trackMouseClicked,
1384                         SetMouseClicked, HandleMouseClicked );
1385     APPLY_EVENT_OPTION( cTrackMousePressedMenuItem, trackMousePressed,
1386                         SetMousePressed, HandleMousePressed );
1387     APPLY_EVENT_OPTION( cTrackMouseReleasedMenuItem, trackMouseReleased,
1388                         SetMouseReleased, HandleMouseReleased );
1389 
1390     APPLY_EVENT_OPTION( cTrackShutdownMenuItem, trackShutdown, SetJavaShutdown,
1391                         HandleJavaShutdown );
1392     APPLY_EVENT_OPTION( cTrackFocusMenuItem, trackFocus, SetFocusGained,
1393                         HandleJavaFocusGained );
1394     APPLY_EVENT_OPTION( cTrackFocusLostMenuItem, trackFocusLost, SetFocusLost,
1395                         HandleJavaFocusLost );
1396     APPLY_EVENT_OPTION( cTrackCaretMenuItem, trackCaret, SetCaretUpdate,
1397                         HandleJavaCaretUpdate );
1398 
1399     APPLY_EVENT_OPTION( cTrackMenuSelectedMenuItem, trackMenuSelected,
1400                         SetMenuSelected, HandleMenuSelected );
1401     APPLY_EVENT_OPTION( cTrackMenuDeselectedMenuItem, trackMenuDeselected,
1402                         SetMenuDeselected, HandleMenuDeselected );
1403     APPLY_EVENT_OPTION( cTrackMenuCanceledItem, trackMenuCanceled,
1404                         SetMenuCanceled, HandleMenuCanceled );
1405 
1406     APPLY_EVENT_OPTION( cTrackPopupBecomeVisibleMenuItem, trackPopupVisible,
1407                         SetPopupMenuWillBecomeVisible,
1408                         HandlePopupMenuWillBecomeVisible );
1409     APPLY_EVENT_OPTION( cTrackPopupBecomeInvisibleMenuItem, trackPopupInvisible,
1410                         SetPopupMenuWillBecomeInvisible,
1411                         HandlePopupMenuWillBecomeInvisible );
1412     APPLY_EVENT_OPTION( cTrackPopupCanceledItem, trackPopupCanceled,
1413                         SetPopupMenuCanceled, HandlePopupMenuCanceled );
1414 
1415     APPLY_EVENT_OPTION( cTrackPropertyNameItem, trackPropertyNameChange,
1416                         SetPropertyNameChange, HandlePropertyNameChange );
1417     APPLY_EVENT_OPTION( cTrackPropertyDescriptionItem,
1418                         trackPropertyDescriptionChange,
1419                         SetPropertyDescriptionChange,
1420                         HandlePropertyDescriptionChange );
1421     APPLY_EVENT_OPTION( cTrackPropertyStateItem, trackPropertyStateChange,
1422                         SetPropertyStateChange, HandlePropertyStateChange );
1423     APPLY_EVENT_OPTION( cTrackPropertyValueItem, trackPropertyValueChange,
1424                         SetPropertyValueChange, HandlePropertyValueChange );
1425     APPLY_EVENT_OPTION( cTrackPropertySelectionItem,
1426                         trackPropertySelectionChange,
1427                         SetPropertySelectionChange,
1428                         HandlePropertySelectionChange);
1429     APPLY_EVENT_OPTION( cTrackPropertyTextItem, trackPropertyTextChange,
1430                         SetPropertyTextChange, HandlePropertyTextChange );
1431     APPLY_EVENT_OPTION( cTrackPropertyCaretItem, trackPropertyCaretChange,
1432                         SetPropertyCaretChange, HandlePropertyCaretChange );
1433     APPLY_EVENT_OPTION( cTrackPropertyVisibleDataItem,
1434                         trackPropertyVisibleDataChange,
1435                         SetPropertyVisibleDataChange,
1436                         HandlePropertyVisibleDataChange );
1437     APPLY_EVENT_OPTION( cTrackPropertyChildItem, trackPropertyChildChange,
1438                         SetPropertyChildChange, HandlePropertyChildChange );
1439     APPLY_EVENT_OPTION( cTrackPropertyActiveDescendentItem,
1440                         trackPropertyActiveDescendentChange,
1441                         SetPropertyActiveDescendentChange,
1442                         HandlePropertyActiveDescendentChange );
1443     APPLY_EVENT_OPTION( cTrackPropertyTableModelChangeItem,
1444                         trackPropertyTableModelChange,
1445                         SetPropertyTableModelChange,
1446                         HandlePropertyTableModelChange );
1447 
1448     MaybeCheckMonitorTheSameEventsAsJAWS(menu);
1449     MaybeCheckMonitorAllEvents(menu);
1450 }
1451 
EnableDlgItem(HWND hDlg,int nIDDlgItem,BOOL bEnable)1452 BOOL EnableDlgItem(HWND hDlg, int nIDDlgItem, BOOL bEnable) {
1453     HWND dlgItem = ::GetDlgItem(hDlg, nIDDlgItem);
1454     if ( NULL == dlgItem ) {
1455         return FALSE;
1456     }
1457     return ::EnableWindow (dlgItem, bEnable);
1458 }
1459 
EnableMessageNavButtons()1460 void EnableMessageNavButtons() {
1461     HWND FocusWindow = ::GetFocus();
1462     int FocusCtrlID = ::GetDlgCtrlID(FocusWindow);
1463     BOOL DisabledFocusWindow = FALSE;
1464     if ( 0 == g_MessageHistory.GetMessageCount () ) {
1465         EnableDlgItem(theDialogWindow, cFirstMessage, FALSE);
1466         EnableDlgItem(theDialogWindow, cPreviousMessage, FALSE);
1467         EnableDlgItem(theDialogWindow, cMessageNumber, FALSE);
1468         EnableDlgItem(theDialogWindow, cNextMessage, FALSE);
1469         EnableDlgItem(theDialogWindow, cLastMessage, FALSE);
1470     } else if ( g_MessageHistory.IsFirstMessage () ) {
1471         EnableDlgItem(theDialogWindow, cFirstMessage, FALSE);
1472         EnableDlgItem(theDialogWindow, cPreviousMessage, FALSE);
1473         EnableDlgItem(theDialogWindow, cMessageNumber, TRUE);
1474         EnableDlgItem(theDialogWindow, cNextMessage, TRUE);
1475         EnableDlgItem(theDialogWindow, cLastMessage, TRUE);
1476         if ( ( cFirstMessage == FocusCtrlID ) ||
1477              ( cPreviousMessage == FocusCtrlID ) ) {
1478             DisabledFocusWindow = TRUE;
1479         }
1480     } else if ( g_MessageHistory.IsLastMessage () ) {
1481         EnableDlgItem(theDialogWindow, cFirstMessage, TRUE);
1482         EnableDlgItem(theDialogWindow, cPreviousMessage, TRUE);
1483         EnableDlgItem(theDialogWindow, cMessageNumber, TRUE);
1484         EnableDlgItem(theDialogWindow, cNextMessage, FALSE);
1485         EnableDlgItem(theDialogWindow, cLastMessage, FALSE);
1486 
1487         if ( ( cNextMessage == FocusCtrlID ) ||
1488              ( cLastMessage == FocusCtrlID ) ) {
1489             DisabledFocusWindow = TRUE;
1490         }
1491     } else {
1492         EnableDlgItem(theDialogWindow, cFirstMessage, TRUE);
1493         EnableDlgItem(theDialogWindow, cPreviousMessage, TRUE);
1494         EnableDlgItem(theDialogWindow, cMessageNumber, TRUE);
1495         EnableDlgItem(theDialogWindow, cNextMessage, TRUE);
1496         EnableDlgItem(theDialogWindow, cLastMessage, TRUE);
1497     }
1498 
1499     if ( DisabledFocusWindow ) {
1500         /*
1501         We just disabled the window that had the focus.  Set focus to the
1502         cjaccessinspectorText window.  Otherwise it will no longer be possible
1503         to tab through the controls in jaccessinspector.
1504         */
1505         HWND jaccessinspectorText =
1506             ::GetDlgItem(theDialogWindow, cjaccessinspectorText);
1507         if ( jaccessinspectorText ) {
1508             ::SetFocus(jaccessinspectorText);
1509         }
1510     }
1511 }
1512 
AddToMessageHistory(const char * message)1513 void WINAPI AddToMessageHistory(const char * message) {
1514     g_MessageHistory.AddMessage(message);
1515     EnableMessageNavButtons();
1516     UpdateMessageNumber();
1517 }
1518 
UpdateMessageNumber()1519 BOOL UpdateMessageNumber () {
1520     HWND dlgItem = ::GetDlgItem(theDialogWindow, cMessageNumber);
1521     if ( NULL == dlgItem ) {
1522         return FALSE;
1523     }
1524 
1525     size_t messageCount = g_MessageHistory.GetMessageCount();
1526     size_t messageNumber = g_MessageHistory.GetCurrentMessageIndex() + 1;
1527     char text [32] = {0};
1528     if ( 0 != messageCount ) {
1529         ::_snprintf(text, sizeof(text), "%d of %d", (int)messageNumber,
1530                                                     (int) messageCount);
1531     }
1532     return ::SetWindowText(dlgItem, text);
1533 }
1534 
GoToMessageDialogProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)1535 INT_PTR CALLBACK GoToMessageDialogProc( HWND hDlg, UINT message, WPARAM wParam,
1536                                         LPARAM lParam ) {
1537     BOOL ret_val = FALSE;
1538     switch ( message ) {
1539     case WM_INITDIALOG:
1540         {
1541             /*
1542             This code to center the Go To Message dialog box in the
1543             jaccessinspector window was taken from
1544             <http://msdn.microsoft.com/en-us/library/ms644996(VS.85).aspx>.
1545             */
1546             HWND hwndOwner = NULL;
1547             RECT rcOwner = { 0, 0, 0, 0 };
1548             RECT rc = { 0, 0, 0, 0 };
1549             RECT rcDlg = { 0, 0, 0, 0 };
1550 
1551             // Get the owner window and dialog box rectangles.
1552             if ( NULL == (hwndOwner = GetParent(hDlg)) ) {
1553                 hwndOwner = GetDesktopWindow();
1554             }
1555 
1556             GetWindowRect(hwndOwner, &rcOwner);
1557             GetWindowRect(hDlg, &rcDlg);
1558             CopyRect(&rc, &rcOwner);
1559 
1560             // Offset the owner and dialog box rectangles so that right and
1561             // bottom values represent the width and height, and then offset
1562             // the owner again to discard space taken up by the dialog box.
1563             OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top);
1564             OffsetRect(&rc, -rc.left, -rc.top);
1565             OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom);
1566 
1567             // The new position is the sum of half the remaining space and the
1568             // owner's original position.
1569             SetWindowPos (hDlg,
1570                 HWND_TOP,
1571                 rcOwner.left + (rc.right / 2),
1572                 rcOwner.top + (rc.bottom / 2),
1573                 0, 0,  // Ignores size arguments.
1574                 SWP_NOSIZE);
1575         }
1576         break;
1577 
1578     case WM_COMMAND:
1579         switch ( LOWORD (wParam) ) {
1580         case IDOK:
1581             {
1582                 size_t GoToMessageNumber = 0;
1583                 BOOL Translated = FALSE;
1584                 GoToMessageNumber = GetDlgItemInt( hDlg, IDC_MESSAGE_NUMBER_EDIT,
1585                                                    &Translated, FALSE );
1586                 EndDialog (hDlg, IDOK);
1587                 theGoToDialogWindow = NULL;
1588 
1589                 if ( ( Translated ) && ( GoToMessageNumber > 0 ) ) {
1590                     const char * messageText = NULL;
1591                     if ( (GoToMessageNumber - 1) <
1592                          g_MessageHistory.GetMessageCount() ) {
1593                         messageText =
1594                             g_MessageHistory.GetMessage(GoToMessageNumber - 1);
1595                     } else if ( (GoToMessageNumber - 1) >=
1596                                 g_MessageHistory.GetMessageCount() ) {
1597                         messageText = g_MessageHistory.GetLastMessage();
1598                     }
1599                     if ( ( NULL != messageText ) && ( 0 != messageText [0] ) ) {
1600                         ::SetDlgItemText( theDialogWindow, cjaccessinspectorText,
1601                                           messageText );
1602                     }
1603                     EnableMessageNavButtons();
1604                     UpdateMessageNumber();
1605                 }
1606             }
1607             break;
1608         case IDCANCEL:
1609             EndDialog(hDlg, IDCANCEL);
1610             theGoToDialogWindow = NULL;
1611             break;
1612         }
1613         break;
1614     }
1615     return ret_val;
1616 }
1617 
InitGoToMessageDialogBox(HANDLE hInstance)1618 BOOL InitGoToMessageDialogBox (HANDLE hInstance) {
1619     theGoToDialogWindow = CreateDialog (
1620         (struct HINSTANCE__ *)hInstance, MAKEINTRESOURCE(IDD_GO_TO_MESSAGE),
1621         theDialogWindow, GoToMessageDialogProc);
1622 
1623     if ( NULL == theGoToDialogWindow ) {
1624         return FALSE;
1625     }
1626 
1627     ShowWindow (theGoToDialogWindow, SW_SHOW);
1628     return TRUE;
1629 }
1630 
ShouldCheckMonitorTheSameEventsAsJAWS()1631 BOOL ShouldCheckMonitorTheSameEventsAsJAWS () {
1632     if (
1633         ( FALSE == trackMouse )
1634         && ( FALSE == trackMouseExited )
1635         && ( FALSE == trackMouseClicked )
1636         && ( FALSE == trackMousePressed )
1637         && ( FALSE == trackMouseReleased )
1638         && ( TRUE == trackFocus )
1639         && ( TRUE == trackFocusLost )
1640         && ( FALSE == trackCaret )
1641         && ( FALSE == trackShutdown )
1642         && ( FALSE == trackMenuSelected )
1643         && ( FALSE == trackMenuDeselected )
1644         && ( FALSE == trackMenuCanceled )
1645         && ( FALSE == trackPopupVisible )
1646         && ( FALSE == trackPopupInvisible )
1647         && ( FALSE == trackPopupCanceled )
1648         && ( TRUE == trackPropertyNameChange )
1649         && ( TRUE == trackPropertyDescriptionChange )
1650         && ( TRUE == trackPropertyStateChange )
1651         && ( TRUE == trackPropertyValueChange )
1652         && ( TRUE == trackPropertySelectionChange )
1653         && ( TRUE == trackPropertyTextChange )
1654         && ( TRUE == trackPropertyCaretChange )
1655         && ( FALSE == trackPropertyVisibleDataChange )
1656         && ( TRUE == trackPropertyChildChange )
1657         && ( TRUE == trackPropertyActiveDescendentChange )
1658         && ( FALSE == trackPropertyTableModelChange )
1659         )
1660     {
1661         return TRUE;
1662     }
1663 
1664     return FALSE;
1665 }
1666 
MaybeCheckMonitorTheSameEventsAsJAWS(HMENU menu)1667 void MaybeCheckMonitorTheSameEventsAsJAWS(HMENU menu) {
1668     UINT uCheck = MF_BYCOMMAND | MF_UNCHECKED;
1669     if ( ShouldCheckMonitorTheSameEventsAsJAWS() ) {
1670         uCheck = MF_BYCOMMAND | MF_CHECKED;
1671     }
1672     ::CheckMenuItem(menu, cMonitorTheSameEventsAsJAWS, uCheck);
1673 }
1674 
ShouldCheckMonitorAllEvents()1675 BOOL ShouldCheckMonitorAllEvents() {
1676     if (
1677         ( TRUE == trackMouse )
1678         && ( TRUE == trackMouseExited )
1679         && ( TRUE == trackMouseClicked )
1680         && ( TRUE == trackMousePressed )
1681         && ( TRUE == trackMouseReleased )
1682         && ( TRUE == trackFocus )
1683         && ( TRUE == trackFocusLost )
1684         && ( TRUE == trackCaret )
1685         && ( TRUE == trackShutdown )
1686         && ( TRUE == trackMenuSelected )
1687         && ( TRUE == trackMenuDeselected )
1688         && ( TRUE == trackMenuCanceled )
1689         && ( TRUE == trackPopupVisible )
1690         && ( TRUE == trackPopupInvisible )
1691         && ( TRUE == trackPopupCanceled )
1692         && ( TRUE == trackPropertyNameChange )
1693         && ( TRUE == trackPropertyDescriptionChange )
1694         && ( TRUE == trackPropertyStateChange )
1695         && ( TRUE == trackPropertyValueChange )
1696         && ( TRUE == trackPropertySelectionChange )
1697         && ( TRUE == trackPropertyTextChange )
1698         && ( TRUE == trackPropertyCaretChange )
1699         && ( TRUE == trackPropertyVisibleDataChange )
1700         && ( TRUE == trackPropertyChildChange )
1701         && ( TRUE == trackPropertyActiveDescendentChange )
1702         && ( TRUE == trackPropertyTableModelChange )
1703         )
1704     {
1705         return TRUE;
1706     }
1707 
1708     return FALSE;
1709 }
1710 
MaybeCheckMonitorAllEvents(HMENU menu)1711 void MaybeCheckMonitorAllEvents(HMENU menu) {
1712     UINT uCheck = MF_BYCOMMAND | MF_UNCHECKED;
1713     if ( ShouldCheckMonitorAllEvents() ) {
1714         uCheck = MF_BYCOMMAND | MF_CHECKED;
1715     }
1716     ::CheckMenuItem(menu, cMonitorAllEvents, uCheck);
1717 }
1718