1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the plugins of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include <QtCore/QtConfig>
43 #ifndef QT_NO_ACCESSIBILITY
46 #include <private/qsystemlibrary_p.h>
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>
58 #include "qwindowsaccessibility.h"
60 # include "qwindowsmsaaaccessible.h"
62 # include "iaccessible2.h"
68 //#include <uiautomationcoreapi.h>
69 #ifndef UiaRootObjectId
70 #define UiaRootObjectId -25
74 #if !defined(WINABLEAPI)
75 # if defined(Q_OS_WINCE)
82 #if !defined(Q_CC_BOR) && !defined (Q_CC_GNU)
86 #include "../qtwindows_additional.h"
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)
99 \class QWindowsAccessibility
101 Implements QPlatformAccessibility
104 QWindowsAccessibility::QWindowsAccessibility()
108 void QWindowsAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
111 switch (event->type()) {
112 case QAccessible::PopupMenuStart:
113 soundName = QLatin1String("MenuPopup");
116 case QAccessible::MenuCommand:
117 soundName = QLatin1String("MenuCommand");
120 case QAccessible::Alert:
123 #ifndef QT_NO_MESSAGEBOX
124 QMessageBox *mb = qobject_cast<QMessageBox*>(o);
126 switch (mb->icon()) {
127 case QMessageBox::Warning:
128 soundName = QLatin1String("SystemExclamation");
130 case QMessageBox::Critical:
131 soundName = QLatin1String("SystemHand");
133 case QMessageBox::Information:
134 soundName = QLatin1String("SystemAsterisk");
140 #endif // QT_NO_MESSAGEBOX
143 soundName = QLatin1String("SystemAsterisk");
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();
160 if (!file.isEmpty()) {
161 PlaySound(reinterpret_cast<const wchar_t *>(soundName.utf16()), 0, SND_ALIAS | SND_ASYNC | SND_NODEFAULT | SND_NOWAIT);
165 typedef void (WINAPI *PtrNotifyWinEvent)(DWORD, HWND, LONG, LONG);
167 #if defined(Q_OS_WINCE) // ### TODO: check for NotifyWinEvent in CE 6.0
168 // There is no user32.lib nor NotifyWinEvent for CE
171 static PtrNotifyWinEvent ptrNotifyWinEvent = 0;
172 static bool resolvedNWE = false;
175 ptrNotifyWinEvent = (PtrNotifyWinEvent)QSystemLibrary::resolve(QLatin1String("user32"), "NotifyWinEvent");
177 if (!ptrNotifyWinEvent)
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;
187 window = QGuiApplication::focusWindow();
192 QPlatformNativeInterface *platform = QGuiApplication::platformNativeInterface();
193 HWND hWnd = (HWND)platform->nativeResourceForWindow("handle", window);
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);
201 qAccessibleRecentSentEvents()->insert(eventId, qMakePair(event->object(), event->child()));
202 ptrNotifyWinEvent(event->type(), hWnd, OBJID_CLIENT, eventId );
209 QWindow *QWindowsAccessibility::windowHelper(const QAccessibleInterface *iface)
211 QWindow *window = iface->window();
213 QAccessibleInterface *acc = iface->parent();
214 while (acc && !window) {
215 window = acc->window();
216 QAccessibleInterface *par = acc->parent();
226 helper to wrap a QAccessibleInterface inside a IAccessible*
228 IAccessible *QWindowsAccessibility::wrap(QAccessibleInterface *acc)
233 QWindowsMsaaAccessible *wacc = new QWindowsMsaaAccessible(acc);
235 QWindowsIA2Accessible *wacc = new QWindowsIA2Accessible(acc);
237 IAccessible *iacc = 0;
238 wacc->QueryInterface(IID_IAccessible, (void**)&iacc);
245 QPair<QObject*, int> QWindowsAccessibility::getCachedObject(int entryId)
247 return qAccessibleRecentSentEvents()->value(entryId);
251 void QWindowsAccessibility::setRootObject(QObject *o)
256 void QWindowsAccessibility::initialize()
261 void QWindowsAccessibility::cleanup()
268 bool QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
270 if (static_cast<long>(lParam) == static_cast<long>(UiaRootObjectId)) {
271 /* For UI Automation */
272 } else if ((DWORD)lParam == OBJID_CLIENT) {
274 // Ignoring all requests while starting up
275 // ### Maybe QPA takes care of this???
276 if (QCoreApplication::startingUp() || QCoreApplication::closingDown())
280 typedef LRESULT (WINAPI *PtrLresultFromObject)(REFIID, WPARAM, LPUNKNOWN);
281 static PtrLresultFromObject ptrLresultFromObject = 0;
282 static bool oleaccChecked = false;
284 if (!oleaccChecked) {
285 oleaccChecked = true;
286 #if !defined(Q_OS_WINCE)
287 ptrLresultFromObject = (PtrLresultFromObject)QSystemLibrary::resolve(QLatin1String("oleacc"), "LresultFromObject");
291 if (ptrLresultFromObject) {
292 QWindow *window = QWindowsContext::instance()->findWindow(hwnd);
294 QAccessibleInterface *acc = window->accessibleRoot();
296 if (IAccessible *iface = wrap(acc)) {
297 *lResult = ptrLresultFromObject(IID_IAccessible, wParam, iface); // ref == 2
299 iface->Release(); // the client will release the object again, and then it will destroy itself
314 #endif //QT_NO_ACCESSIBILITY