Refactor accessibility for Qt5

* Moved most stuff to gui\accessible
* Moved widget-specific stuff to widgets\accessible
* Moved platform-specific code to either the bridge plugin (this was already the case)
  or to the platform plugin.
* Added several classes and functions. These have not yet gone through an API
  review. The plan is to do that in a later commit.
  Classes:
   - QPlatformAccessibility
   - QWindowsAccessibility
  Functions:
   - QWindow *QAccessibleInterface::window();
   - QPlatformAccessibility *QPlatformIntegration::accessibility()

* The bridge code can now either be a plugin or integrated into the platform plugin
* Mac accessibility is left out for now. Unix "should still work" (tm). These platforms
  should be fixed soon.

Change-Id: Ib49ffa73b647ee0af90864544c2769440157f562
Reviewed-on: http://codereview.qt-project.org/5330
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@nokia.com>
Reviewed-by: Jan-Arve Sæther <jan-arve.saether@nokia.com>
This commit is contained in:
Jan-Arve Saether 2011-09-16 06:56:48 +02:00 committed by Qt by Nokia
parent 8ebd7d84fc
commit 87ae97c11a
44 changed files with 703 additions and 484 deletions

View File

@ -0,0 +1,31 @@
# Qt accessibility module
contains(QT_CONFIG, accessibility) {
HEADERS += \
accessible/qaccessible.h \
accessible/qaccessible2.h \
accessible/qaccessibleobject.h \
accessible/qaccessibleplugin.h \
accessible/qplatformaccessibility_qpa.h
SOURCES += accessible/qaccessible.cpp \
accessible/qaccessible2.cpp \
accessible/qaccessibleobject.cpp \
accessible/qaccessibleplugin.cpp \
accessible/qplatformaccessibility_qpa.cpp
HEADERS += accessible/qaccessiblebridge.h
SOURCES += accessible/qaccessiblebridge.cpp
### FIXME
# mac:!qpa {
# HEADERS += accessible/qaccessible_mac_p.h
# OBJECTIVE_SOURCES += accessible/qaccessible_mac.mm \
# accessible/qaccessible_mac_cocoa.mm
# } else:win32:!qpa {
# SOURCES += accessible/qaccessible_win.cpp
# } else {
# HEADERS += accessible/qaccessiblebridge.h
# SOURCES += accessible/qaccessible_unix.cpp accessible/qaccessiblebridge.cpp
# }
}

View File

@ -44,14 +44,16 @@
#ifndef QT_NO_ACCESSIBILITY
#include "qaccessibleplugin.h"
#include "qaccessiblewidget.h"
#include "qapplication.h"
#include "qhash.h"
#include "qmetaobject.h"
#include "qmutex.h"
#include <private/qfactoryloader_p.h>
#include "qaccessibleobject.h"
#include "qaccessiblebridge.h"
#include <QtGui/QGuiApplication>
#include <private/qguiapplication_p.h>
#include "qplatformaccessibility_qpa.h"
#include "qwidget.h"
#include <QtCore/QHash>
#include <QtCore/QMetaObject>
#include <QtCore/QMutex>
#include <private/qfactoryloader_p.h>
QT_BEGIN_NAMESPACE
@ -438,16 +440,10 @@ QT_BEGIN_NAMESPACE
Destroys the object.
*/
/*!
\fn void QAccessible::initialize()
\internal
*/
/*!
\fn void QAccessible::cleanup()
\internal
*/
/* accessible widgets plugin discovery stuff */
#ifndef QT_NO_LIBRARY
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
(QAccessibleFactoryInterface_iid, QLatin1String("/accessible")))
@ -460,6 +456,22 @@ QAccessible::RootObjectHandler QAccessible::rootObjectHandler = 0;
static bool accessibility_active = false;
static bool cleanupAdded = false;
static QPlatformAccessibility *platformAccessibility()
{
QPlatformIntegration *pfIntegration = QGuiApplicationPrivate::platformIntegration();
return pfIntegration ? pfIntegration->accessibility() : 0;
}
/*!
\internal
*/
void QAccessible::cleanup()
{
if (QPlatformAccessibility *pfAccessibility = platformAccessibility())
pfAccessibility->cleanup();
}
static void qAccessibleCleanup()
{
qAccessibleFactories()->clear();
@ -507,6 +519,7 @@ static void qAccessibleCleanup()
The function is called by setRootObject().
*/
/*!
Installs the InterfaceFactory \a factory. The last factory added
is the first one used by queryAccessibleInterface().
@ -585,7 +598,8 @@ QAccessibleInterface *QAccessible::queryAccessibleInterface(QObject *object)
return 0;
QEvent e(QEvent::AccessibilityPrepare);
QApplication::sendEvent(object, &e);
QCoreApplication::sendEvent(object, &e);
const QMetaObject *mo = object->metaObject();
while (mo) {
@ -607,13 +621,11 @@ QAccessibleInterface *QAccessible::queryAccessibleInterface(QObject *object)
mo = mo->superClass();
}
QWidget *widget = qobject_cast<QWidget*>(object);
if (widget)
return new QAccessibleWidget(widget);
else if (object == qApp)
return new QAccessibleApplication();
return 0;
if (!iface) {
if (object == qApp)
iface = new QAccessibleApplication;
}
return iface;
}
/*!
@ -628,9 +640,9 @@ bool QAccessible::isActive()
return accessibility_active;
}
/*!
\fn void QAccessible::setRootObject(QObject *object)
/*!
Sets the root accessible object of this application to \a object.
All other accessible objects in the application can be reached by the
client using object navigation.
@ -644,10 +656,18 @@ bool QAccessible::isActive()
\sa queryAccessibleInterface()
*/
void QAccessible::setRootObject(QObject *o)
{
if (rootObjectHandler) {
rootObjectHandler(o);
return;
}
if (QPlatformAccessibility *pfAccessibility = platformAccessibility())
pfAccessibility->setRootObject(o);
}
/*!
\fn void QAccessible::updateAccessibility(QObject *object, int child, Event reason)
Notifies accessibility clients about a change in \a object's
accessibility information.
@ -665,6 +685,21 @@ bool QAccessible::isActive()
the parameters of the call is expensive you can test isActive() to
avoid unnecessary computations.
*/
void QAccessible::updateAccessibility(QObject *o, int who, Event reason)
{
Q_ASSERT(o);
if (updateHandler) {
updateHandler(o, who, reason);
return;
}
if (!isActive())
return;
if (QPlatformAccessibility *pfAccessibility = platformAccessibility())
pfAccessibility->notifyAccessibilityUpdate(o, who, reason);
}
/*!
@ -1161,6 +1196,24 @@ QVector<QPair<QAccessibleInterface*, QAccessible::Relation> > QAccessibleInterfa
\sa value()
*/
/*!
Returns the window associated with the underlying object.
For instance, QAccessibleWidget reimplements this and returns
the windowHandle() of the QWidget.
The default implementation returns the window() of the parent interface.
It is used on some platforms to be able to notify the AT client about
state changes.
\preliminary
*/
QWindow *QAccessibleInterface::window() const
{
QAccessibleInterface *par = parent();
QWindow *w = par ? par->window() : 0;
delete par;
return w;
}
/*!
\since 4.2

View File

@ -51,6 +51,8 @@
#include <QtGui/qcolor.h>
#include <QtGui/qevent.h>
class QWindow;
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
@ -61,7 +63,7 @@ QT_MODULE(Gui)
class QAccessibleInterface;
class Q_WIDGETS_EXPORT QAccessible
class Q_GUI_EXPORT QAccessible
{
public:
enum Event {
@ -294,7 +296,7 @@ public:
Increase = -3,
Decrease = -4,
Accept = -5,
Cancel = -6,
Cancel = -6,
Select = -7,
ClearSelection = -8,
RemoveSelection = -9,
@ -325,7 +327,6 @@ public:
static bool isActive();
static void setRootObject(QObject*);
static void initialize();
static void cleanup();
private:
@ -362,13 +363,14 @@ class QAccessibleActionInterface;
class QAccessibleImageInterface;
class QAccessibleTable2Interface;
class Q_WIDGETS_EXPORT QAccessibleInterface : public QAccessible
class Q_GUI_EXPORT QAccessibleInterface : public QAccessible
{
public:
virtual ~QAccessibleInterface() {}
// check for valid pointers
virtual bool isValid() const = 0;
virtual QObject *object() const = 0;
virtual QWindow *window() const;
// hierarchy
virtual int childCount() const = 0;
@ -440,7 +442,7 @@ private:
QAccessible2Interface *cast_helper(QAccessible2::InterfaceType);
};
class Q_WIDGETS_EXPORT QAccessibleEvent : public QEvent
class QAccessibleEvent : public QEvent
{
public:
inline QAccessibleEvent(Type type, int child);

View File

@ -40,7 +40,7 @@
****************************************************************************/
#include "qaccessible2.h"
#include "qapplication.h"
#include <QtGui/QGuiApplication>
#include "qclipboard.h"
#include "qtextboundaryfinder.h"
@ -137,7 +137,7 @@ QT_BEGIN_NAMESPACE
/*!
\internal
*/
QString Q_WIDGETS_EXPORT qTextBeforeOffsetFromString(int offset, QAccessible2::BoundaryType boundaryType,
QString Q_GUI_EXPORT qTextBeforeOffsetFromString(int offset, QAccessible2::BoundaryType boundaryType,
int *startOffset, int *endOffset, const QString& text)
{
QTextBoundaryFinder::BoundaryType type;
@ -175,7 +175,7 @@ QString Q_WIDGETS_EXPORT qTextBeforeOffsetFromString(int offset, QAccessible2::B
/*!
\internal
*/
QString Q_WIDGETS_EXPORT qTextAfterOffsetFromString(int offset, QAccessible2::BoundaryType boundaryType,
QString Q_GUI_EXPORT qTextAfterOffsetFromString(int offset, QAccessible2::BoundaryType boundaryType,
int *startOffset, int *endOffset, const QString& text)
{
QTextBoundaryFinder::BoundaryType type;
@ -210,7 +210,7 @@ QString Q_WIDGETS_EXPORT qTextAfterOffsetFromString(int offset, QAccessible2::Bo
/*!
\internal
*/
QString Q_WIDGETS_EXPORT qTextAtOffsetFromString(int offset, QAccessible2::BoundaryType boundaryType,
QString Q_GUI_EXPORT qTextAtOffsetFromString(int offset, QAccessible2::BoundaryType boundaryType,
int *startOffset, int *endOffset, const QString& text)
{
QTextBoundaryFinder::BoundaryType type;
@ -264,7 +264,7 @@ void QAccessibleSimpleEditableTextInterface::copyText(int startOffset, int endOf
Q_UNUSED(startOffset);
Q_UNUSED(endOffset);
#else
QApplication::clipboard()->setText(textForRange(iface, startOffset, endOffset));
QGuiApplication::clipboard()->setText(textForRange(iface, startOffset, endOffset));
#endif
}
@ -290,7 +290,7 @@ void QAccessibleSimpleEditableTextInterface::cutText(int startOffset, int endOff
#else
QString sub = textForRange(iface, startOffset, endOffset);
deleteText(startOffset, endOffset);
QApplication::clipboard()->setText(sub);
QGuiApplication::clipboard()->setText(sub);
#endif
}
@ -300,7 +300,7 @@ void QAccessibleSimpleEditableTextInterface::pasteText(int offset)
Q_UNUSED(offset);
#else
QString txt = iface->text(QAccessible::Value, 0);
txt.insert(offset, QApplication::clipboard()->text());
txt.insert(offset, QGuiApplication::clipboard()->text());
iface->setText(QAccessible::Value, 0, txt);
#endif
}

View File

@ -42,7 +42,7 @@
#ifndef QACCESSIBLE2_H
#define QACCESSIBLE2_H
#include <QtWidgets/qaccessible.h>
#include "qaccessible.h"
QT_BEGIN_HEADER
@ -90,7 +90,7 @@ namespace QAccessible2
};
}
class Q_WIDGETS_EXPORT QAccessible2Interface
class Q_GUI_EXPORT QAccessible2Interface
{
public:
virtual ~QAccessible2Interface() {}
@ -129,7 +129,7 @@ inline QAccessible2Interface *qAccessibleTable2CastHelper() { return 0; }
} \
private:
class Q_WIDGETS_EXPORT QAccessibleTextInterface: public QAccessible2Interface
class Q_GUI_EXPORT QAccessibleTextInterface: public QAccessible2Interface
{
public:
inline QAccessible2Interface *qAccessibleTextCastHelper() { return this; }
@ -157,7 +157,7 @@ public:
virtual void scrollToSubstring(int startIndex, int endIndex) = 0;
};
class Q_WIDGETS_EXPORT QAccessibleEditableTextInterface: public QAccessible2Interface
class Q_GUI_EXPORT QAccessibleEditableTextInterface: public QAccessible2Interface
{
public:
inline QAccessible2Interface *qAccessibleEditableTextCastHelper() { return this; }
@ -173,7 +173,7 @@ public:
virtual void setAttributes(int startOffset, int endOffset, const QString &attributes) = 0;
};
class Q_WIDGETS_EXPORT QAccessibleSimpleEditableTextInterface: public QAccessibleEditableTextInterface
class Q_GUI_EXPORT QAccessibleSimpleEditableTextInterface: public QAccessibleEditableTextInterface
{
public:
QAccessibleSimpleEditableTextInterface(QAccessibleInterface *accessibleInterface);
@ -190,7 +190,7 @@ private:
QAccessibleInterface *iface;
};
class Q_WIDGETS_EXPORT QAccessibleValueInterface: public QAccessible2Interface
class Q_GUI_EXPORT QAccessibleValueInterface: public QAccessible2Interface
{
public:
inline QAccessible2Interface *qAccessibleValueCastHelper() { return this; }
@ -203,7 +203,7 @@ public:
virtual QVariant minimumValue() = 0;
};
class Q_WIDGETS_EXPORT QAccessibleTableInterface: public QAccessible2Interface
class Q_GUI_EXPORT QAccessibleTableInterface: public QAccessible2Interface
{
public:
inline QAccessible2Interface *qAccessibleTableCastHelper() { return this; }
@ -237,7 +237,7 @@ public:
int *columnSpan, bool *isSelected) = 0;
};
class Q_WIDGETS_EXPORT QAccessibleTable2CellInterface: public QAccessibleInterface
class Q_GUI_EXPORT QAccessibleTable2CellInterface: public QAccessibleInterface
{
public:
// Returns the number of columns occupied by this cell accessible.
@ -266,7 +266,7 @@ public:
virtual bool isExpandable() const = 0;
};
class Q_WIDGETS_EXPORT QAccessibleTable2Interface: public QAccessible2Interface
class Q_GUI_EXPORT QAccessibleTable2Interface: public QAccessible2Interface
{
public:
inline QAccessible2Interface *qAccessibleTable2CastHelper() { return this; }
@ -326,7 +326,7 @@ friend class QAbstractItemView;
friend class QAbstractItemViewPrivate;
};
class Q_WIDGETS_EXPORT QAccessibleActionInterface : public QAccessible2Interface
class Q_GUI_EXPORT QAccessibleActionInterface : public QAccessible2Interface
{
public:
inline QAccessible2Interface *qAccessibleActionCastHelper() { return this; }
@ -339,7 +339,7 @@ public:
virtual QStringList keyBindings(int actionIndex) = 0;
};
class Q_WIDGETS_EXPORT QAccessibleImageInterface : public QAccessible2Interface
class Q_GUI_EXPORT QAccessibleImageInterface : public QAccessible2Interface
{
public:
inline QAccessible2Interface *qAccessibleImageCastHelper() { return this; }

View File

@ -63,7 +63,7 @@ public:
virtual void notifyAccessibilityUpdate(int, QAccessibleInterface*, int) = 0;
};
struct Q_WIDGETS_EXPORT QAccessibleBridgeFactoryInterface : public QFactoryInterface
struct Q_GUI_EXPORT QAccessibleBridgeFactoryInterface : public QFactoryInterface
{
virtual QAccessibleBridge *create(const QString& name) = 0;
};
@ -71,7 +71,7 @@ struct Q_WIDGETS_EXPORT QAccessibleBridgeFactoryInterface : public QFactoryInter
#define QAccessibleBridgeFactoryInterface_iid "com.trolltech.Qt.QAccessibleBridgeFactoryInterface"
Q_DECLARE_INTERFACE(QAccessibleBridgeFactoryInterface, QAccessibleBridgeFactoryInterface_iid)
class Q_WIDGETS_EXPORT QAccessibleBridgePlugin : public QObject, public QAccessibleBridgeFactoryInterface
class Q_GUI_EXPORT QAccessibleBridgePlugin : public QObject, public QAccessibleBridgeFactoryInterface
{
Q_OBJECT
Q_INTERFACES(QAccessibleBridgeFactoryInterface:QFactoryInterface)

View File

@ -43,11 +43,11 @@
#ifndef QT_NO_ACCESSIBILITY
#include "qapplication.h"
#include "qwidget.h"
#include <QtGui/QGuiApplication>
#include <QtGui/QWindow>
#include "qpointer.h"
#include "qmetaobject.h"
#include "qvarlengtharray.h"
QT_BEGIN_NAMESPACE
@ -208,15 +208,27 @@ QAccessibleApplication::QAccessibleApplication()
{
}
// all toplevel widgets except popups and the desktop
static QWidgetList topLevelWidgets()
QWindow *QAccessibleApplication::window() const
{
QWidgetList list;
const QWidgetList tlw(QApplication::topLevelWidgets());
// an application can have several windows, and AFAIK we don't need
// to notify about changes on the application.
return 0;
}
// all toplevel windows except popups and the desktop
static QObjectList topLevelObjects()
{
QObjectList list;
const QWindowList tlw(QGuiApplication::topLevelWindows());
for (int i = 0; i < tlw.count(); ++i) {
QWidget *w = tlw.at(i);
if (!(w->windowType() == Qt::Popup) && !(w->windowType() == Qt::Desktop))
list.append(w);
QWindow *w = tlw.at(i);
if (w->windowType() != Qt::Popup && w->windowType() != Qt::Desktop) {
if (QAccessibleInterface *root = w->accessibleRoot()) {
if (root->object())
list.append(w->accessibleRoot()->object());
delete root;
}
}
}
return list;
@ -225,17 +237,14 @@ static QWidgetList topLevelWidgets()
/*! \reimp */
int QAccessibleApplication::childCount() const
{
return topLevelWidgets().count();
return topLevelObjects().count();
}
/*! \reimp */
int QAccessibleApplication::indexOfChild(const QAccessibleInterface *child) const
{
if (!child->object()->isWidgetType())
return -1;
const QWidgetList tlw(topLevelWidgets());
int index = tlw.indexOf(static_cast<QWidget*>(child->object()));
const QObjectList tlw(topLevelObjects());
int index = tlw.indexOf(child->object());
if (index != -1)
++index;
return index;
@ -244,13 +253,14 @@ int QAccessibleApplication::indexOfChild(const QAccessibleInterface *child) cons
/*! \reimp */
int QAccessibleApplication::childAt(int x, int y) const
{
const QWidgetList tlw(topLevelWidgets());
for (int i = 0; i < tlw.count(); ++i) {
QWidget *w = tlw.at(i);
if (w->frameGeometry().contains(x,y))
for (int i = 0; i < childCount(); ++i) {
QAccessibleInterface *childIface = child(i);
QRect geom = childIface->rect();
if (geom.contains(x,y))
return i+1;
delete childIface;
}
return -1;
return rect().contains(x,y) ? 0 : -1;
}
/*! \reimp */
@ -270,17 +280,6 @@ QAccessible::Relation QAccessibleApplication::relationTo(int child, const
return Self;
}
QWidgetList tlw(topLevelWidgets());
if (tlw.contains(qobject_cast<QWidget*>(o)))
return Ancestor;
for (int i = 0; i < tlw.count(); ++i) {
QWidget *w = tlw.at(i);
QObjectList cl = w->findChildren<QObject *>(QString());
if (cl.contains(o))
return Ancestor;
}
return Unrelated;
}
@ -292,9 +291,9 @@ QAccessibleInterface *QAccessibleApplication::parent() const
QAccessibleInterface *QAccessibleApplication::child(int index) const
{
Q_ASSERT(index >= 0);
const QWidgetList tlw(topLevelWidgets());
if (index >= 0 && index < tlw.count())
return QAccessible::queryAccessibleInterface(tlw.at(index));
const QObjectList tlo(topLevelObjects());
if (index >= 0 && index < tlo.count())
return QAccessible::queryAccessibleInterface(tlo.at(index));
return 0;
}
@ -312,18 +311,12 @@ int QAccessibleApplication::navigate(RelationFlag relation, int entry,
case Self:
targetObject = object();
break;
case Child:
if (entry > 0 && entry <= childCount()) {
const QWidgetList tlw(topLevelWidgets());
if (tlw.count() >= entry)
targetObject = tlw.at(entry-1);
} else {
return -1;
}
break;
case FocusChild:
targetObject = QApplication::activeWindow();
targetObject = QGuiApplication::activeWindow();
break;
case Ancestor:
*target = parent();
return 0;
default:
break;
}
@ -336,9 +329,9 @@ QString QAccessibleApplication::text(Text t, int) const
{
switch (t) {
case Name:
return QApplication::applicationName();
return QGuiApplication::applicationName();
case Description:
return QApplication::applicationFilePath();
return QGuiApplication::applicationFilePath();
default:
break;
}
@ -354,7 +347,7 @@ QAccessible::Role QAccessibleApplication::role(int) const
/*! \reimp */
QAccessible::State QAccessibleApplication::state(int) const
{
return QApplication::activeWindow() ? Focused : Normal;
return QGuiApplication::activeWindow() ? Focused : Normal;
}
/*! \reimp */
@ -366,16 +359,19 @@ int QAccessibleApplication::userActionCount(int) const
/*! \reimp */
bool QAccessibleApplication::doAction(int action, int child, const QVariantList &param)
{
//###Move to IA2 action interface at some point to get rid of the ambiguity.
/* //### what is action == 0 and action == 1 ?????
if (action == 0 || action == 1) {
QWidget *w = 0;
w = QApplication::activeWindow();
QWindow *w = 0;
w = QGuiApplication::activeWindow();
if (!w)
w = topLevelWidgets().at(0);
w = topLevelWindows().at(0);
if (!w)
return false;
w->activateWindow();
w->requestActivateWindow();
return true;
}
*/
return QAccessibleObject::doAction(action, child, param);
}
@ -385,9 +381,9 @@ QString QAccessibleApplication::actionText(int action, Text text, int child) con
QString str;
if ((action == 0 || action == 1) && !child) switch (text) {
case Name:
return QApplication::tr("Activate");
return QGuiApplication::tr("Activate");
case Description:
return QApplication::tr("Activates the program's main window");
return QGuiApplication::tr("Activates the program's main window");
default:
break;
}

View File

@ -42,7 +42,7 @@
#ifndef QACCESSIBLEOBJECT_H
#define QACCESSIBLEOBJECT_H
#include <QtWidgets/qaccessible.h>
#include "qaccessible.h"
QT_BEGIN_HEADER
@ -55,7 +55,7 @@ QT_MODULE(Gui)
class QAccessibleObjectPrivate;
class QObject;
class Q_WIDGETS_EXPORT QAccessibleObject : public QAccessibleInterface
class Q_GUI_EXPORT QAccessibleObject : public QAccessibleInterface
{
public:
explicit QAccessibleObject(QObject *object);
@ -64,13 +64,13 @@ public:
QObject *object() const;
// properties
QRect rect(int child) const;
QRect rect(int child = 0) const;
void setText(Text t, int child, const QString &text);
// actions
int userActionCount(int child) const;
bool doAction(int action, int child, const QVariantList &params);
QString actionText(int action, Text t, int child) const;
int userActionCount(int child = 0) const;
bool doAction(int action, int child = 0, const QVariantList &params = QVariantList());
QString actionText(int action, Text t, int child = 0) const;
protected:
virtual ~QAccessibleObject();
@ -80,11 +80,12 @@ private:
Q_DISABLE_COPY(QAccessibleObject)
};
class Q_WIDGETS_EXPORT QAccessibleApplication : public QAccessibleObject
class Q_GUI_EXPORT QAccessibleApplication : public QAccessibleObject
{
public:
QAccessibleApplication();
QWindow *window() const;
// relations
int childCount() const;
int indexOfChild(const QAccessibleInterface*) const;
@ -97,14 +98,14 @@ public:
int navigate(RelationFlag, int, QAccessibleInterface **) const;
// properties and state
QString text(Text t, int child) const;
Role role(int child) const;
State state(int child) const;
QString text(Text t, int child = 0) const;
Role role(int child = 0) const;
State state(int child = 0) const;
// actions
int userActionCount(int child) const;
bool doAction(int action, int child, const QVariantList &params);
QString actionText(int action, Text t, int child) const;
int userActionCount(int child = 0) const;
bool doAction(int action, int child = 0, const QVariantList &params = QVariantList());
QString actionText(int action, Text t, int child = 0) const;
};
#endif // QT_NO_ACCESSIBILITY

View File

@ -39,10 +39,11 @@
**
****************************************************************************/
#include "qaccessibleplugin.h"
#include <QtCore/qglobal.h>
#ifndef QT_NO_ACCESSIBILITY
#include "qaccessibleplugin.h"
#include "qaccessible.h"
QT_BEGIN_NAMESPACE

View File

@ -42,7 +42,7 @@
#ifndef QACCESSIBLEPLUGIN_H
#define QACCESSIBLEPLUGIN_H
#include <QtWidgets/qaccessible.h>
#include "qaccessible.h"
#include <QtCore/qfactoryinterface.h>
QT_BEGIN_HEADER
@ -56,7 +56,7 @@ QT_MODULE(Gui)
class QStringList;
class QAccessibleInterface;
struct Q_WIDGETS_EXPORT QAccessibleFactoryInterface : public QAccessible, public QFactoryInterface
struct Q_GUI_EXPORT QAccessibleFactoryInterface : public QAccessible, public QFactoryInterface
{
virtual QAccessibleInterface* create(const QString &key, QObject *object) = 0;
};
@ -66,7 +66,7 @@ Q_DECLARE_INTERFACE(QAccessibleFactoryInterface, QAccessibleFactoryInterface_iid
class QAccessiblePluginPrivate;
class Q_WIDGETS_EXPORT QAccessiblePlugin : public QObject, public QAccessibleFactoryInterface
class Q_GUI_EXPORT QAccessiblePlugin : public QObject, public QAccessibleFactoryInterface
{
Q_OBJECT
Q_INTERFACES(QAccessibleFactoryInterface:QFactoryInterface)

View File

@ -38,64 +38,45 @@
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qaccessible.h"
#include "qplatformaccessibility_qpa.h"
#include <private/qfactoryloader_p.h>
#include "qaccessibleplugin.h"
#include "qaccessibleobject.h"
#include "qaccessiblebridge.h"
#include <QtGui/QGuiApplication>
#ifndef QT_NO_ACCESSIBILITY
#include "qcoreapplication.h"
#include "qmutex.h"
#include "qvector.h"
#include "private/qfactoryloader_p.h"
#include <stdlib.h>
QT_BEGIN_NAMESPACE
/* accessiblebridge plugin discovery stuff */
#ifndef QT_NO_LIBRARY
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, bridgeloader,
(QAccessibleBridgeFactoryInterface_iid, QLatin1String("/accessiblebridge")))
#endif
Q_GLOBAL_STATIC(QVector<QAccessibleBridge *>, bridges)
static bool isInit = false;
void QAccessible::initialize()
/*!
\class QPlatformAccessibility
\brief The QPlatformAccessibility class is the base class for
integrating accessibility backends
\preliminary
\ingroup accessibility
\sa QAccessible
*/
QPlatformAccessibility::QPlatformAccessibility()
{
if (isInit)
return;
isInit = true;
if (qgetenv("QT_ACCESSIBILITY") != "1")
return;
#ifndef QT_NO_LIBRARY
const QStringList l = loader()->keys();
for (int i = 0; i < l.count(); ++i) {
if (QAccessibleBridgeFactoryInterface *factory =
qobject_cast<QAccessibleBridgeFactoryInterface*>(loader()->instance(l.at(i)))) {
QAccessibleBridge * bridge = factory->create(l.at(i));
if (bridge)
bridges()->append(bridge);
}
}
#endif
}
void QAccessible::cleanup()
QPlatformAccessibility::~QPlatformAccessibility()
{
qDeleteAll(*bridges());
}
void QAccessible::updateAccessibility(QObject *o, int who, Event reason)
void QPlatformAccessibility::notifyAccessibilityUpdate(QObject *o,
int who,
QAccessible::Event reason)
{
Q_ASSERT(o);
if (updateHandler) {
updateHandler(o, who, reason);
return;
}
initialize();
if (!bridges() || bridges()->isEmpty())
return;
@ -117,15 +98,11 @@ void QAccessible::updateAccessibility(QObject *o, int who, Event reason)
for (int i = 0; i < bridges()->count(); ++i)
bridges()->at(i)->notifyAccessibilityUpdate(reason, iface, who);
delete iface;
}
void QAccessible::setRootObject(QObject *o)
void QPlatformAccessibility::setRootObject(QObject *o)
{
if (rootObjectHandler) {
rootObjectHandler(o);
return;
}
initialize();
if (bridges()->isEmpty())
return;
@ -139,7 +116,33 @@ void QAccessible::setRootObject(QObject *o)
}
}
QT_END_NAMESPACE
void QPlatformAccessibility::initialize()
{
static bool isInit = false;
if (isInit)
return;
isInit = true; // ### not atomic
#ifdef Q_OS_UNIX
if (qgetenv("QT_ACCESSIBILITY") != "1")
return;
#endif
#ifndef QT_NO_LIBRARY
const QStringList l = bridgeloader()->keys();
for (int i = 0; i < l.count(); ++i) {
if (QAccessibleBridgeFactoryInterface *factory =
qobject_cast<QAccessibleBridgeFactoryInterface*>(bridgeloader()->instance(l.at(i)))) {
QAccessibleBridge * bridge = factory->create(l.at(i));
if (bridge) {
bridges()->append(bridge);
#
}
}
}
#endif
}
#endif // QT_NO_ACCESSIBILITY
void QPlatformAccessibility::cleanup()
{
qDeleteAll(*bridges());
}

View File

@ -0,0 +1,74 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QPLATFORMACCESSIBILITY_H
#define QPLATFORMACCESSIBILITY_H
#include <QtCore/qobject.h>
#ifndef QT_NO_ACCESSIBILITY
#include "qaccessible.h"
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
class Q_GUI_EXPORT QPlatformAccessibility
{
public:
QPlatformAccessibility();
virtual ~QPlatformAccessibility();
virtual void notifyAccessibilityUpdate(QObject *o, int who, QAccessible::Event reason);
virtual void setRootObject(QObject *o);
virtual void initialize();
virtual void cleanup();
};
QT_END_NAMESPACE
QT_END_HEADER
#endif // QT_NO_ACCESSIBILITY
#endif // QPLATFORMACCESSIBILITY_H

View File

@ -15,6 +15,7 @@ load(qt_module_config)
HEADERS += $$QT_SOURCE_TREE/src/gui/qtguiversion.h
include(accessible/accessible.pri)
include(kernel/kernel.pri)
include(image/image.pri)
include(text/text.pri)

View File

@ -43,6 +43,7 @@
#include <QtGui/QPlatformFontDatabase>
#include <QtGui/QPlatformClipboard>
#include <QtGui/QPlatformAccessibility>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qpixmap_raster_p.h>
#include <private/qdnd_p.h>
@ -209,6 +210,16 @@ QPlatformInputContext *QPlatformIntegration::inputContext() const
return 0;
}
/*!
Returns the platforms accessibility.
The default implementation returns 0, implying no accessibility support.
*/
QPlatformAccessibility *QPlatformIntegration::accessibility() const
{
return new QPlatformAccessibility;
}
QVariant QPlatformIntegration::styleHint(StyleHint hint) const
{
switch (hint) {

View File

@ -67,6 +67,7 @@ class QMenu;
class QMenuBar;
class QPlatformMenu;
class QPlatformMenuBar;
class QPlatformAccessibility;
class Q_GUI_EXPORT QPlatformIntegration
{
@ -101,6 +102,7 @@ public:
virtual QPlatformMenu *createPlatformMenu(QMenu *menu = 0) const;
virtual QPlatformMenuBar *createPlatformMenuBar(QMenuBar *menuBar = 0) const;
virtual QPlatformAccessibility *accessibility() const;
// Access native handles. The window handle is already available from Wid;
virtual QPlatformNativeInterface *nativeInterface() const;

View File

@ -559,6 +559,8 @@ void QWindow::setScreen(QScreen *newScreen)
/*!
Returns the accessibility interface for the object that the window represents
\preliminary
\sa QAccessible
*/
QAccessibleInterface *QWindow::accessibleRoot() const
{

View File

@ -45,7 +45,7 @@
#include <QtCore/qpointer.h>
#include <QtWidgets/qaccessiblewidget.h>
#include <QtWidgets/qabstractitemview.h>
#include <QtWidgets/qaccessible2.h>
#include <QtGui/qaccessible2.h>
QT_BEGIN_NAMESPACE

View File

@ -44,8 +44,8 @@
#include <QtWidgets/qabstractitemview.h>
#include <QtWidgets/qheaderview.h>
#include <QtWidgets/qaccessible.h>
#include <QtWidgets/qaccessible2.h>
#include <QtGui/qaccessible.h>
#include <QtGui/qaccessible2.h>
#include <QtWidgets/qaccessiblewidget.h>

View File

@ -153,6 +153,7 @@ QStringList AccessibleFactory::keys() const
#ifndef QT_NO_DOCKWIDGET
list << QLatin1String("QDockWidget");
#endif
list << QLatin1String("QAccessibleWidget");
return list;
}
@ -348,6 +349,8 @@ QAccessibleInterface *AccessibleFactory::create(const QString &classname, QObjec
} else if (classname == QLatin1String("QDockWidget")) {
iface = new QAccessibleDockWidget(widget);
#endif
} else {
iface = new QAccessibleWidget(widget);
}
return iface;

View File

@ -42,7 +42,7 @@
#ifndef QACCESSIBLEWIDGETS_H
#define QACCESSIBLEWIDGETS_H
#include <QtWidgets/qaccessible2.h>
#include <QtGui/qaccessible2.h>
#include <QtWidgets/qaccessiblewidget.h>
#ifndef QT_NO_ACCESSIBILITY

View File

@ -43,7 +43,7 @@
#define RANGECONTROLS_H
#include <QtWidgets/qaccessiblewidget.h>
#include <QtWidgets/qaccessible2.h>
#include <QtGui/qaccessible2.h>
QT_BEGIN_NAMESPACE

View File

@ -43,7 +43,7 @@
#define SIMPLEWIDGETS_H
#include <QtCore/qcoreapplication.h>
#include <QtWidgets/qaccessible2.h>
#include <QtGui/qaccessible2.h>
#include <QtWidgets/qaccessiblewidget.h>
QT_BEGIN_NAMESPACE

View File

@ -88,6 +88,7 @@ enum WindowsEventType // Simplify event types
ClipboardEvent = ClipboardEventFlag + 1,
ActivateApplicationEvent = ApplicationEventFlag + 1,
DeactivateApplicationEvent = ApplicationEventFlag + 2,
AccessibleObjectFromWindowRequest = ApplicationEventFlag + 3,
InputMethodStartCompositionEvent = InputMethodEventFlag + 1,
InputMethodCompositionEvent = InputMethodEventFlag + 2,
InputMethodEndCompositionEvent = InputMethodEventFlag + 3,
@ -166,6 +167,8 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
default:
break;
}
case WM_GETOBJECT:
return QtWindows::AccessibleObjectFromWindowRequest;
default:
break;
}

View File

@ -4,7 +4,7 @@
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
@ -38,20 +38,32 @@
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qaccessible.h"
#include <QtCore/QtConfig>
#ifndef QT_NO_ACCESSIBILITY
#include "qapplication.h"
#include "qwindowsaccessibility.h"
#include "qwindowscontext.h"
#include <private/qsystemlibrary_p.h>
#include "qmessagebox.h" // ### dependency
#include "qt_windows.h"
#include "qwidget.h"
#include "qsettings.h"
#include <QtCore/qmap.h>
#include <QtCore/qsettings.h>
#include <QtCore/qpair.h>
#include <QtWidgets/qapplication.h>
#include <QtWidgets/qmessagebox.h>
#include <QtWidgets/qgraphicsitem.h>
#include <QtWidgets/qgraphicsscene.h>
#include <QtWidgets/qgraphicsview.h>
#include <QtGui/qaccessible.h>
#include <QtGui/qplatformnativeinterface_qpa.h>
#include <QtGui/qwindow.h>
#include "qt_windows.h"
//#include <uiautomationcoreapi.h>
#ifndef UiaRootObjectId
#define UiaRootObjectId -25
#endif
#include <winuser.h>
#if !defined(WINABLEAPI)
@ -255,9 +267,9 @@ static const char *eventString(QAccessible::Event ev)
void showDebug(const char* funcName, const QAccessibleInterface *iface)
{
qDebug() << "Role:" << roleString(iface->role(0))
<< "Name:" << iface->text(QAccessible::Name, 0)
<< "State:" << QString::number(int(iface->state(0)), 16)
qDebug() << "Role:" << roleString(iface->role(0))
<< "Name:" << iface->text(QAccessible::Name, 0)
<< "State:" << QString::number(int(iface->state(0)), 16)
<< QLatin1String(funcName);
}
#else
@ -269,229 +281,6 @@ typedef QMap<int, QPair<QObject*,int> > NotifyMap;
Q_GLOBAL_STATIC(NotifyMap, qAccessibleRecentSentEvents)
static int eventNum = 0;
void QAccessible::initialize()
{
}
void QAccessible::cleanup()
{
}
void QAccessible::updateAccessibility(QObject *o, int who, Event reason)
{
Q_ASSERT(o);
if (updateHandler) {
updateHandler(o, who, reason);
return;
}
QString soundName;
switch (reason) {
case PopupMenuStart:
soundName = QLatin1String("MenuPopup");
break;
case MenuCommand:
soundName = QLatin1String("MenuCommand");
break;
case Alert:
{
#ifndef QT_NO_MESSAGEBOX
QMessageBox *mb = qobject_cast<QMessageBox*>(o);
if (mb) {
switch (mb->icon()) {
case QMessageBox::Warning:
soundName = QLatin1String("SystemExclamation");
break;
case QMessageBox::Critical:
soundName = QLatin1String("SystemHand");
break;
case QMessageBox::Information:
soundName = QLatin1String("SystemAsterisk");
break;
default:
break;
}
} else
#endif // QT_NO_MESSAGEBOX
{
soundName = QLatin1String("SystemAsterisk");
}
}
break;
default:
break;
}
if (soundName.size()) {
#ifndef QT_NO_SETTINGS
QSettings settings(QLatin1String("HKEY_CURRENT_USER\\AppEvents\\Schemes\\Apps\\.Default\\") + soundName,
QSettings::NativeFormat);
QString file = settings.value(QLatin1String(".Current/.")).toString();
#else
QString file;
#endif
if (!file.isEmpty()) {
PlaySound(reinterpret_cast<const wchar_t *>(soundName.utf16()), 0, SND_ALIAS | SND_ASYNC | SND_NODEFAULT | SND_NOWAIT);
}
}
if (!isActive())
return;
typedef void (WINAPI *PtrNotifyWinEvent)(DWORD, HWND, LONG, LONG);
#if defined(Q_WS_WINCE) // ### TODO: check for NotifyWinEvent in CE 6.0
// There is no user32.lib nor NotifyWinEvent for CE
return;
#else
static PtrNotifyWinEvent ptrNotifyWinEvent = 0;
static bool resolvedNWE = false;
if (!resolvedNWE) {
resolvedNWE = true;
ptrNotifyWinEvent = (PtrNotifyWinEvent)QSystemLibrary::resolve(QLatin1String("user32"), "NotifyWinEvent");
}
if (!ptrNotifyWinEvent)
return;
// An event has to be associated with a window,
// so find the first parent that is a widget.
QWidget *w = 0;
QObject *p = o;
do {
if (p->isWidgetType()) {
w = static_cast<QWidget*>(p);
if (w->internalWinId())
break;
}
if (QGraphicsObject *gfxObj = qobject_cast<QGraphicsObject*>(p)) {
QGraphicsItem *parentItem = gfxObj->parentItem();
if (parentItem) {
p = parentItem->toGraphicsObject();
} else {
QGraphicsView *view = 0;
if (QGraphicsScene *scene = gfxObj->scene()) {
QWidget *fw = QApplication::focusWidget();
const QList<QGraphicsView*> views = scene->views();
for (int i = 0 ; i < views.count() && view != fw; ++i) {
view = views.at(i);
}
}
p = view;
}
} else {
p = p->parent();
}
} while (p);
//qDebug() << "updateAccessibility(), hwnd:" << w << ", object:" << o << "," << eventString(reason);
if (!w) {
if (reason != QAccessible::ContextHelpStart &&
reason != QAccessible::ContextHelpEnd)
w = QApplication::focusWidget();
if (!w) {
w = QApplication::activeWindow();
if (!w)
return;
// ### Fixme
// if (!w) {
// w = qApp->mainWidget();
// if (!w)
// return;
// }
}
}
WId wid = w->internalWinId();
if (reason != MenuCommand) { // MenuCommand is faked
if (w != o) {
// See comment "SENDING EVENTS TO OBJECTS WITH NO WINDOW HANDLE"
eventNum %= 50; //[0..49]
int eventId = - eventNum - 1;
qAccessibleRecentSentEvents()->insert(eventId, qMakePair(o,who));
ptrNotifyWinEvent(reason, wid, OBJID_CLIENT, eventId );
++eventNum;
} else {
ptrNotifyWinEvent(reason, wid, OBJID_CLIENT, who);
}
}
#endif // Q_WS_WINCE
}
/* == SENDING EVENTS TO OBJECTS WITH NO WINDOW HANDLE ==
If the user requested to send the event to a widget with no window,
we need to send an event to an object with no hwnd.
The way we do that is to send it to the *first* ancestor widget
with a window.
Then we'll need a way of identifying the child:
We'll just keep a list of the most recent events that we have sent,
where each entry in the list is identified by a negative value
between [-50,-1]. This negative value we will pass on to
NotifyWinEvent() as the child id. When the negative value have
reached -50, it will wrap around to -1. This seems to be enough
Now, when the client receives that event, he will first call
AccessibleObjectFromEvent() where dwChildID is the special
negative value. AccessibleObjectFromEvent does two steps:
1. It will first sent a WM_GETOBJECT to the server, asking
for the IAccessible interface for the HWND.
2. With the IAccessible interface it got hold of it will call
acc_getChild where the child id argument is the special
negative identifier. In our reimplementation of get_accChild
we check for this if the child id is negative. If it is, then
we'll look up in our table for the entry that is associated
with that value.
The entry will then contain a pointer to the QObject /QWidget
that we can use to call queryAccessibleInterface() on.
The following figure shows how the interaction between server and
client is in the case when the server is sending an event.
SERVER (Qt) | CLIENT |
--------------------------------------------+---------------------------------------+
|
acc->updateAccessibility(obj, childIndex) |
|
recentEvents()->insert(- 1 - eventNum, |
qMakePair(obj, childIndex) |
NotifyWinEvent(hwnd, childId) => |
| AccessibleObjectFromEvent(event, hwnd, OBJID_CLIENT, childId )
| will do:
<=== 1. send WM_GETOBJECT(hwnd, OBJID_CLIENT)
widget ~= hwnd
iface = queryAccessibleInteface(widget)
(create IAccessible interface wrapper for
iface)
return iface ===> IAccessible* iface; (for hwnd)
|
<=== call iface->get_accChild(childId)
get_accChild() { |
if (varChildID.lVal < 0) {
QPair ref = recentEvents().value(varChildID.lVal);
[...]
}
*/
void QAccessible::setRootObject(QObject *o)
{
if (rootObjectHandler) {
rootObjectHandler(o);
}
}
class QWindowsEnumerate : public IEnumVARIANT
{
public:
@ -674,14 +463,6 @@ static inline BSTR QStringToBSTR(const QString &str)
/*
*/
IAccessible *qt_createWindowsAccessible(QAccessibleInterface *access)
{
QWindowsAccessible *acc = new QWindowsAccessible(access);
IAccessible *iface;
acc->QueryInterface(IID_IAccessible, (void**)&iface);
return iface;
}
/*
IUnknown
@ -742,45 +523,45 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetIDsOfNames(const _GUID &, wchar
// PROPERTIES: Hierarchical
if (_bstr_t(rgszNames[0]) == _bstr_t(L"accParent"))
rgdispid[0] = DISPID_ACC_PARENT;
else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accChildCount"))
else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accChildCount"))
rgdispid[0] = DISPID_ACC_CHILDCOUNT;
else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accChild"))
else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accChild"))
rgdispid[0] = DISPID_ACC_CHILD;
// PROPERTIES: Descriptional
else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accName("))
else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accName("))
rgdispid[0] = DISPID_ACC_NAME;
else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accValue"))
else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accValue"))
rgdispid[0] = DISPID_ACC_VALUE;
else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accDescription"))
else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accDescription"))
rgdispid[0] = DISPID_ACC_DESCRIPTION;
else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accRole"))
else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accRole"))
rgdispid[0] = DISPID_ACC_ROLE;
else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accState"))
else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accState"))
rgdispid[0] = DISPID_ACC_STATE;
else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accHelp"))
else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accHelp"))
rgdispid[0] = DISPID_ACC_HELP;
else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accHelpTopic"))
else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accHelpTopic"))
rgdispid[0] = DISPID_ACC_HELPTOPIC;
else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accKeyboardShortcut"))
else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accKeyboardShortcut"))
rgdispid[0] = DISPID_ACC_KEYBOARDSHORTCUT;
else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accFocus"))
else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accFocus"))
rgdispid[0] = DISPID_ACC_FOCUS;
else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accSelection"))
else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accSelection"))
rgdispid[0] = DISPID_ACC_SELECTION;
else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accDefaultAction"))
else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accDefaultAction"))
rgdispid[0] = DISPID_ACC_DEFAULTACTION;
// METHODS
else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accSelect"))
else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accSelect"))
rgdispid[0] = DISPID_ACC_SELECT;
else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accLocation"))
else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accLocation"))
rgdispid[0] = DISPID_ACC_LOCATION;
else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accNavigate"))
else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accNavigate"))
rgdispid[0] = DISPID_ACC_NAVIGATE;
else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accHitTest"))
else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accHitTest"))
rgdispid[0] = DISPID_ACC_HITTEST;
else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accDoDefaultAction"))
else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accDoDefaultAction"))
rgdispid[0] = DISPID_ACC_DODEFAULTACTION;
else
return DISP_E_UNKNOWNINTERFACE;
@ -798,7 +579,7 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::Invoke(long dispIdMember, const _G
{
HRESULT hr = DISP_E_MEMBERNOTFOUND;
switch(dispIdMember)
switch (dispIdMember)
{
case DISPID_ACC_PARENT:
if (wFlags == DISPATCH_PROPERTYGET) {
@ -1021,7 +802,7 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::accNavigate(long navDir, VARIANT v
QAccessibleInterface *acc = 0;
int control = -1;
switch(navDir) {
switch (navDir) {
case NAVDIR_FIRSTCHILD:
control = accessible->navigate(Child, 1, &acc);
break;
@ -1422,11 +1203,27 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetWindow(HWND *phwnd)
return E_UNEXPECTED;
QObject *o = accessible->object();
if (!o || !o->isWidgetType())
QWindow *window = qobject_cast<QWindow*>(o);
if (!window)
window = QGuiApplication::topLevelWindows().first();
Q_ASSERT(window);
if (!o || !window)
return E_FAIL;
#ifdef Q_WS_QPA
//QPlatformNativeInterface *platform = QGuiApplication::platformNativeInterface();
//Q_ASSERT(platform);
//*phwnd = (HWND)platform->nativeResourceForWindow("handle", window);
return S_OK;
#else
*phwnd = static_cast<QWidget*>(o)->effectiveWinId();
return S_OK;
#endif
}
HRESULT STDMETHODCALLTYPE QWindowsAccessible::ContextSensitiveHelp(BOOL)
@ -1434,6 +1231,176 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::ContextSensitiveHelp(BOOL)
return S_OK;
}
QWindowsAccessibility::QWindowsAccessibility()
{
}
void QWindowsAccessibility::notifyAccessibilityUpdate(QObject *o, int who, QAccessible::Event reason)
{
QString soundName;
switch (reason) {
case QAccessible::PopupMenuStart:
soundName = QLatin1String("MenuPopup");
break;
case QAccessible::MenuCommand:
soundName = QLatin1String("MenuCommand");
break;
case QAccessible::Alert:
{
/* ### FIXME
#ifndef QT_NO_MESSAGEBOX
QMessageBox *mb = qobject_cast<QMessageBox*>(o);
if (mb) {
switch (mb->icon()) {
case QMessageBox::Warning:
soundName = QLatin1String("SystemExclamation");
break;
case QMessageBox::Critical:
soundName = QLatin1String("SystemHand");
break;
case QMessageBox::Information:
soundName = QLatin1String("SystemAsterisk");
break;
default:
break;
}
} else
#endif // QT_NO_MESSAGEBOX
*/
{
soundName = QLatin1String("SystemAsterisk");
}
}
break;
default:
break;
}
if (!soundName.isEmpty()) {
#ifndef QT_NO_SETTINGS
QSettings settings(QLatin1String("HKEY_CURRENT_USER\\AppEvents\\Schemes\\Apps\\.Default\\") + soundName,
QSettings::NativeFormat);
QString file = settings.value(QLatin1String(".Current/.")).toString();
#else
QString file;
#endif
if (!file.isEmpty()) {
PlaySound(reinterpret_cast<const wchar_t *>(soundName.utf16()), 0, SND_ALIAS | SND_ASYNC | SND_NODEFAULT | SND_NOWAIT);
}
}
typedef void (WINAPI *PtrNotifyWinEvent)(DWORD, HWND, LONG, LONG);
#if defined(Q_WS_WINCE) // ### TODO: check for NotifyWinEvent in CE 6.0
// There is no user32.lib nor NotifyWinEvent for CE
return;
#else
static PtrNotifyWinEvent ptrNotifyWinEvent = 0;
static bool resolvedNWE = false;
if (!resolvedNWE) {
resolvedNWE = true;
ptrNotifyWinEvent = (PtrNotifyWinEvent)QSystemLibrary::resolve(QLatin1String("user32"), "NotifyWinEvent");
}
if (!ptrNotifyWinEvent)
return;
// An event has to be associated with a window,
// so find the first parent that is a widget and that has a WId
QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(o);
QWindow *window = iface->window();
if (!window) {
window = QGuiApplication::activeWindow();
if (!window)
return;
}
QPlatformNativeInterface *platform = QGuiApplication::platformNativeInterface();
HWND hWnd = (HWND)platform->nativeResourceForWindow("handle", window);
if (reason != QAccessible::MenuCommand) { // MenuCommand is faked
// See comment "SENDING EVENTS TO OBJECTS WITH NO WINDOW HANDLE"
eventNum %= 50; //[0..49]
int eventId = - eventNum - 1;
qAccessibleRecentSentEvents()->insert(eventId, qMakePair(o, who));
ptrNotifyWinEvent(reason, hWnd, OBJID_CLIENT, eventId );
++eventNum;
}
#endif // Q_WS_WINCE
}
/*
void QWindowsAccessibility::setRootObject(QObject *o)
{
}
void QWindowsAccessibility::initialize()
{
}
void QWindowsAccessibility::cleanup()
{
}
*/
bool QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
{
if (static_cast<long>(lParam) == static_cast<long>(UiaRootObjectId)) {
/* For UI Automation
*/
} else if ((DWORD)lParam == OBJID_CLIENT) {
#if 1
// Ignoring all requests while starting up
// ### Maybe QPA takes care of this???
if (QApplication::startingUp() || QApplication::closingDown())
return false;
#endif
typedef LRESULT (WINAPI *PtrLresultFromObject)(REFIID, WPARAM, LPUNKNOWN);
static PtrLresultFromObject ptrLresultFromObject = 0;
static bool oleaccChecked = false;
if (!oleaccChecked) {
oleaccChecked = true;
#if !defined(Q_OS_WINCE)
ptrLresultFromObject = (PtrLresultFromObject)QSystemLibrary::resolve(QLatin1String("oleacc"), "LresultFromObject");
#endif
}
if (ptrLresultFromObject) {
QWindow *window = QWindowsContext::instance()->findWindow(hwnd);
if (window) {
QAccessibleInterface *acc = window->accessibleRoot();
if (acc) {
QWindowsAccessible *winacc = new QWindowsAccessible(acc);
IAccessible *iface;
HRESULT hr = winacc->QueryInterface(IID_IAccessible, (void**)&iface);
if (SUCCEEDED(hr)) {
*lResult = ptrLresultFromObject(IID_IAccessible, wParam, iface); // ref == 2
if (*lResult) {
iface->Release(); // the client will release the object again, and then it will destroy itself
}
return true;
}
}
}
}
}
return false;
}
QT_END_NAMESPACE
#endif // QT_NO_ACCESSIBILITY
#endif //QT_NO_ACCESSIBILITY

View File

@ -0,0 +1,61 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QWINDOWSACCESSIBILITY_H
#define QWINDOWSACCESSIBILITY_H
#include <QtGui/QPlatformAccessibility>
#include <OleAcc.h>
class QWindowsAccessibility : public QPlatformAccessibility
{
public:
QWindowsAccessibility();
static bool handleAccessibleObjectFromWindowRequest(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT *lResult);
virtual void notifyAccessibilityUpdate(QObject *o, int who, QAccessible::Event reason);
/*
virtual void setRootObject(QObject *o);
virtual void initialize();
virtual void cleanup();
*/
};
#endif // QWINDOWSACCESSIBILITY_H

View File

@ -47,6 +47,7 @@
#include "qtwindowsglobal.h"
#include "qwindowsmime.h"
#include "qwindowsinputcontext.h"
#include "qwindowsaccessibility.h"
#include <QtGui/QWindow>
#include <QtGui/QWindowSystemInterface>
@ -623,6 +624,8 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::UnknownEvent:
return false;
case QtWindows::AccessibleObjectFromWindowRequest:
return QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(hwnd, wParam, lParam, result);
default:
break;
}

View File

@ -50,6 +50,7 @@
#include "qwindowsclipboard.h"
#include "qwindowsdrag.h"
#include "qwindowsinputcontext.h"
#include "qwindowsaccessibility.h"
#include <QtGui/QPlatformNativeInterface>
#include <QtGui/QWindowSystemInterface>
@ -138,6 +139,7 @@ struct QWindowsIntegrationPrivate
QWindowsGuiEventDispatcher *m_eventDispatcher;
QOpenGLStaticContextPtr m_staticOpenGLContext;
QWindowsInputContext m_inputContext;
QWindowsAccessibility m_accessibility;
};
QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(bool openGL)
@ -258,6 +260,11 @@ QPlatformInputContext * QWindowsIntegration::inputContext() const
return &d->m_inputContext;
}
QPlatformAccessibility *QWindowsIntegration::accessibility() const
{
return &d->m_accessibility;
}
QWindowsIntegration *QWindowsIntegration::instance()
{
return static_cast<QWindowsIntegration *>(QGuiApplicationPrivate::platformIntegration());

View File

@ -66,6 +66,7 @@ public:
virtual QPlatformClipboard *clipboard() const;
virtual QPlatformDrag *drag() const;
virtual QPlatformInputContext *inputContext() const;
virtual QPlatformAccessibility *accessibility() const;
virtual QPlatformNativeInterface *nativeInterface() const;
virtual QPlatformFontDatabase *fontDatabase() const;

View File

@ -8,7 +8,7 @@ INCLUDEPATH += ../../../3rdparty/harfbuzz/src
QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms
# Note: OpenGL32 must precede Gdi32 as it overwrites some functions.
LIBS *= -lOpenGL32 -lGdi32 -lUser32 -lOle32 -lWinspool -lImm32
LIBS *= -lOpenGL32 -lGdi32 -lUser32 -lOle32 -lWinspool -lImm32 -lWinmm
win32-g++: LIBS *= -luuid
contains(QT_CONFIG, directwrite) {
@ -39,7 +39,8 @@ SOURCES += \
qwindowsdrag.cpp \
qwindowscursor.cpp \
pixmaputils.cpp \
qwindowsinputcontext.cpp
qwindowsinputcontext.cpp \
qwindowsaccessibility.cpp
HEADERS += \
qwindowsnativeimage.h \
@ -64,7 +65,8 @@ HEADERS += \
qwindowscursor.h \
pixmaputils.h \
array.h \
qwindowsinputcontext.h
qwindowsinputcontext.h \
qwindowsaccessibility.h
target.path += $$[QT_INSTALL_PLUGINS]/platforms
INSTALLS += target

View File

@ -53,8 +53,8 @@
QVERIFY(QTestAccessibility::verifyEvent(object, child, (int)event))
#include <QtCore/qlist.h>
#include <QtWidgets/qaccessible.h>
#include <QtWidgets/qapplication.h>
#include <QtGui/qaccessible.h>
#include <QtGui/qguiapplication.h>
QT_BEGIN_HEADER
@ -127,9 +127,9 @@ private:
{
// qDebug("rootObjectHandler called %p", object);
if (object) {
QApplication* app = qobject_cast<QApplication*>(object);
QGuiApplication* app = qobject_cast<QGuiApplication*>(object);
if ( !app )
qWarning("%s: root Object is not a QApplication!", Q_FUNC_INFO);
qWarning("%s: root Object is not a QGuiApplication!", Q_FUNC_INFO);
} else {
qWarning("%s: root Object called with 0 pointer", Q_FUNC_INFO);
}

View File

@ -1,25 +1,6 @@
# Qt accessibility module
contains(QT_CONFIG, accessibility) {
HEADERS += accessible/qaccessible.h \
accessible/qaccessible2.h \
accessible/qaccessibleobject.h \
accessible/qaccessiblewidget.h \
accessible/qaccessibleplugin.h
SOURCES += accessible/qaccessible.cpp \
accessible/qaccessible2.cpp \
accessible/qaccessibleobject.cpp \
accessible/qaccessiblewidget.cpp \
accessible/qaccessibleplugin.cpp
mac:!qpa {
HEADERS += accessible/qaccessible_mac_p.h
OBJECTIVE_SOURCES += accessible/qaccessible_mac.mm \
accessible/qaccessible_mac_cocoa.mm
} else:win32:!qpa {
SOURCES += accessible/qaccessible_win.cpp
} else {
HEADERS += accessible/qaccessiblebridge.h
SOURCES += accessible/qaccessible_unix.cpp accessible/qaccessiblebridge.cpp
}
HEADERS += accessible/qaccessiblewidget.h
SOURCES += accessible/qaccessiblewidget.cpp
}

View File

@ -187,6 +187,11 @@ QAccessibleWidget::QAccessibleWidget(QWidget *w, Role role, const QString &name)
d->asking = 0;
}
QWindow *QAccessibleWidget::window() const
{
return widget()->windowHandle();
}
/*!
Destroys this object.
*/

View File

@ -42,7 +42,7 @@
#ifndef QACCESSIBLEWIDGET_H
#define QACCESSIBLEWIDGET_H
#include <QtWidgets/qaccessibleobject.h>
#include <QtGui/qaccessibleobject.h>
QT_BEGIN_HEADER
@ -59,25 +59,26 @@ class Q_WIDGETS_EXPORT QAccessibleWidget : public QAccessibleObject
public:
explicit QAccessibleWidget(QWidget *o, Role r = Client, const QString& name = QString());
QWindow *window() const;
int childCount() const;
int indexOfChild(const QAccessibleInterface *child) const;
Relation relationTo(int child, const QAccessibleInterface *other, int otherChild) const;
int childAt(int x, int y) const;
QRect rect(int child) const;
QRect rect(int child = 0) const;
QAccessibleInterface *parent() const;
QAccessibleInterface *child(int index) const;
int navigate(RelationFlag rel, int entry, QAccessibleInterface **target) const;
QString text(Text t, int child) const;
Role role(int child) const;
State state(int child) const;
QString text(Text t, int child = 0) const;
Role role(int child = 0) const;
State state(int child = 0) const;
#ifndef QT_NO_ACTION
int userActionCount(int child) const;
QString actionText(int action, Text t, int child) const;
bool doAction(int action, int child, const QVariantList &params);
int userActionCount(int child = 0) const;
QString actionText(int action, Text t, int child = 0) const;
bool doAction(int action, int child = 0, const QVariantList &params = QVariantList());
#endif
QVariant invokeMethod(Method method, int child, const QVariantList &params);

View File

@ -53,7 +53,7 @@
#include <QtWidgets/qgridlayout.h>
#include <QtWidgets/qdesktopwidget.h>
#include <QtWidgets/qpushbutton.h>
#include <QtWidgets/qaccessible.h>
#include <QtGui/qaccessible.h>
#include <QtWidgets/qicon.h>
#include <QtGui/qtextdocument.h>
#include <QtWidgets/qapplication.h>

View File

@ -246,7 +246,7 @@
#include <QtGui/qinputpanel.h>
#include <QtWidgets/qgraphicseffect.h>
#ifndef QT_NO_ACCESSIBILITY
# include <QtWidgets/qaccessible.h>
# include <QtGui/qaccessible.h>
#endif
#include <private/qapplication_p.h>
#include <private/qobject_p.h>

View File

@ -43,6 +43,7 @@
#include "private/qwidget_p.h"
#include "private/qapplication_p.h"
#include <QtGui/qaccessible.h>
QT_BEGIN_NAMESPACE
@ -59,6 +60,13 @@ QWidgetWindow::QWidgetWindow(QWidget *widget)
{
}
QAccessibleInterface *QWidgetWindow::accessibleRoot() const
{
if (m_widget)
return QAccessible::queryAccessibleInterface(m_widget);
return 0;
}
bool QWidgetWindow::event(QEvent *event)
{
switch (event->type()) {

View File

@ -63,6 +63,7 @@ public:
QWidgetWindow(QWidget *widget);
QWidget *widget() const { return m_widget; }
QAccessibleInterface *accessibleRoot() const;
protected:
bool event(QEvent *);

View File

@ -64,7 +64,6 @@
#include "QtGui/qclipboard.h"
#include "QtCore/qpoint.h"
#include "QtWidgets/qcompleter.h"
#include "QtWidgets/qaccessible.h"
#include "QtCore/qthread.h"
#include "qplatformdefs.h"

View File

@ -353,7 +353,7 @@ class QtTestAccessibleWidgetIface: public QAccessibleWidget
{
public:
QtTestAccessibleWidgetIface(QtTestAccessibleWidget *w): QAccessibleWidget(w) {}
QString text(Text t, int control) const
QString text(Text t, int control = 0) const
{
if (t == Help)
return QString::fromLatin1("Help yourself");