Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.cpp
40957 views
1
/*
2
* Copyright (c) 2005, 2016, 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
#include "jaccesswalker.h"
27
#include "AccessInfo.h"
28
29
HWND ourHwnd;
30
HWND topLevelWindow;
31
int depth = -1;
32
FILE *logfile;
33
HMENU popupMenu;
34
35
char theJaccesswalkerClassName[] = "JaccesswalkerWin";
36
char theAccessInfoClassName[] = "AccessInfoWin";
37
38
HWND theJaccesswalkerWindow;
39
HWND theTreeControlWindow;
40
HINSTANCE theInstance;
41
Jaccesswalker *theJaccesswalker;
42
AccessibleNode *theSelectedNode;
43
AccessibleNode *thePopupNode;
44
AccessibleContext theSelectedAccessibleContext;
45
HWND hwndTV; // handle of tree-view control
46
47
int APIENTRY WinMain(HINSTANCE hInstance,
48
HINSTANCE hPrevInstance,
49
LPSTR lpCmdLine,
50
int nCmdShow)
51
{
52
53
if (logfile == null) {
54
logfile = fopen(JACCESSWALKER_LOG, "w"); // overwrite existing log file
55
logString(logfile, "Starting jaccesswalker.exe %s\n", getTimeAndDate());
56
}
57
58
theInstance = hInstance;
59
60
// start Jaccesswalker
61
theJaccesswalker = new Jaccesswalker(nCmdShow);
62
63
return 0;
64
}
65
66
Jaccesswalker::Jaccesswalker(int nCmdShow) {
67
68
HWND hwnd;
69
static char szAppName[] = "jaccesswalker";
70
static char szMenuName[] = "JACCESSWALKERMENU";
71
MSG msg;
72
WNDCLASSEX wc;
73
74
// jaccesswalker window
75
wc.cbSize = sizeof(wc);
76
wc.style = CS_HREDRAW | CS_VREDRAW;
77
wc.lpfnWndProc = WinProc;
78
wc.cbClsExtra = 0;
79
wc.cbWndExtra = 0;
80
wc.hInstance = theInstance;
81
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
82
wc.hCursor = LoadCursor(NULL, IDI_APPLICATION);
83
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
84
wc.lpszMenuName = szMenuName;
85
wc.lpszClassName = szAppName;
86
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
87
88
RegisterClassEx(&wc);
89
90
// AccessInfo Window
91
wc.cbSize = sizeof(WNDCLASSEX);
92
93
wc.hInstance = theInstance;
94
wc.lpszClassName = theAccessInfoClassName;
95
wc.lpfnWndProc = (WNDPROC)AccessInfoWindowProc;
96
wc.style = 0;
97
98
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
99
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
100
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
101
102
wc.lpszMenuName = "";
103
wc.cbClsExtra = 0;
104
wc.cbWndExtra = 0;
105
106
wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
107
108
RegisterClassEx(&wc);
109
110
// create the jaccesswalker window
111
hwnd = CreateWindow(szAppName,
112
szAppName,
113
WS_OVERLAPPEDWINDOW,
114
CW_USEDEFAULT,
115
CW_USEDEFAULT,
116
CW_USEDEFAULT,
117
CW_USEDEFAULT,
118
NULL,
119
NULL,
120
theInstance,
121
NULL);
122
123
ourHwnd = hwnd;
124
125
/* Initialize the common controls. */
126
INITCOMMONCONTROLSEX cc;
127
cc.dwSize = sizeof(INITCOMMONCONTROLSEX);
128
cc.dwICC = ICC_TREEVIEW_CLASSES;
129
InitCommonControlsEx(&cc);
130
131
ShowWindow(hwnd, nCmdShow);
132
133
UpdateWindow(hwnd);
134
135
BOOL result = initializeAccessBridge();
136
if (result != FALSE) {
137
while (GetMessage(&msg, NULL, 0, 0)) {
138
TranslateMessage(&msg);
139
DispatchMessage(&msg);
140
}
141
shutdownAccessBridge();
142
}
143
}
144
145
/*
146
* the jaccesswalker window proc
147
*/
148
LRESULT CALLBACK WinProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {
149
150
int command;
151
short width, height;
152
153
switch(iMsg) {
154
155
case WM_CREATE:
156
// create the accessibility tree view
157
theTreeControlWindow = CreateATreeView(hwnd);
158
159
// load the popup menu
160
popupMenu = LoadMenu(theInstance, "PopupMenu");
161
popupMenu = GetSubMenu(popupMenu, 0);
162
break;
163
164
case WM_CLOSE:
165
EndDialog(hwnd, TRUE);
166
PostQuitMessage (0);
167
break;
168
169
case WM_SIZE:
170
width = LOWORD(lParam);
171
height = HIWORD(lParam);
172
SetWindowPos(theTreeControlWindow, NULL, 0, 0, width, height, 0);
173
return FALSE; // let windows finish handling this
174
175
case WM_COMMAND:
176
command = LOWORD(wParam);
177
switch(command) {
178
179
case cExitMenuItem:
180
EndDialog(hwnd, TRUE);
181
PostQuitMessage (0);
182
break;
183
184
case cRefreshTreeItem:
185
// update the accessibility tree
186
theJaccesswalker->buildAccessibilityTree();
187
break;
188
189
case cAPIMenuItem:
190
// open a new window with the Accessibility API in it for the
191
// selected element in the tree
192
if (theSelectedNode != (AccessibleNode *) 0) {
193
theSelectedNode->displayAPIWindow();
194
}
195
break;
196
197
case cAPIPopupItem:
198
// open a new window with the Accessibility API in it for the
199
// element in the tree adjacent to the popup menu
200
if (thePopupNode != (AccessibleNode *) 0) {
201
thePopupNode->displayAPIWindow();
202
}
203
break;
204
205
}
206
break;
207
208
case WM_NOTIFY: // receive tree messages
209
210
NMTREEVIEW *nmptr = (LPNMTREEVIEW) lParam;
211
switch (nmptr->hdr.code) {
212
213
case TVN_SELCHANGED:
214
// get the selected tree node
215
theSelectedNode = (AccessibleNode *) nmptr->itemNew.lParam;
216
break;
217
218
case NM_RCLICK:
219
220
// display a popup menu over the tree node
221
POINT p;
222
GetCursorPos(&p);
223
TrackPopupMenu(popupMenu, 0, p.x, p.y, 0, hwnd, NULL);
224
225
// get the tree node under the popup menu
226
TVHITTESTINFO hitinfo;
227
ScreenToClient(theTreeControlWindow, &p);
228
hitinfo.pt = p;
229
HTREEITEM node = TreeView_HitTest(theTreeControlWindow, &hitinfo);
230
231
if (node != null) {
232
TVITEMEX tvItem;
233
tvItem.hItem = node;
234
if (TreeView_GetItem(hwndTV, &tvItem) == TRUE) {
235
thePopupNode = (AccessibleNode *)tvItem.lParam;
236
}
237
}
238
break;
239
}
240
}
241
return DefWindowProc(hwnd, iMsg, wParam, lParam);
242
}
243
244
/*
245
* Accessibility information window proc
246
*/
247
LRESULT CALLBACK AccessInfoWindowProc(HWND hWnd, UINT message,
248
UINT wParam, LONG lParam) {
249
short width, height;
250
HWND dlgItem;
251
252
switch (message) {
253
case WM_CREATE:
254
RECT rcClient; // dimensions of client area
255
HWND hwndEdit; // handle of tree-view control
256
257
// Get the dimensions of the parent window's client area,
258
// and create the edit control.
259
GetClientRect(hWnd, &rcClient);
260
hwndEdit = CreateWindow("Edit",
261
"",
262
WS_VISIBLE | WS_TABSTOP | WS_CHILD |
263
ES_MULTILINE | ES_AUTOVSCROLL |
264
ES_READONLY | WS_VSCROLL,
265
0, 0, rcClient.right, rcClient.bottom,
266
hWnd,
267
(HMENU) cAccessInfoText,
268
theInstance,
269
NULL);
270
break;
271
272
case WM_CLOSE:
273
DestroyWindow(hWnd);
274
break;
275
276
case WM_SIZE:
277
width = LOWORD(lParam);
278
height = HIWORD(lParam);
279
dlgItem = GetDlgItem(hWnd, cAccessInfoText);
280
SetWindowPos(dlgItem, NULL, 0, 0, width, height, 0);
281
return FALSE; // let windows finish handling this
282
break;
283
284
default:
285
return DefWindowProc(hWnd, message, wParam, lParam);
286
}
287
288
return 0;
289
}
290
291
/**
292
* Build a tree (and the treeview control) of all accessible Java components
293
*
294
*/
295
void Jaccesswalker::buildAccessibilityTree() {
296
TreeView_DeleteAllItems (theTreeControlWindow);
297
// have MS-Windows call EnumWndProc() with all of the top-level windows
298
EnumWindows((WNDENUMPROC) EnumWndProc, NULL);
299
}
300
301
/**
302
* Create (and display) the accessible component nodes of a parent AccessibleContext
303
*
304
*/
305
BOOL CALLBACK EnumWndProc(HWND hwnd, LPARAM lParam) {
306
if (IsJavaWindow(hwnd)) {
307
long vmID;
308
AccessibleContext ac;
309
if (GetAccessibleContextFromHWND(hwnd, &vmID, &ac) == TRUE) {
310
theJaccesswalker->addComponentNodes(vmID, ac, (AccessibleNode *) NULL,
311
hwnd, TVI_ROOT, theTreeControlWindow);
312
}
313
topLevelWindow = hwnd;
314
} else {
315
char szClass [MAX_PATH] = {0};
316
::GetClassNameA(hwnd, szClass, sizeof(szClass) - 1);
317
if ( ( 0 == ::strcmp(szClass, "IEFrame") )
318
|| ( 0 == ::strcmp(szClass, "MozillaUIWindowClass") ) ) {
319
EnumChildWindows(hwnd, (WNDENUMPROC) EnumChildProc, NULL);
320
}
321
}
322
return TRUE;
323
}
324
325
/*
326
Detects whether or not the specified Java window is one from which no useable
327
information can be obtained.
328
329
This function tests for various scenarios I have seen in Java applets where the
330
Java applet had no meaningful accessible information. It does not detect all
331
scenarios, just the most common ones.
332
*/
333
BOOL IsInaccessibleJavaWindow(const HWND hwnd)
334
{
335
BOOL ret_val ( FALSE );
336
{
337
BOOL bT ( FALSE );
338
long vmIdWindow ( 0 );
339
AccessibleContext acWindow ( 0 );
340
bT = GetAccessibleContextFromHWND(hwnd, &vmIdWindow, &acWindow);
341
if ( ( bT ) && ( 0 != vmIdWindow ) && ( 0 != acWindow ) ) {
342
AccessibleContextInfo infoWindow = {0};
343
bT = GetAccessibleContextInfo(vmIdWindow, acWindow, &infoWindow);
344
if ( ( bT )
345
&& ( 0 == infoWindow.name [0] )
346
&& ( 0 == infoWindow.description [0] )
347
&& ( 0 == ::wcscmp(infoWindow.role_en_US, L"frame") ) ) {
348
if ( 0 == infoWindow.childrenCount ) {
349
ret_val = TRUE;
350
} else if ( 1 == infoWindow.childrenCount ) {
351
AccessibleContext acChild ( 0 );
352
acChild =
353
GetAccessibleChildFromContext(vmIdWindow, acWindow, 0);
354
if ( NULL != acChild ) {
355
AccessibleContextInfo infoChild = {0};
356
bT = GetAccessibleContextInfo( vmIdWindow, acChild,
357
&infoChild );
358
if ( ( bT )
359
&& ( 0 == infoChild.name [0] )
360
&& ( 0 == infoChild.description [0] )
361
&& ( 0 == ::wcscmp(infoChild.role_en_US, L"panel") )
362
&& ( 1 == infoChild.childrenCount ) ) {
363
AccessibleContext acChild1 ( 0 );
364
acChild1 = GetAccessibleChildFromContext( vmIdWindow,
365
acChild, 0);
366
if ( NULL != acChild1 ) {
367
AccessibleContextInfo infoChild1 = {0};
368
bT = GetAccessibleContextInfo( vmIdWindow,
369
acChild1, &infoChild1 );
370
if ( ( bT )
371
&& ( 0 == infoChild1.name [0] )
372
&& ( 0 == infoChild1.description [0] )
373
&& ( 0 == ::wcscmp(infoChild1.role_en_US, L"frame") )
374
&& ( 0 == infoChild1.childrenCount ) ) {
375
ret_val = TRUE;
376
} else if ( ( bT )
377
&& ( 0 == infoChild1.name [0] )
378
&& ( 0 == infoChild1.description [0] )
379
&& ( 0 == ::wcscmp( infoChild1.role_en_US,
380
L"panel") )
381
&& ( 1 == infoChild1.childrenCount ) ) {
382
AccessibleContext acChild2 ( 0 );
383
acChild2 = GetAccessibleChildFromContext(
384
vmIdWindow, acChild1, 0 );
385
if ( NULL != acChild2 ) {
386
AccessibleContextInfo infoChild2 = {0};
387
bT = GetAccessibleContextInfo(
388
vmIdWindow, acChild2, &infoChild2 );
389
if ( ( bT )
390
&& ( 0 == infoChild2.name [0] )
391
&& ( 0 == infoChild2.description [0] )
392
&& ( 0 == ::wcscmp( infoChild2.role_en_US,
393
L"frame") )
394
&& ( 0 == infoChild2.childrenCount ) ) {
395
ret_val = TRUE;
396
}
397
}
398
}
399
}
400
} else if ( ( bT )
401
&& ( 0 == infoChild.name [0] )
402
&& ( 0 == infoChild.description [0] )
403
&& ( 0 == ::wcscmp( infoChild.role_en_US,
404
L"canvas") )
405
&& ( 0 == infoChild.childrenCount ) ) {
406
ret_val = TRUE;
407
}
408
}
409
}
410
} else if ( ( bT )
411
&& ( 0 == infoWindow.name [0] )
412
&& ( 0 == infoWindow.description [0] )
413
&& ( 0 == ::wcscmp(infoWindow.role_en_US, L"panel") ) ) {
414
if ( 1 == infoWindow.childrenCount ) {
415
AccessibleContext acChild ( 0 );
416
acChild = GetAccessibleChildFromContext( vmIdWindow,
417
acWindow, 0 );
418
if ( NULL != acChild ) {
419
AccessibleContextInfo infoChild = {0};
420
bT = GetAccessibleContextInfo( vmIdWindow,
421
acChild, &infoChild );
422
if ( ( bT )
423
&& ( 0 == infoChild.name [0] )
424
&& ( 0 == infoChild.description [0] )
425
&& ( 0 == ::wcscmp(infoChild.role_en_US, L"frame") )
426
&& ( 0 == infoChild.childrenCount ) ) {
427
ret_val = TRUE;
428
} else if ( ( bT )
429
&& ( 0 == infoChild.name [0] )
430
&& ( 0 == infoChild.description [0] )
431
&& ( 0 == ::wcscmp( infoChild.role_en_US,
432
L"panel") )
433
&& ( 1 == infoChild.childrenCount ) ) {
434
AccessibleContext acChild1 ( 0 );
435
acChild1 = GetAccessibleChildFromContext( vmIdWindow,
436
acChild, 0);
437
if ( NULL != acChild1 ) {
438
AccessibleContextInfo infoChild1 = {0};
439
bT = GetAccessibleContextInfo( vmIdWindow,
440
acChild1,
441
&infoChild1 );
442
if ( ( bT )
443
&& ( 0 == infoChild1.name [0] )
444
&& ( 0 == infoChild1.description [0] )
445
&& ( 0 == ::wcscmp( infoChild1.role_en_US,
446
L"frame") )
447
&& ( 0 == infoChild1.childrenCount ) ) {
448
ret_val = TRUE;
449
}
450
}
451
}
452
}
453
}
454
}
455
} else if ( FALSE == bT ) {
456
ret_val = TRUE;
457
}
458
}
459
return ret_val;
460
}
461
462
BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam)
463
{
464
if ( ( IsJavaWindow(hwnd) )
465
&& ( FALSE == IsInaccessibleJavaWindow(hwnd) ) ) {
466
long vmID ( 0 );
467
AccessibleContext ac ( 0 );
468
if ( TRUE == GetAccessibleContextFromHWND(hwnd, &vmID, &ac) ) {
469
theJaccesswalker->addComponentNodes(
470
vmID, ac, (AccessibleNode *) NULL,
471
hwnd, TVI_ROOT, theTreeControlWindow);
472
}
473
topLevelWindow = hwnd;
474
} else {
475
EnumChildWindows(hwnd, (WNDENUMPROC) EnumChildProc, NULL);
476
}
477
return TRUE;
478
}
479
480
// CreateATreeView - creates a tree-view control.
481
// Returns the handle of the new control if successful or NULL
482
// otherwise.
483
// hwndParent - handle of the control's parent window
484
HWND CreateATreeView(HWND hwndParent) {
485
RECT rcClient; // dimensions of client area
486
487
// Get the dimensions of the parent window's client area, and create
488
// the tree-view control.
489
GetClientRect(hwndParent, &rcClient);
490
hwndTV = CreateWindow(WC_TREEVIEW,
491
"",
492
WS_VISIBLE | WS_TABSTOP | WS_CHILD |
493
TVS_HASLINES | TVS_HASBUTTONS |
494
TVS_LINESATROOT,
495
0, 0, rcClient.right, rcClient.bottom,
496
hwndParent,
497
(HMENU) cTreeControl,
498
theInstance,
499
NULL);
500
501
return hwndTV;
502
}
503
504
/**
505
* Create (and display) the accessible component nodes of a parent AccessibleContext
506
*
507
*/
508
void Jaccesswalker::addComponentNodes(long vmID, AccessibleContext context,
509
AccessibleNode *parent, HWND hwnd,
510
HTREEITEM treeNodeParent, HWND treeWnd) {
511
512
AccessibleNode *newNode = new AccessibleNode( vmID, context, parent, hwnd,
513
treeNodeParent );
514
515
AccessibleContextInfo info;
516
if (GetAccessibleContextInfo(vmID, context, &info) != FALSE) {
517
char s[LINE_BUFSIZE];
518
519
wsprintf(s, "%ls", info.name);
520
newNode->setAccessibleName(s);
521
wsprintf(s, "%ls", info.role);
522
newNode->setAccessibleRole(s);
523
524
wsprintf(s, "%ls [%ls]", info.name, info.role);
525
526
TVITEM tvi;
527
tvi.mask = TVIF_PARAM | TVIF_TEXT;
528
tvi.pszText = (char *) s; // Accessible name and role
529
tvi.cchTextMax = (int)strlen(s);
530
tvi.lParam = (LPARAM) newNode; // Accessibility information
531
532
TVINSERTSTRUCT tvis;
533
tvis.hParent = treeNodeParent;
534
tvis.hInsertAfter = TVI_LAST;
535
tvis.item = tvi;
536
537
HTREEITEM treeNodeItem = TreeView_InsertItem(treeWnd, &tvis);
538
539
for (int i = 0; i < info.childrenCount; i++) {
540
addComponentNodes(vmID, GetAccessibleChildFromContext(vmID, context, i),
541
newNode, hwnd, treeNodeItem, treeWnd);
542
}
543
} else {
544
char s[LINE_BUFSIZE];
545
sprintf( s,
546
"ERROR calling GetAccessibleContextInfo; vmID = %X, context = %p",
547
vmID, (void*)context );
548
549
TVITEM tvi;
550
tvi.mask = TVIF_PARAM | TVIF_TEXT; // text and lParam are only valid parts
551
tvi.pszText = (char *) s;
552
tvi.cchTextMax = (int)strlen(s);
553
tvi.lParam = (LPARAM) newNode;
554
555
TVINSERTSTRUCT tvis;
556
tvis.hParent = treeNodeParent;
557
tvis.hInsertAfter = TVI_LAST; // make tree in order given
558
tvis.item = tvi;
559
560
HTREEITEM treeNodeItem = TreeView_InsertItem(treeWnd, &tvis);
561
}
562
}
563
564
// -----------------------------
565
566
/**
567
* Create an AccessibleNode
568
*
569
*/
570
AccessibleNode::AccessibleNode(long JavaVMID, AccessibleContext context,
571
AccessibleNode *parent, HWND hwnd,
572
HTREEITEM parentTreeNodeItem) {
573
vmID = JavaVMID;
574
ac = context;
575
parentNode = parent;
576
baseHWND = hwnd;
577
treeNodeParent = parentTreeNodeItem;
578
579
// setting accessibleName and accessibleRole not done here,
580
// in order to minimize calls to the AccessBridge
581
// (since such a call is needed to enumerate children)
582
}
583
584
/**
585
* Destroy an AccessibleNode
586
*
587
*/
588
AccessibleNode::~AccessibleNode() {
589
ReleaseJavaObject(vmID, ac);
590
}
591
592
/**
593
* Set the accessibleName string
594
*
595
*/
596
void AccessibleNode::setAccessibleName(char *name) {
597
strncpy(accessibleName, name, MAX_STRING_SIZE);
598
}
599
600
/**
601
* Set the accessibleRole string
602
*
603
*/
604
void AccessibleNode::setAccessibleRole(char *role) {
605
strncpy(accessibleRole, role, SHORT_STRING_SIZE);
606
}
607
608
609
610
611
612
613
614
/**
615
* Create an API window to show off the info for this AccessibleContext
616
*/
617
BOOL AccessibleNode::displayAPIWindow() {
618
619
HWND apiWindow = CreateWindow(theAccessInfoClassName,
620
"Java Accessibility API view",
621
WS_OVERLAPPEDWINDOW,
622
CW_USEDEFAULT,
623
CW_USEDEFAULT,
624
600,
625
750,
626
HWND_DESKTOP,
627
NULL,
628
theInstance,
629
(void *) NULL);
630
631
if (!apiWindow) {
632
printError("cannot create API window");
633
return FALSE;
634
}
635
636
char buffer[HUGE_BUFSIZE];
637
buffer[0] = '\0';
638
getAccessibleInfo(vmID, ac, buffer, sizeof(buffer));
639
displayAndLog(apiWindow, cAccessInfoText, logfile, buffer);
640
641
ShowWindow(apiWindow, SW_SHOWNORMAL);
642
UpdateWindow(apiWindow);
643
644
return TRUE;
645
}
646
647
648
649
650