diff options
author | Frederik Gladhorn <frederik.gladhorn@nokia.com> | 2012-05-10 23:52:05 +0200 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-08-14 01:40:06 +0200 |
commit | 8e1ff45e74f529c7f49688242ea0fd25ce2913f3 (patch) | |
tree | ae13e233a4b9da58d2f4cf5ae0b733e86fe0d5a9 /src/platformsupport/linuxaccessibility/application.cpp | |
parent | 85b624a969c2674f726b6e80af1418bdd9f91969 (diff) |
Add Linux Accessibility Bridge
This is a plugin that bridges the QAccessible world
to AT-SPI 2 on Linux.
Change-Id: I7af22621ee6a3cefc723b137b7f227a611cf6641
Reviewed-by: Jan-Arve Sæther <jan-arve.saether@nokia.com>
Diffstat (limited to 'src/platformsupport/linuxaccessibility/application.cpp')
-rw-r--r-- | src/platformsupport/linuxaccessibility/application.cpp | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/src/platformsupport/linuxaccessibility/application.cpp b/src/platformsupport/linuxaccessibility/application.cpp new file mode 100644 index 0000000000..84f5cef625 --- /dev/null +++ b/src/platformsupport/linuxaccessibility/application.cpp @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** 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$ +** +****************************************************************************/ + + +#include "application_p.h" + +#include <QtWidgets/qapplication.h> +#include <QtDBus/qdbuspendingreply.h> +#include <qdebug.h> + +#include "deviceeventcontroller_adaptor.h" + +//#define KEYBOARD_DEBUG + +QT_BEGIN_NAMESPACE + +/*! + \class QSpiApplicationAdaptor + + \brief QSpiApplicationAdaptor + + QSpiApplicationAdaptor +*/ + +QSpiApplicationAdaptor::QSpiApplicationAdaptor(const QDBusConnection &connection, QObject *parent) + : QObject(parent), dbusConnection(connection) +{ +} + +enum QSpiKeyEventType { + QSPI_KEY_EVENT_PRESS, + QSPI_KEY_EVENT_RELEASE, + QSPI_KEY_EVENT_LAST_DEFINED +}; + +void QSpiApplicationAdaptor::sendEvents(bool active) +{ + if (active) { + qApp->installEventFilter(this); + } else { + qApp->removeEventFilter(this); + } +} + + +bool QSpiApplicationAdaptor::eventFilter(QObject *target, QEvent *event) +{ + if (!event->spontaneous()) + return false; + + switch (event->type()) { + case QEvent::WindowActivate: + emit windowActivated(target, true); + break; + case QEvent::WindowDeactivate: + emit windowActivated(target, false); + break; + case QEvent::KeyPress: + case QEvent::KeyRelease: { + QKeyEvent *keyEvent = static_cast <QKeyEvent *>(event); + QSpiDeviceEvent de; + + if (event->type() == QEvent::KeyPress) + de.type = QSPI_KEY_EVENT_PRESS; + else + de.type = QSPI_KEY_EVENT_RELEASE; + + de.id = keyEvent->nativeVirtualKey(); + de.hardwareCode = keyEvent->nativeScanCode(); + + de.modifiers = keyEvent->nativeModifiers(); + de.timestamp = QDateTime::currentMSecsSinceEpoch(); + + if (keyEvent->key() == Qt::Key_Tab) + de.text = QStringLiteral("Tab"); + else if (keyEvent->key() == Qt::Key_Backtab) + de.text = QStringLiteral("Backtab"); + else if (keyEvent->key() == Qt::Key_Left) + de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Left") : QStringLiteral("Left"); + else if (keyEvent->key() == Qt::Key_Right) + de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Right") : QStringLiteral("Right"); + else if (keyEvent->key() == Qt::Key_Up) + de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Up") : QStringLiteral("Up"); + else if (keyEvent->key() == Qt::Key_Down) + de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Down") : QStringLiteral("Down"); + else if (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return) + de.text = QStringLiteral("Return"); + else if (keyEvent->key() == Qt::Key_Backspace) + de.text = QStringLiteral("BackSpace"); + else if (keyEvent->key() == Qt::Key_Delete) + de.text = QStringLiteral("Delete"); + else if (keyEvent->key() == Qt::Key_PageUp) + de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Page_Up") : QStringLiteral("Page_Up"); + else if (keyEvent->key() == Qt::Key_PageDown) + de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Page_Up") : QStringLiteral("Page_Down"); + else if (keyEvent->key() == Qt::Key_Home) + de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Home") : QStringLiteral("Home"); + else if (keyEvent->key() == Qt::Key_End) + de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_End") : QStringLiteral("End"); + else if (keyEvent->key() == Qt::Key_Clear && (keyEvent->modifiers() & Qt::KeypadModifier)) + de.text = QStringLiteral("KP_Begin"); // Key pad 5 + else if (keyEvent->key() == Qt::Key_Escape) + de.text = QStringLiteral("Escape"); + else if (keyEvent->key() == Qt::Key_Space) + de.text = QStringLiteral("space"); + else if (keyEvent->key() == Qt::Key_CapsLock) + de.text = QStringLiteral("Caps_Lock"); + else if (keyEvent->key() == Qt::Key_NumLock) + de.text = QStringLiteral("Num_Lock"); + else if (keyEvent->key() == Qt::Key_Insert) + de.text = QStringLiteral("Insert"); + else + de.text = keyEvent->text(); + + // This is a bit dubious, Gnome uses some gtk function here. + // Long term the spec will hopefully change to just use keycodes. + de.isText = !de.text.isEmpty(); + +#ifdef KEYBOARD_DEBUG + qDebug() << QStringLiteral("Key event text: ") << event->type() << de.isText << QStringLiteral(" ") << de.text + << QStringLiteral(" hardware code: ") << de.hardwareCode + << QStringLiteral(" native sc: ") << keyEvent->nativeScanCode() + << QStringLiteral(" native mod: ") << keyEvent->nativeModifiers() + << QStringLiteral("native virt: ") << keyEvent->nativeVirtualKey(); +#endif + + QDBusMessage m = QDBusMessage::createMethodCall(QStringLiteral("org.a11y.atspi.Registry"), + QStringLiteral("/org/a11y/atspi/registry/deviceeventcontroller"), + QStringLiteral("org.a11y.atspi.DeviceEventController"), QStringLiteral("NotifyListenersSync")); + m.setArguments(QVariantList() <<QVariant::fromValue(de)); + + // FIXME: this is critical, the timeout should probably be pretty low to allow normal processing + int timeout = 100; + bool sent = dbusConnection.callWithCallback(m, this, SLOT(notifyKeyboardListenerCallback(QDBusMessage)), + SLOT(notifyKeyboardListenerError(QDBusError, QDBusMessage)), timeout); + if (sent) { + //queue the event and send it after callback + keyEvents.enqueue(QPair<QObject*, QKeyEvent*> (target, copyKeyEvent(keyEvent))); +#ifdef KEYBOARD_DEBUG + qDebug() << QStringLiteral("Sent key: ") << de.text; +#endif + return true; + } + } + default: + break; + } + return false; +} + +QKeyEvent* QSpiApplicationAdaptor::copyKeyEvent(QKeyEvent* old) +{ + return new QKeyEvent(old->type(), old->key(), old->modifiers(), old->text(), old->isAutoRepeat(), old->count()); +} + +void QSpiApplicationAdaptor::notifyKeyboardListenerCallback(const QDBusMessage& message) +{ + if (!keyEvents.length()) { + qWarning() << QStringLiteral("QSpiApplication::notifyKeyboardListenerCallback with no queued key called"); + return; + } + Q_ASSERT(message.arguments().length() == 1); + if (message.arguments().at(0).toBool() == true) { + QPair<QObject*, QKeyEvent*> event = keyEvents.dequeue(); + delete event.second; + } else { + QPair<QObject*, QKeyEvent*> event = keyEvents.dequeue(); + QApplication::postEvent(event.first, event.second); + } +} + +void QSpiApplicationAdaptor::notifyKeyboardListenerError(const QDBusError& error, const QDBusMessage& /*message*/) +{ + qWarning() << QStringLiteral("QSpiApplication::keyEventError ") << error.name() << error.message(); + while (!keyEvents.isEmpty()) { + QPair<QObject*, QKeyEvent*> event = keyEvents.dequeue(); + QApplication::postEvent(event.first, event.second); + } +} + +QT_END_NAMESPACE |