]> git.saurik.com Git - wxWidgets.git/blob - samples/access/accesstest.cpp
285edb016c18b67a8cca4cfe400018ee9f44bb35
[wxWidgets.git] / samples / access / accesstest.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: accesstest.cpp
3 // Purpose: wxWindows accessibility sample
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 2002-02-12
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx/wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 // for all others, include the necessary headers (this file is usually all you
28 // need because it includes almost all "standard" wxWindows headers)
29 #ifndef WX_PRECOMP
30 #include "wx/wx.h"
31 #endif
32
33 #include "wx/access.h"
34 #include "wx/splitter.h"
35
36 #ifdef __WXMSW__
37 #include "windows.h"
38 #include <ole2.h>
39 #include <oleauto.h>
40 #include <oleacc.h>
41 #include "wx/msw/ole/oleutils.h"
42 #include "wx/msw/winundef.h"
43
44 #ifndef OBJID_CLIENT
45 #define OBJID_CLIENT 0xFFFFFFFC
46 #endif
47
48 #endif
49
50 // ----------------------------------------------------------------------------
51 // resources
52 // ----------------------------------------------------------------------------
53
54 // the application icon (under Windows and OS/2 it is in resources)
55 #if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXMAC__) || defined(__WXMGL__) || defined(__WXX11__)
56 #include "mondrian.xpm"
57 #endif
58
59 // ----------------------------------------------------------------------------
60 // private classes
61 // ----------------------------------------------------------------------------
62
63 // Define a new application type, each program should derive a class from wxApp
64 class MyApp : public wxApp
65 {
66 public:
67 // override base class virtuals
68 // ----------------------------
69
70 // this one is called on application startup and is a good place for the app
71 // initialization (doing it here and not in the ctor allows to have an error
72 // return: if OnInit() returns false, the application terminates)
73 virtual bool OnInit();
74
75 };
76
77 // Define a new frame type: this is going to be our main frame
78 class MyFrame : public wxFrame
79 {
80 public:
81 // ctor(s)
82 MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size,
83 long style = wxDEFAULT_FRAME_STYLE);
84
85 // event handlers (these functions should _not_ be virtual)
86 void OnQuit(wxCommandEvent& event);
87 void OnQuery(wxCommandEvent& event);
88 void OnAbout(wxCommandEvent& event);
89
90 // Log messages to the text control
91 void Log(const wxString& text);
92
93 // Recursively give information about an object
94 void LogObject(int indent, IAccessible* obj);
95
96 // Get info for a child (id > 0) or object (id == 0)
97 void GetInfo(IAccessible* accessible, int id, wxString& name, wxString& role);
98 private:
99 wxTextCtrl* m_textCtrl;
100
101 // any class wishing to process wxWindows events must use this macro
102 DECLARE_EVENT_TABLE()
103 };
104
105 // ----------------------------------------------------------------------------
106 // constants
107 // ----------------------------------------------------------------------------
108
109 // IDs for the controls and the menu commands
110 enum
111 {
112 // menu items
113 AccessTest_Quit = 1,
114
115 // query the hierarchy
116 AccessTest_Query,
117
118 // it is important for the id corresponding to the "About" command to have
119 // this standard value as otherwise it won't be handled properly under Mac
120 // (where it is special and put into the "Apple" menu)
121 AccessTest_About = wxID_ABOUT
122 };
123
124 // ----------------------------------------------------------------------------
125 // event tables and other macros for wxWindows
126 // ----------------------------------------------------------------------------
127
128 // the event tables connect the wxWindows events with the functions (event
129 // handlers) which process them. It can be also done at run-time, but for the
130 // simple menu events like this the static method is much simpler.
131 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
132 EVT_MENU(AccessTest_Quit, MyFrame::OnQuit)
133 EVT_MENU(AccessTest_Query, MyFrame::OnQuery)
134 EVT_MENU(AccessTest_About, MyFrame::OnAbout)
135 END_EVENT_TABLE()
136
137 // Create a new application object: this macro will allow wxWindows to create
138 // the application object during program execution (it's better than using a
139 // static object for many reasons) and also declares the accessor function
140 // wxGetApp() which will return the reference of the right type (i.e. MyApp and
141 // not wxApp)
142 IMPLEMENT_APP(MyApp)
143
144 // ============================================================================
145 // implementation
146 // ============================================================================
147
148 // ----------------------------------------------------------------------------
149 // the application class
150 // ----------------------------------------------------------------------------
151
152 // 'Main program' equivalent: the program execution "starts" here
153 bool MyApp::OnInit()
154 {
155 // create the main application window
156 MyFrame *frame = new MyFrame(_T("AccessTest wxWindows App"),
157 wxPoint(50, 50), wxSize(450, 340));
158
159 // and show it (the frames, unlike simple controls, are not shown when
160 // created initially)
161 frame->Show(TRUE);
162
163 // success: wxApp::OnRun() will be called which will enter the main message
164 // loop and the application will run. If we returned FALSE here, the
165 // application would exit immediately.
166 return TRUE;
167 }
168
169 class FrameAccessible: public wxWindowAccessible
170 {
171 public:
172 FrameAccessible(wxWindow* win): wxWindowAccessible(win) {}
173
174 // Gets the name of the specified object.
175 virtual wxAccStatus GetName(int childId, wxString* name)
176 {
177 #if 1
178 if (childId == wxACC_SELF)
179 {
180 * name = wxT("Julian's Frame");
181 return wxACC_OK;
182 }
183 else
184 #endif
185 return wxACC_NOT_IMPLEMENTED;
186 }
187 };
188
189 class ScrolledWindowAccessible: public wxWindowAccessible
190 {
191 public:
192 ScrolledWindowAccessible(wxWindow* win): wxWindowAccessible(win) {}
193
194 // Gets the name of the specified object.
195 virtual wxAccStatus GetName(int childId, wxString* name)
196 {
197 if (childId == wxACC_SELF)
198 {
199 * name = wxT("My scrolled window");
200 return wxACC_OK;
201 }
202 else
203 return wxACC_NOT_IMPLEMENTED;
204 }
205 };
206
207 class SplitterWindowAccessible: public wxWindowAccessible
208 {
209 public:
210 SplitterWindowAccessible(wxWindow* win): wxWindowAccessible(win) {}
211
212 // Gets the name of the specified object.
213 virtual wxAccStatus GetName(int childId, wxString* name)
214 {
215 if (childId == wxACC_SELF)
216 {
217 * name = wxT("Splitter window");
218 return wxACC_OK;
219 }
220 else
221 return wxACC_NOT_IMPLEMENTED;
222 }
223
224 // Can return either a child object, or an integer
225 // representing the child element, starting from 1.
226 virtual wxAccStatus HitTest(const wxPoint& pt, int* childId, wxAccessible** childObject)
227 { return wxACC_NOT_IMPLEMENTED; }
228
229 // Returns the rectangle for this object (id = 0) or a child element (id > 0).
230 virtual wxAccStatus GetLocation(wxRect& WXUNUSED(rect), int WXUNUSED(elementId))
231 { return wxACC_NOT_IMPLEMENTED; }
232
233 // Navigates from fromId to toId/toObject.
234 virtual wxAccStatus Navigate(wxNavDir WXUNUSED(navDir), int WXUNUSED(fromId),
235 int* WXUNUSED(toId), wxAccessible** WXUNUSED(toObject))
236 { return wxACC_NOT_IMPLEMENTED; }
237
238 // Gets the number of children.
239 virtual wxAccStatus GetChildCount(int* WXUNUSED(childId))
240 { return wxACC_NOT_IMPLEMENTED; }
241
242 // Gets the specified child (starting from 1).
243 // If *child is NULL and return value is wxACC_OK,
244 // this means that the child is a simple element and
245 // not an accessible object.
246 virtual wxAccStatus GetChild(int WXUNUSED(childId), wxAccessible** WXUNUSED(child))
247 { return wxACC_NOT_IMPLEMENTED; }
248
249 // Gets the parent, or NULL.
250 virtual wxAccStatus GetParent(wxAccessible** WXUNUSED(parent))
251 { return wxACC_NOT_IMPLEMENTED; }
252
253 // Performs the default action. childId is 0 (the action for this object)
254 // or > 0 (the action for a child).
255 // Return wxACC_NOT_SUPPORTED if there is no default action for this
256 // window (e.g. an edit control).
257 virtual wxAccStatus DoDefaultAction(int WXUNUSED(childId))
258 { return wxACC_NOT_IMPLEMENTED; }
259
260 // Gets the default action for this object (0) or > 0 (the action for a child).
261 // Return wxACC_OK even if there is no action. actionName is the action, or the empty
262 // string if there is no action.
263 // The retrieved string describes the action that is performed on an object,
264 // not what the object does as a result. For example, a toolbar button that prints
265 // a document has a default action of "Press" rather than "Prints the current document."
266 virtual wxAccStatus GetDefaultAction(int WXUNUSED(childId), wxString* WXUNUSED(actionName))
267 { return wxACC_NOT_IMPLEMENTED; }
268
269 // Returns the description for this object or a child.
270 virtual wxAccStatus GetDescription(int WXUNUSED(childId), wxString* WXUNUSED(description))
271 { return wxACC_NOT_IMPLEMENTED; }
272
273 // Returns help text for this object or a child, similar to tooltip text.
274 virtual wxAccStatus GetHelpText(int WXUNUSED(childId), wxString* WXUNUSED(helpText))
275 { return wxACC_NOT_IMPLEMENTED; }
276
277 // Returns the keyboard shortcut for this object or child.
278 // Return e.g. ALT+K
279 virtual wxAccStatus GetKeyboardShortcut(int WXUNUSED(childId), wxString* WXUNUSED(shortcut))
280 { return wxACC_NOT_IMPLEMENTED; }
281
282 // Returns a role constant.
283 virtual wxAccStatus GetRole(int WXUNUSED(childId), wxAccRole* WXUNUSED(role))
284 { return wxACC_NOT_IMPLEMENTED; }
285
286 // Returns a state constant.
287 virtual wxAccStatus GetState(int WXUNUSED(childId), long* WXUNUSED(state))
288 { return wxACC_NOT_IMPLEMENTED; }
289
290 // Returns a localized string representing the value for the object
291 // or child.
292 virtual wxAccStatus GetValue(int WXUNUSED(childId), wxString* WXUNUSED(strValue))
293 { return wxACC_NOT_IMPLEMENTED; }
294
295 // Selects the object or child.
296 virtual wxAccStatus Select(int WXUNUSED(childId), wxAccSelectionFlags WXUNUSED(selectFlags))
297 { return wxACC_NOT_IMPLEMENTED; }
298
299 // Gets the window with the keyboard focus.
300 // If childId is 0 and child is NULL, no object in
301 // this subhierarchy has the focus.
302 // If this object has the focus, child should be 'this'.
303 virtual wxAccStatus GetFocus(int* WXUNUSED(childId), wxAccessible** WXUNUSED(child))
304 { return wxACC_NOT_IMPLEMENTED; }
305
306 // Gets a variant representing the selected children
307 // of this object.
308 // Acceptable values:
309 // - a null variant (IsNull() returns TRUE)
310 // - a list variant (GetType() == wxT("list"))
311 // - an integer representing the selected child element,
312 // or 0 if this object is selected (GetType() == wxT("long"))
313 // - a "void*" pointer to a wxAccessible child object
314 virtual wxAccStatus GetSelections(wxVariant* WXUNUSED(selections))
315 { return wxACC_NOT_IMPLEMENTED; }
316
317 };
318
319 // ----------------------------------------------------------------------------
320 // main frame
321 // ----------------------------------------------------------------------------
322
323 // frame constructor
324 MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size, long style)
325 : wxFrame(NULL, -1, title, pos, size, style)
326 {
327 m_textCtrl = NULL;
328
329 // SetAccessible(new FrameAccessible(this));
330
331 // set the frame icon
332 SetIcon(wxICON(mondrian));
333
334 #if wxUSE_MENUS
335 // create a menu bar
336 wxMenu *menuFile = new wxMenu;
337
338 // the "About" item should be in the help menu
339 wxMenu *helpMenu = new wxMenu;
340 helpMenu->Append(AccessTest_About, _T("&About...\tF1"), _T("Show about dialog"));
341
342 menuFile->Append(AccessTest_Query, _T("Query"), _T("Query the window hierarchy"));
343 menuFile->AppendSeparator();
344 menuFile->Append(AccessTest_Quit, _T("E&xit\tAlt-X"), _T("Quit this program"));
345
346 // now append the freshly created menu to the menu bar...
347 wxMenuBar *menuBar = new wxMenuBar();
348 menuBar->Append(menuFile, _T("&File"));
349 menuBar->Append(helpMenu, _T("&Help"));
350
351 // ... and attach this menu bar to the frame
352 SetMenuBar(menuBar);
353 #endif // wxUSE_MENUS
354
355 #if 0 // wxUSE_STATUSBAR
356 // create a status bar just for fun (by default with 1 pane only)
357 CreateStatusBar(2);
358 SetStatusText(_T("Welcome to wxWindows!"));
359 #endif // wxUSE_STATUSBAR
360
361 #if 1
362 wxSplitterWindow* splitter = new wxSplitterWindow(this, -1);
363 splitter->CreateAccessible();
364
365 wxListBox* listBox = new wxListBox(splitter, -1);
366 listBox->CreateAccessible();
367
368 m_textCtrl = new wxTextCtrl(splitter, -1, wxT(""), wxDefaultPosition,
369 wxDefaultSize, wxTE_MULTILINE);
370 m_textCtrl->CreateAccessible();
371
372 splitter->SplitHorizontally(listBox, m_textCtrl, 150);
373 #endif
374
375 #if 0
376 #if 1
377 wxListBox* listBox = new wxListBox(this, -1);
378 //listBox->SetAccessible(new wxAccessible(listBox));
379 #else
380 wxScrolledWindow* scrolledWindow = new wxScrolledWindow(this, -1);
381 scrolledWindow->SetAccessible(new ScrolledWindowAccessible(scrolledWindow));
382 #endif
383 #endif
384 }
385
386
387 // event handlers
388
389 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
390 {
391 // TRUE is to force the frame to close
392 Close(TRUE);
393 }
394
395 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
396 {
397 wxString msg;
398 msg.Printf( _T("This is the About dialog of the AccessTest sample.\n")
399 _T("Welcome to %s"), wxVERSION_STRING);
400
401 wxMessageBox(msg, _T("About AccessTest"), wxOK | wxICON_INFORMATION, this);
402 }
403
404 void MyFrame::OnQuery(wxCommandEvent& WXUNUSED(event))
405 {
406 m_textCtrl->Clear();
407 IAccessible* accessibleFrame = NULL;
408 if (S_OK != AccessibleObjectFromWindow((HWND) GetHWND(), OBJID_CLIENT,
409 IID_IAccessible, (void**) & accessibleFrame))
410 {
411 Log(wxT("Could not get object."));
412 return;
413 }
414 if (accessibleFrame)
415 {
416 //Log(wxT("Got an IAccessible for the frame."));
417 LogObject(0, accessibleFrame);
418 Log(wxT("Checking children using AccessibleChildren()..."));
419
420 // Now check the AccessibleChildren function works OK
421 long childCount = 0;
422 if (S_OK != accessibleFrame->get_accChildCount(& childCount))
423 {
424 Log(wxT("Could not get number of children."));
425 accessibleFrame->Release();
426 return;
427 }
428 else if (childCount == 0)
429 {
430 Log(wxT("No children."));
431 accessibleFrame->Release();
432 return;
433 }
434
435
436 long obtained = 0;
437 VARIANT *var = new VARIANT[childCount];
438 int i;
439 for (i = 0; i < childCount; i++)
440 {
441 VariantInit(& (var[i]));
442 var[i].vt = VT_DISPATCH;
443 }
444
445 if (S_OK == AccessibleChildren(accessibleFrame, 0, childCount, var, &obtained))
446 {
447 for (i = 0; i < childCount; i++)
448 {
449 IAccessible* childAccessible = NULL;
450 if (var[i].pdispVal)
451 {
452 if (var[i].pdispVal->QueryInterface(IID_IAccessible, (LPVOID*) & childAccessible) == S_OK)
453 {
454 var[i].pdispVal->Release();
455
456 wxString name, role;
457 GetInfo(childAccessible, 0, name, role);
458 wxString str;
459 str.Printf(wxT("Found child %s/%s"), name.c_str(), role.c_str());
460 Log(str);
461 childAccessible->Release();
462 }
463 else
464 {
465 var[i].pdispVal->Release();
466 }
467 }
468 }
469 }
470 else
471 {
472 Log(wxT("AccessibleChildren failed."));
473 }
474 delete[] var;
475
476
477 accessibleFrame->Release();
478 }
479 }
480
481 // Log messages to the text control
482 void MyFrame::Log(const wxString& text)
483 {
484 if (m_textCtrl)
485 {
486 wxString text2(text);
487 text2.Replace(wxT("\n"), wxT(" "));
488 text2.Replace(wxT("\r"), wxT(" "));
489 m_textCtrl->SetInsertionPointEnd();
490 m_textCtrl->WriteText(text2 + wxT("\n"));
491 }
492 }
493
494 // Recursively give information about an object
495 void MyFrame::LogObject(int indent, IAccessible* obj)
496 {
497 wxString name, role;
498 if (indent == 0)
499 {
500 GetInfo(obj, 0, name, role);
501
502 wxString str;
503 str.Printf(wxT("Name = %s; Role = %s"), name.c_str(), role.c_str());
504 str.Pad(indent, wxT(' '), FALSE);
505 Log(str);
506 }
507
508 long childCount = 0;
509 if (S_OK == obj->get_accChildCount(& childCount))
510 {
511 wxString str;
512 str.Printf(wxT("There are %d children."), (int) childCount);
513 str.Pad(indent, wxT(' '), FALSE);
514 Log(str);
515 Log(wxT(""));
516 }
517
518 int i;
519 for (i = 1; i <= childCount; i++)
520 {
521 GetInfo(obj, i, name, role);
522
523 wxString str;
524 str.Printf(wxT("%d) Name = %s; Role = %s"), i, name.c_str(), role.c_str());
525 str.Pad(indent, wxT(' '), FALSE);
526 Log(str);
527
528 VARIANT var;
529 VariantInit(& var);
530 var.vt = VT_I4;
531 var.lVal = i;
532 IDispatch* pDisp = NULL;
533 IAccessible* childObject = NULL;
534
535 if (S_OK == obj->get_accChild(var, & pDisp) && pDisp)
536 {
537 wxString str;
538 str.Printf(wxT("This is a real object."));
539 str.Pad(indent+4, wxT(' '), FALSE);
540 Log(str);
541
542 if (pDisp->QueryInterface(IID_IAccessible, (LPVOID*) & childObject) == S_OK)
543 {
544 LogObject(indent + 4, childObject);
545 childObject->Release();
546 }
547 pDisp->Release();
548 }
549 else
550 {
551 wxString str;
552 str.Printf(wxT("This is an element."));
553 str.Pad(indent+4, wxT(' '), FALSE);
554 Log(str);
555 }
556 // Log(wxT(""));
557 }
558
559 }
560
561 // Get info for a child (id > 0) or object (id == 0)
562 void MyFrame::GetInfo(IAccessible* accessible, int id, wxString& name, wxString& role)
563 {
564 VARIANT var;
565 VariantInit(& var);
566 var.vt = VT_I4;
567 var.lVal = id;
568
569 BSTR bStrName = 0;
570 HRESULT hResult = accessible->get_accName(var, & bStrName);
571
572 if (hResult == S_OK)
573 {
574 name = wxConvertStringFromOle(bStrName);
575 SysFreeString(bStrName);
576 }
577 else
578 {
579 name = wxT("NO NAME");
580 }
581
582 VARIANT varRole;
583 VariantInit(& varRole);
584
585 hResult = accessible->get_accRole(var, & varRole);
586
587 if (hResult == S_OK && varRole.vt == VT_I4)
588 {
589 wxChar buf[256];
590 GetRoleText(varRole.lVal, buf, 256);
591
592 role = buf;
593 }
594 else
595 {
596 role = wxT("NO ROLE");
597 }
598 }