Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qspiapplicationadaptor.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4
6
7#include <QtCore/qcoreapplication.h>
8#include <QtDBus/qdbuspendingreply.h>
9#include <qdebug.h>
10
11#if QT_CONFIG(accessibility)
12#include "deviceeventcontroller_adaptor.h"
13#include "atspi/atspi-constants.h"
14
15#include <xcb/xproto.h>
16
17//#define KEYBOARD_DEBUG
18
20
31 : QObject(parent), dbusConnection(connection)
32{
33}
34
35enum QSpiKeyEventType {
36 QSPI_KEY_EVENT_PRESS,
37 QSPI_KEY_EVENT_RELEASE,
38 QSPI_KEY_EVENT_LAST_DEFINED
39};
40
42{
43 if (active) {
44 qApp->installEventFilter(this);
45 } else {
46 qApp->removeEventFilter(this);
47 }
48}
49
50
52{
53 if (!event->spontaneous())
54 return false;
55
56 switch (event->type()) {
59 break;
62 break;
64 case QEvent::KeyRelease: {
65 QKeyEvent *keyEvent = static_cast <QKeyEvent *>(event);
67
68 if (event->type() == QEvent::KeyPress)
69 de.type = QSPI_KEY_EVENT_PRESS;
70 else
71 de.type = QSPI_KEY_EVENT_RELEASE;
72
73 de.id = keyEvent->nativeVirtualKey();
74 de.hardwareCode = keyEvent->nativeScanCode();
75
77
78 if (keyEvent->key() == Qt::Key_Tab)
79 de.text = QStringLiteral("Tab");
80 else if (keyEvent->key() == Qt::Key_Backtab)
81 de.text = QStringLiteral("Backtab");
82 else if (keyEvent->key() == Qt::Key_Control)
83 de.text = QStringLiteral("Control_L");
84 else if (keyEvent->key() == Qt::Key_Left)
85 de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Left") : QStringLiteral("Left");
86 else if (keyEvent->key() == Qt::Key_Right)
87 de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Right") : QStringLiteral("Right");
88 else if (keyEvent->key() == Qt::Key_Up)
89 de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Up") : QStringLiteral("Up");
90 else if (keyEvent->key() == Qt::Key_Down)
91 de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Down") : QStringLiteral("Down");
92 else if (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return)
93 de.text = QStringLiteral("Return");
94 else if (keyEvent->key() == Qt::Key_Backspace)
95 de.text = QStringLiteral("BackSpace");
96 else if (keyEvent->key() == Qt::Key_Delete)
97 de.text = QStringLiteral("Delete");
98 else if (keyEvent->key() == Qt::Key_PageUp)
99 de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Page_Up") : QStringLiteral("Page_Up");
100 else if (keyEvent->key() == Qt::Key_PageDown)
101 de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Page_Up") : QStringLiteral("Page_Down");
102 else if (keyEvent->key() == Qt::Key_Home)
103 de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Home") : QStringLiteral("Home");
104 else if (keyEvent->key() == Qt::Key_End)
105 de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_End") : QStringLiteral("End");
106 else if (keyEvent->key() == Qt::Key_Clear && (keyEvent->modifiers() & Qt::KeypadModifier))
107 de.text = QStringLiteral("KP_Begin"); // Key pad 5
108 else if (keyEvent->key() == Qt::Key_Escape)
109 de.text = QStringLiteral("Escape");
110 else if (keyEvent->key() == Qt::Key_Space)
111 de.text = QStringLiteral("space");
112 else if (keyEvent->key() == Qt::Key_CapsLock)
113 de.text = QStringLiteral("Caps_Lock");
114 else if (keyEvent->key() == Qt::Key_NumLock)
115 de.text = QStringLiteral("Num_Lock");
116 else if (keyEvent->key() == Qt::Key_Insert)
117 de.text = QStringLiteral("Insert");
118 else
119 de.text = keyEvent->text();
120
121 // This is a bit dubious, Gnome uses some gtk function here.
122 // Long term the spec will hopefully change to just use keycodes.
123 de.isText = !de.text.isEmpty();
124
125 de.modifiers = 0;
126 if ((keyEvent->modifiers() & Qt::ShiftModifier) && (keyEvent->key() != Qt::Key_Shift))
127 de.modifiers |= 1 << ATSPI_MODIFIER_SHIFT;
128 // TODO rather introduce Qt::CapslockModifier into KeyboardModifier
129 if (keyEvent->nativeModifiers() & XCB_MOD_MASK_LOCK )
130 de.modifiers |= 1 << ATSPI_MODIFIER_SHIFTLOCK;
131 if ((keyEvent->modifiers() & Qt::ControlModifier) && (keyEvent->key() != Qt::Key_Control))
132 de.modifiers |= 1 << ATSPI_MODIFIER_CONTROL;
133 if ((keyEvent->modifiers() & Qt::AltModifier) && (keyEvent->key() != Qt::Key_Alt))
134 de.modifiers |= 1 << ATSPI_MODIFIER_ALT;
135 if ((keyEvent->modifiers() & Qt::MetaModifier) && (keyEvent->key() != Qt::Key_Meta))
136 de.modifiers |= 1 << ATSPI_MODIFIER_META;
137
138#ifdef KEYBOARD_DEBUG
139 qDebug() << "Key event text:" << event->type() << de.text
140 << "native virtual key:" << de.id
141 << "hardware code/scancode:" << de.hardwareCode
142 << "modifiers:" << de.modifiers
143 << "text:" << de.text;
144#endif
145
146 QDBusMessage m = QDBusMessage::createMethodCall(QStringLiteral("org.a11y.atspi.Registry"),
147 QStringLiteral("/org/a11y/atspi/registry/deviceeventcontroller"),
148 QStringLiteral("org.a11y.atspi.DeviceEventController"), QStringLiteral("NotifyListenersSync"));
149 m.setArguments(QVariantList() << QVariant::fromValue(de));
150
151 // FIXME: this is critical, the timeout should probably be pretty low to allow normal processing
152 int timeout = 100;
153 bool sent = dbusConnection.callWithCallback(m, this, SLOT(notifyKeyboardListenerCallback(QDBusMessage)),
154 SLOT(notifyKeyboardListenerError(QDBusError,QDBusMessage)), timeout);
155 if (sent) {
156 //queue the event and send it after callback
157 keyEvents.enqueue(QPair<QPointer<QObject>, QKeyEvent*> (QPointer<QObject>(target), copyKeyEvent(keyEvent)));
158 return true;
159 }
160 }
161 default:
162 break;
163 }
164 return false;
165}
166
167QKeyEvent* QSpiApplicationAdaptor::copyKeyEvent(QKeyEvent* old)
168{
169 return new QKeyEvent(old->type(), old->key(), old->modifiers(),
170 old->nativeScanCode(), old->nativeVirtualKey(), old->nativeModifiers(),
171 old->text(), old->isAutoRepeat(), old->count());
172}
173
174void QSpiApplicationAdaptor::notifyKeyboardListenerCallback(const QDBusMessage& message)
175{
176 if (!keyEvents.size()) {
177 qWarning("QSpiApplication::notifyKeyboardListenerCallback with no queued key called");
178 return;
179 }
180 Q_ASSERT(message.arguments().size() == 1);
181 if (message.arguments().at(0).toBool() == true) {
182 QPair<QPointer<QObject>, QKeyEvent*> event = keyEvents.dequeue();
183 delete event.second;
184 } else {
185 QPair<QPointer<QObject>, QKeyEvent*> event = keyEvents.dequeue();
186 if (event.first)
187 QCoreApplication::postEvent(event.first.data(), event.second);
188 }
189}
190
191void QSpiApplicationAdaptor::notifyKeyboardListenerError(const QDBusError& error, const QDBusMessage& /*message*/)
192{
193 qWarning() << "QSpiApplication::keyEventError " << error.name() << error.message();
194 while (!keyEvents.isEmpty()) {
195 QPair<QPointer<QObject>, QKeyEvent*> event = keyEvents.dequeue();
196 if (event.first)
197 QCoreApplication::postEvent(event.first.data(), event.second);
198 }
199}
200
202
203#include "moc_qspiapplicationadaptor_p.cpp"
204
205#endif // QT_CONFIG(accessibility)
static void postEvent(QObject *receiver, QEvent *event, int priority=Qt::NormalEventPriority)
\inmodule QtDBus
bool callWithCallback(const QDBusMessage &message, QObject *receiver, const char *returnMethod, const char *errorMethod, int timeout=-1) const
Sends the message over this connection and returns immediately.
\inmodule QtDBus
Definition qdbuserror.h:21
\inmodule QtDBus
static QDBusMessage createMethodCall(const QString &destination, const QString &path, const QString &interface, const QString &method)
Constructs a new DBus message representing a method call.
static qint64 currentMSecsSinceEpoch() noexcept
\inmodule QtCore
Definition qcoreevent.h:45
@ KeyRelease
Definition qcoreevent.h:65
@ KeyPress
Definition qcoreevent.h:64
@ WindowActivate
Definition qcoreevent.h:83
@ WindowDeactivate
Definition qcoreevent.h:84
Type type() const
Returns the event type.
Definition qcoreevent.h:299
The QKeyEvent class describes a key event.
Definition qevent.h:423
int count() const
Returns the number of keys involved in this event.
Definition qevent.h:444
Qt::KeyboardModifiers modifiers() const
Returns the keyboard modifier flags that existed immediately after the event occurred.
Definition qevent.cpp:1465
quint32 nativeScanCode() const
Definition qevent.h:446
QString text() const
Returns the Unicode text that this key generated.
Definition qevent.h:442
quint32 nativeVirtualKey() const
Definition qevent.h:447
bool isAutoRepeat() const
Returns true if this event comes from an auto-repeating key; returns false if it comes from an initia...
Definition qevent.h:443
quint32 nativeModifiers() const
Definition qevent.h:448
int key() const
Returns the code of the key that was pressed or released.
Definition qevent.h:433
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
\inmodule QtCore
Definition qobject.h:90
\inmodule QtCore
Definition qpointer.h:18
void enqueue(const T &t)
Adds value t to the tail of the queue.
Definition qqueue.h:18
T dequeue()
Removes the head item in the queue and returns it.
Definition qqueue.h:19
QSpiApplicationAdaptor(const QDBusConnection &connection, QObject *parent)
bool eventFilter(QObject *obj, QEvent *event) override
Filters events if this object has been installed as an event filter for the watched object.
void sendEvents(bool active)
void windowActivated(QObject *window, bool active)
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:531
Combined button and popup list for selecting options.
@ Key_Escape
Definition qnamespace.h:658
@ Key_Tab
Definition qnamespace.h:659
@ Key_Shift
Definition qnamespace.h:678
@ Key_Return
Definition qnamespace.h:662
@ Key_Right
Definition qnamespace.h:674
@ Key_Enter
Definition qnamespace.h:663
@ Key_PageUp
Definition qnamespace.h:676
@ Key_Space
Definition qnamespace.h:512
@ Key_Backspace
Definition qnamespace.h:661
@ Key_Backtab
Definition qnamespace.h:660
@ Key_Insert
Definition qnamespace.h:664
@ Key_Left
Definition qnamespace.h:672
@ Key_Control
Definition qnamespace.h:679
@ Key_Alt
Definition qnamespace.h:681
@ Key_Up
Definition qnamespace.h:673
@ Key_Down
Definition qnamespace.h:675
@ Key_Delete
Definition qnamespace.h:665
@ Key_NumLock
Definition qnamespace.h:683
@ Key_Meta
Definition qnamespace.h:680
@ Key_PageDown
Definition qnamespace.h:677
@ Key_Home
Definition qnamespace.h:670
@ Key_Clear
Definition qnamespace.h:669
@ Key_CapsLock
Definition qnamespace.h:682
@ Key_End
Definition qnamespace.h:671
@ ShiftModifier
@ ControlModifier
@ MetaModifier
@ KeypadModifier
@ AltModifier
std::pair< T1, T2 > QPair
#define qApp
DBusConnection const char DBusError * error
DBusConnection * connection
QList< QVariant > QVariantList
Definition qjsonarray.h:15
#define qDebug
[1]
Definition qlogging.h:160
#define qWarning
Definition qlogging.h:162
#define SLOT(a)
Definition qobjectdefs.h:51
const GLfloat * m
GLbitfield GLuint64 timeout
[4]
GLenum target
GLuint GLsizei const GLchar * message
struct _cl_event * event
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QStringLiteral(str)
#define emit
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent