]> git.saurik.com Git - wxWidgets.git/blob - samples/access/accesstest.cpp
Further tweaks to accessibility code
[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 // ----------------------------------------------------------------------------
208 // main frame
209 // ----------------------------------------------------------------------------
210
211 // frame constructor
212 MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size, long style)
213 : wxFrame(NULL, -1, title, pos, size, style)
214 {
215 m_textCtrl = NULL;
216
217 // SetAccessible(new FrameAccessible(this));
218
219 // set the frame icon
220 SetIcon(wxICON(mondrian));
221
222 #if wxUSE_MENUS
223 // create a menu bar
224 wxMenu *menuFile = new wxMenu;
225
226 // the "About" item should be in the help menu
227 wxMenu *helpMenu = new wxMenu;
228 helpMenu->Append(AccessTest_About, _T("&About...\tF1"), _T("Show about dialog"));
229
230 menuFile->Append(AccessTest_Query, _T("Query"), _T("Query the window hierarchy"));
231 menuFile->AppendSeparator();
232 menuFile->Append(AccessTest_Quit, _T("E&xit\tAlt-X"), _T("Quit this program"));
233
234 // now append the freshly created menu to the menu bar...
235 wxMenuBar *menuBar = new wxMenuBar();
236 menuBar->Append(menuFile, _T("&File"));
237 menuBar->Append(helpMenu, _T("&Help"));
238
239 // ... and attach this menu bar to the frame
240 SetMenuBar(menuBar);
241 #endif // wxUSE_MENUS
242
243 #if 0 // wxUSE_STATUSBAR
244 // create a status bar just for fun (by default with 1 pane only)
245 CreateStatusBar(2);
246 SetStatusText(_T("Welcome to wxWindows!"));
247 #endif // wxUSE_STATUSBAR
248
249 #if 1
250 wxSplitterWindow* splitter = new wxSplitterWindow(this, -1);
251 splitter->CreateAccessible();
252
253 wxListBox* listBox = new wxListBox(splitter, -1);
254 listBox->CreateAccessible();
255
256 m_textCtrl = new wxTextCtrl(splitter, -1, wxT(""), wxDefaultPosition,
257 wxDefaultSize, wxTE_MULTILINE);
258 m_textCtrl->CreateAccessible();
259
260 splitter->SplitHorizontally(listBox, m_textCtrl, 150);
261 #endif
262
263 #if 0
264 #if 1
265 wxListBox* listBox = new wxListBox(this, -1);
266 //listBox->SetAccessible(new wxAccessible(listBox));
267 #else
268 wxScrolledWindow* scrolledWindow = new wxScrolledWindow(this, -1);
269 scrolledWindow->SetAccessible(new ScrolledWindowAccessible(scrolledWindow));
270 #endif
271 #endif
272 }
273
274
275 // event handlers
276
277 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
278 {
279 // TRUE is to force the frame to close
280 Close(TRUE);
281 }
282
283 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
284 {
285 wxString msg;
286 msg.Printf( _T("This is the About dialog of the AccessTest sample.\n")
287 _T("Welcome to %s"), wxVERSION_STRING);
288
289 wxMessageBox(msg, _T("About AccessTest"), wxOK | wxICON_INFORMATION, this);
290 }
291
292 void MyFrame::OnQuery(wxCommandEvent& WXUNUSED(event))
293 {
294 m_textCtrl->Clear();
295 IAccessible* accessibleFrame = NULL;
296 if (S_OK != AccessibleObjectFromWindow((HWND) GetHWND(), OBJID_CLIENT,
297 IID_IAccessible, (void**) & accessibleFrame))
298 {
299 Log(wxT("Could not get object."));
300 return;
301 }
302 if (accessibleFrame)
303 {
304 //Log(wxT("Got an IAccessible for the frame."));
305 LogObject(0, accessibleFrame);
306 Log(wxT("Checking children using AccessibleChildren()..."));
307
308 // Now check the AccessibleChildren function works OK
309 long childCount = 0;
310 if (S_OK != accessibleFrame->get_accChildCount(& childCount))
311 {
312 Log(wxT("Could not get number of children."));
313 accessibleFrame->Release();
314 return;
315 }
316 else if (childCount == 0)
317 {
318 Log(wxT("No children."));
319 accessibleFrame->Release();
320 return;
321 }
322
323
324 long obtained = 0;
325 VARIANT *var = new VARIANT[childCount];
326 int i;
327 for (i = 0; i < childCount; i++)
328 {
329 VariantInit(& (var[i]));
330 var[i].vt = VT_DISPATCH;
331 }
332
333 if (S_OK == AccessibleChildren(accessibleFrame, 0, childCount, var, &obtained))
334 {
335 for (i = 0; i < childCount; i++)
336 {
337 IAccessible* childAccessible = NULL;
338 if (var[i].pdispVal)
339 {
340 if (var[i].pdispVal->QueryInterface(IID_IAccessible, (LPVOID*) & childAccessible) == S_OK)
341 {
342 var[i].pdispVal->Release();
343
344 wxString name, role;
345 GetInfo(childAccessible, 0, name, role);
346 wxString str;
347 str.Printf(wxT("Found child %s/%s"), name.c_str(), role.c_str());
348 Log(str);
349 childAccessible->Release();
350 }
351 else
352 {
353 var[i].pdispVal->Release();
354 }
355 }
356 }
357 }
358 else
359 {
360 Log(wxT("AccessibleChildren failed."));
361 }
362 delete[] var;
363
364
365 accessibleFrame->Release();
366 }
367 }
368
369 // Log messages to the text control
370 void MyFrame::Log(const wxString& text)
371 {
372 if (m_textCtrl)
373 {
374 wxString text2(text);
375 text2.Replace(wxT("\n"), wxT(" "));
376 text2.Replace(wxT("\r"), wxT(" "));
377 m_textCtrl->SetInsertionPointEnd();
378 m_textCtrl->WriteText(text2 + wxT("\n"));
379 }
380 }
381
382 // Recursively give information about an object
383 void MyFrame::LogObject(int indent, IAccessible* obj)
384 {
385 wxString name, role;
386 if (indent == 0)
387 {
388 GetInfo(obj, 0, name, role);
389
390 wxString str;
391 str.Printf(wxT("Name = %s; Role = %s"), name.c_str(), role.c_str());
392 str.Pad(indent, wxT(' '), FALSE);
393 Log(str);
394 }
395
396 long childCount = 0;
397 if (S_OK == obj->get_accChildCount(& childCount))
398 {
399 wxString str;
400 str.Printf(wxT("There are %d children."), (int) childCount);
401 str.Pad(indent, wxT(' '), FALSE);
402 Log(str);
403 Log(wxT(""));
404 }
405
406 int i;
407 for (i = 1; i <= childCount; i++)
408 {
409 GetInfo(obj, i, name, role);
410
411 wxString str;
412 str.Printf(wxT("%d) Name = %s; Role = %s"), i, name.c_str(), role.c_str());
413 str.Pad(indent, wxT(' '), FALSE);
414 Log(str);
415
416 VARIANT var;
417 VariantInit(& var);
418 var.vt = VT_I4;
419 var.lVal = i;
420 IDispatch* pDisp = NULL;
421 IAccessible* childObject = NULL;
422
423 if (S_OK == obj->get_accChild(var, & pDisp) && pDisp)
424 {
425 wxString str;
426 str.Printf(wxT("This is a real object."));
427 str.Pad(indent+4, wxT(' '), FALSE);
428 Log(str);
429
430 if (pDisp->QueryInterface(IID_IAccessible, (LPVOID*) & childObject) == S_OK)
431 {
432 LogObject(indent + 4, childObject);
433 childObject->Release();
434 }
435 pDisp->Release();
436 }
437 else
438 {
439 wxString str;
440 str.Printf(wxT("This is an element."));
441 str.Pad(indent+4, wxT(' '), FALSE);
442 Log(str);
443 }
444 // Log(wxT(""));
445 }
446
447 }
448
449 // Get info for a child (id > 0) or object (id == 0)
450 void MyFrame::GetInfo(IAccessible* accessible, int id, wxString& name, wxString& role)
451 {
452 VARIANT var;
453 VariantInit(& var);
454 var.vt = VT_I4;
455 var.lVal = id;
456
457 BSTR bStrName = 0;
458 HRESULT hResult = accessible->get_accName(var, & bStrName);
459
460 if (hResult == S_OK)
461 {
462 name = wxConvertStringFromOle(bStrName);
463 SysFreeString(bStrName);
464 }
465 else
466 {
467 name = wxT("NO NAME");
468 }
469
470 VARIANT varRole;
471 VariantInit(& varRole);
472
473 hResult = accessible->get_accRole(var, & varRole);
474
475 if (hResult == S_OK && varRole.vt == VT_I4)
476 {
477 wxChar buf[256];
478 GetRoleText(varRole.lVal, buf, 256);
479
480 role = buf;
481 }
482 else
483 {
484 role = wxT("NO ROLE");
485 }
486 }