db2d5f949f1fdd553a5260699445f519d378577c
[profile/ivi/qtbase.git] / src / plugins / platforms / windows / accessible / qwindowsaccessibility.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QtCore/QtConfig>
43 #ifndef QT_NO_ACCESSIBILITY
44
45
46 #include <private/qsystemlibrary_p.h>
47
48 #include <QtCore/qlocale.h>
49 #include <QtCore/qmap.h>
50 #include <QtCore/qpair.h>
51 #include <QtCore/qsettings.h>
52 #include <QtGui/qaccessible.h>
53 #include <QtGui/qaccessible2.h>
54 #include <qpa/qplatformnativeinterface.h>
55 #include <QtGui/qwindow.h>
56 #include <QtGui/qguiapplication.h>
57
58 #include "qwindowsaccessibility.h"
59 #ifdef Q_CC_MINGW
60 # include "qwindowsmsaaaccessible.h"
61 #else
62 # include "iaccessible2.h"
63 #endif
64 #include "comutils.h"
65
66 #include <oleacc.h>
67
68 //#include <uiautomationcoreapi.h>
69 #ifndef UiaRootObjectId
70 #define UiaRootObjectId        -25
71 #endif
72
73 #include <winuser.h>
74 #if !defined(WINABLEAPI)
75 #  if defined(Q_OS_WINCE)
76 #    include <bldver.h>
77 #  endif
78 #  include <winable.h>
79 #endif
80
81 #include <servprov.h>
82 #if !defined(Q_CC_BOR) && !defined (Q_CC_GNU)
83 #include <comdef.h>
84 #endif
85
86 #include "../qtwindows_additional.h"
87
88
89 // This stuff is used for widgets/items with no window handle:
90 typedef QMap<int, QPair<QObject*,int> > NotifyMap;
91 Q_GLOBAL_STATIC(NotifyMap, qAccessibleRecentSentEvents)
92
93
94 QT_BEGIN_NAMESPACE
95
96
97 /*!
98     \!internal
99     \class QWindowsAccessibility
100
101     Implements QPlatformAccessibility
102
103 */
104 QWindowsAccessibility::QWindowsAccessibility()
105 {
106 }
107
108 void QWindowsAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
109 {
110     QString soundName;
111     switch (event->type()) {
112     case QAccessible::PopupMenuStart:
113         soundName = QLatin1String("MenuPopup");
114         break;
115
116     case QAccessible::MenuCommand:
117         soundName = QLatin1String("MenuCommand");
118         break;
119
120     case QAccessible::Alert:
121         {
122         /*      ### FIXME
123 #ifndef QT_NO_MESSAGEBOX
124             QMessageBox *mb = qobject_cast<QMessageBox*>(o);
125             if (mb) {
126                 switch (mb->icon()) {
127                 case QMessageBox::Warning:
128                     soundName = QLatin1String("SystemExclamation");
129                     break;
130                 case QMessageBox::Critical:
131                     soundName = QLatin1String("SystemHand");
132                     break;
133                 case QMessageBox::Information:
134                     soundName = QLatin1String("SystemAsterisk");
135                     break;
136                 default:
137                     break;
138                 }
139             } else
140 #endif // QT_NO_MESSAGEBOX
141 */
142             {
143                 soundName = QLatin1String("SystemAsterisk");
144             }
145
146         }
147         break;
148     default:
149         break;
150     }
151
152     if (!soundName.isEmpty()) {
153 #ifndef QT_NO_SETTINGS
154         QSettings settings(QLatin1String("HKEY_CURRENT_USER\\AppEvents\\Schemes\\Apps\\.Default\\") + soundName,
155                            QSettings::NativeFormat);
156         QString file = settings.value(QLatin1String(".Current/.")).toString();
157 #else
158         QString file;
159 #endif
160         if (!file.isEmpty()) {
161             PlaySound(reinterpret_cast<const wchar_t *>(soundName.utf16()), 0, SND_ALIAS | SND_ASYNC | SND_NODEFAULT | SND_NOWAIT);
162         }
163     }
164
165     typedef void (WINAPI *PtrNotifyWinEvent)(DWORD, HWND, LONG, LONG);
166
167 #if defined(Q_OS_WINCE) // ### TODO: check for NotifyWinEvent in CE 6.0
168     // There is no user32.lib nor NotifyWinEvent for CE
169     return;
170 #else
171     static PtrNotifyWinEvent ptrNotifyWinEvent = 0;
172     static bool resolvedNWE = false;
173     if (!resolvedNWE) {
174         resolvedNWE = true;
175         ptrNotifyWinEvent = (PtrNotifyWinEvent)QSystemLibrary::resolve(QLatin1String("user32"), "NotifyWinEvent");
176     }
177     if (!ptrNotifyWinEvent)
178         return;
179
180     // An event has to be associated with a window,
181     // so find the first parent that is a widget and that has a WId
182     QAccessibleInterface *iface = event->accessibleInterface();
183     QWindow *window = iface ? QWindowsAccessibility::windowHelper(iface) : 0;
184     delete iface;
185
186     if (!window) {
187         window = QGuiApplication::focusWindow();
188         if (!window)
189             return;
190     }
191
192     QPlatformNativeInterface *platform = QGuiApplication::platformNativeInterface();
193     HWND hWnd = (HWND)platform->nativeResourceForWindow("handle", window);
194
195     static int eventNum = 0;
196     if (event->type() != QAccessible::MenuCommand) { // MenuCommand is faked
197         // See comment "SENDING EVENTS TO OBJECTS WITH NO WINDOW HANDLE"
198         eventNum %= 50;              //[0..49]
199         int eventId = - (eventNum - 1);
200
201         qAccessibleRecentSentEvents()->insert(eventId, qMakePair(event->object(), event->child()));
202         ptrNotifyWinEvent(event->type(), hWnd, OBJID_CLIENT, eventId );
203
204         ++eventNum;
205     }
206 #endif // Q_OS_WINCE
207 }
208
209 QWindow *QWindowsAccessibility::windowHelper(const QAccessibleInterface *iface)
210 {
211     QWindow *window = iface->window();
212     if (!window) {
213         QAccessibleInterface *acc = iface->parent();
214         while (acc && !window) {
215             window = acc->window();
216             QAccessibleInterface *par = acc->parent();
217             delete acc;
218             acc = par;
219         }
220     }
221     return window;
222 }
223
224 /*!
225   \internal
226   helper to wrap a QAccessibleInterface inside a IAccessible*
227 */
228 IAccessible *QWindowsAccessibility::wrap(QAccessibleInterface *acc)
229 {
230     if (!acc)
231         return 0;
232 #ifdef Q_CC_MINGW
233     QWindowsMsaaAccessible *wacc = new QWindowsMsaaAccessible(acc);
234 #else
235     QWindowsIA2Accessible *wacc = new QWindowsIA2Accessible(acc);
236 #endif
237     IAccessible *iacc = 0;
238     wacc->QueryInterface(IID_IAccessible, (void**)&iacc);
239     return iacc;
240 }
241
242 /*!
243   \internal
244 */
245 QPair<QObject*, int> QWindowsAccessibility::getCachedObject(int entryId)
246 {
247     return qAccessibleRecentSentEvents()->value(entryId);
248 }
249
250 /*
251 void QWindowsAccessibility::setRootObject(QObject *o)
252 {
253
254 }
255
256 void QWindowsAccessibility::initialize()
257 {
258
259 }
260
261 void QWindowsAccessibility::cleanup()
262 {
263
264 }
265
266 */
267
268 bool QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
269 {
270     if (static_cast<long>(lParam) == static_cast<long>(UiaRootObjectId)) {
271         /* For UI Automation */
272     } else if ((DWORD)lParam == OBJID_CLIENT) {
273 #if 1
274         // Ignoring all requests while starting up
275         // ### Maybe QPA takes care of this???
276         if (QCoreApplication::startingUp() || QCoreApplication::closingDown())
277             return false;
278 #endif
279
280         typedef LRESULT (WINAPI *PtrLresultFromObject)(REFIID, WPARAM, LPUNKNOWN);
281         static PtrLresultFromObject ptrLresultFromObject = 0;
282         static bool oleaccChecked = false;
283
284         if (!oleaccChecked) {
285             oleaccChecked = true;
286 #if !defined(Q_OS_WINCE)
287             ptrLresultFromObject = (PtrLresultFromObject)QSystemLibrary::resolve(QLatin1String("oleacc"), "LresultFromObject");
288 #endif
289         }
290
291         if (ptrLresultFromObject) {
292             QWindow *window = QWindowsContext::instance()->findWindow(hwnd);
293             if (window) {
294                 QAccessibleInterface *acc = window->accessibleRoot();
295                 if (acc) {
296                     if (IAccessible *iface = wrap(acc)) {
297                         *lResult = ptrLresultFromObject(IID_IAccessible, wParam, iface);  // ref == 2
298                         if (*lResult) {
299                             iface->Release(); // the client will release the object again, and then it will destroy itself
300                         }
301                         return true;
302                     } else {
303                         delete acc;
304                     }
305                 }
306             }
307         }
308     }
309     return false;
310 }
311
312 QT_END_NAMESPACE
313
314 #endif //QT_NO_ACCESSIBILITY