Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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#if __has_include(<xcb/xproto.h>)
16#include <xcb/xproto.h>
17#endif
18
19//#define KEYBOARD_DEBUG
20
22
23using namespace Qt::Literals::StringLiterals;
24
35 : QObject(parent), dbusConnection(connection)
36{
37}
38
39enum QSpiKeyEventType {
40 QSPI_KEY_EVENT_PRESS,
41 QSPI_KEY_EVENT_RELEASE,
42 QSPI_KEY_EVENT_LAST_DEFINED
43};
44
46{
47 if (active) {
48 qApp->installEventFilter(this);
49 } else {
50 qApp->removeEventFilter(this);
51 }
52}
53
54
56{
57 if (!event->spontaneous())
58 return false;
59
60 switch (event->type()) {
63 break;
66 break;
68 case QEvent::KeyRelease: {
69 QKeyEvent *keyEvent = static_cast <QKeyEvent *>(event);
71
72 if (event->type() == QEvent::KeyPress)
73 de.type = QSPI_KEY_EVENT_PRESS;
74 else
75 de.type = QSPI_KEY_EVENT_RELEASE;
76
77 de.id = keyEvent->nativeVirtualKey();
78 de.hardwareCode = keyEvent->nativeScanCode();
79
80 de.timestamp = QDateTime::currentMSecsSinceEpoch();
81
82 if (keyEvent->key() == Qt::Key_Tab)
83 de.text = QStringLiteral("Tab");
84 else if (keyEvent->key() == Qt::Key_Backtab)
85 de.text = QStringLiteral("Backtab");
86 else if (keyEvent->key() == Qt::Key_Control)
87 de.text = QStringLiteral("Control_L");
88 else if (keyEvent->key() == Qt::Key_Left)
89 de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Left") : QStringLiteral("Left");
90 else if (keyEvent->key() == Qt::Key_Right)
91 de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Right") : QStringLiteral("Right");
92 else if (keyEvent->key() == Qt::Key_Up)
93 de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Up") : QStringLiteral("Up");
94 else if (keyEvent->key() == Qt::Key_Down)
95 de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Down") : QStringLiteral("Down");
96 else if (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return)
97 de.text = QStringLiteral("Return");
98 else if (keyEvent->key() == Qt::Key_Backspace)
99 de.text = QStringLiteral("BackSpace");
100 else if (keyEvent->key() == Qt::Key_Delete)
101 de.text = QStringLiteral("Delete");
102 else if (keyEvent->key() == Qt::Key_PageUp)
103 de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Page_Up") : QStringLiteral("Page_Up");
104 else if (keyEvent->key() == Qt::Key_PageDown)
105 de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Page_Up") : QStringLiteral("Page_Down");
106 else if (keyEvent->key() == Qt::Key_Home)
107 de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_Home") : QStringLiteral("Home");
108 else if (keyEvent->key() == Qt::Key_End)
109 de.text = (keyEvent->modifiers() & Qt::KeypadModifier) ? QStringLiteral("KP_End") : QStringLiteral("End");
110 else if (keyEvent->key() == Qt::Key_Clear && (keyEvent->modifiers() & Qt::KeypadModifier))
111 de.text = QStringLiteral("KP_Begin"); // Key pad 5
112 else if (keyEvent->key() == Qt::Key_Escape)
113 de.text = QStringLiteral("Escape");
114 else if (keyEvent->key() == Qt::Key_Space)
115 de.text = QStringLiteral("space");
116 else if (keyEvent->key() == Qt::Key_CapsLock)
117 de.text = QStringLiteral("Caps_Lock");
118 else if (keyEvent->key() == Qt::Key_NumLock)
119 de.text = QStringLiteral("Num_Lock");
120 else if (keyEvent->key() == Qt::Key_Insert)
121 de.text = QStringLiteral("Insert");
122 else
123 de.text = keyEvent->text();
124
125 // This is a bit dubious, Gnome uses some gtk function here.
126 // Long term the spec will hopefully change to just use keycodes.
127 de.isText = !de.text.isEmpty();
128
129 de.modifiers = 0;
130 if ((keyEvent->modifiers() & Qt::ShiftModifier) && (keyEvent->key() != Qt::Key_Shift))
131 de.modifiers |= 1 << ATSPI_MODIFIER_SHIFT;
132#ifdef XCB_MOD_MASK_LOCK
134 // TODO rather introduce Qt::CapslockModifier into KeyboardModifier
135 if (keyEvent->nativeModifiers() & XCB_MOD_MASK_LOCK )
136 de.modifiers |= 1 << ATSPI_MODIFIER_SHIFTLOCK;
137 }
138#endif
139 if ((keyEvent->modifiers() & Qt::ControlModifier) && (keyEvent->key() != Qt::Key_Control))
140 de.modifiers |= 1 << ATSPI_MODIFIER_CONTROL;
141 if ((keyEvent->modifiers() & Qt::AltModifier) && (keyEvent->key() != Qt::Key_Alt))
142 de.modifiers |= 1 << ATSPI_MODIFIER_ALT;
143 if ((keyEvent->modifiers() & Qt::MetaModifier) && (keyEvent->key() != Qt::Key_Meta))
144 de.modifiers |= 1 << ATSPI_MODIFIER_META;
145
146#ifdef KEYBOARD_DEBUG
147 qDebug() << "Key event text:" << event->type() << de.text
148 << "native virtual key:" << de.id
149 << "hardware code/scancode:" << de.hardwareCode
150 << "modifiers:" << de.modifiers
151 << "text:" << de.text;
152#endif
153
154 QDBusMessage m = QDBusMessage::createMethodCall(QStringLiteral("org.a11y.atspi.Registry"),
155 QStringLiteral("/org/a11y/atspi/registry/deviceeventcontroller"),
156 QStringLiteral("org.a11y.atspi.DeviceEventController"), QStringLiteral("NotifyListenersSync"));
157 m.setArguments(QVariantList() << QVariant::fromValue(de));
158
159 // FIXME: this is critical, the timeout should probably be pretty low to allow normal processing
160 int timeout = 100;
161 bool sent = dbusConnection.callWithCallback(m, this, SLOT(notifyKeyboardListenerCallback(QDBusMessage)),
162 SLOT(notifyKeyboardListenerError(QDBusError,QDBusMessage)), timeout);
163 if (sent) {
164 //queue the event and send it after callback
165 keyEvents.enqueue(QPair<QPointer<QObject>, QKeyEvent*> (QPointer<QObject>(target), copyKeyEvent(keyEvent)));
166 return true;
167 }
168 }
169 default:
170 break;
171 }
172 return false;
173}
174
175QKeyEvent* QSpiApplicationAdaptor::copyKeyEvent(QKeyEvent* old)
176{
177 return new QKeyEvent(old->type(), old->key(), old->modifiers(),
178 old->nativeScanCode(), old->nativeVirtualKey(), old->nativeModifiers(),
179 old->text(), old->isAutoRepeat(), old->count());
180}
181
182void QSpiApplicationAdaptor::notifyKeyboardListenerCallback(const QDBusMessage& message)
183{
184 if (!keyEvents.size()) {
185 qWarning("QSpiApplication::notifyKeyboardListenerCallback with no queued key called");
186 return;
187 }
188 Q_ASSERT(message.arguments().size() == 1);
189 if (message.arguments().at(0).toBool() == true) {
190 QPair<QPointer<QObject>, QKeyEvent*> event = keyEvents.dequeue();
191 delete event.second;
192 } else {
193 QPair<QPointer<QObject>, QKeyEvent*> event = keyEvents.dequeue();
194 if (event.first)
195 QCoreApplication::postEvent(event.first.data(), event.second);
196 }
197}
198
199void QSpiApplicationAdaptor::notifyKeyboardListenerError(const QDBusError& error, const QDBusMessage& /*message*/)
200{
201 qWarning() << "QSpiApplication::keyEventError " << error.name() << error.message();
202 while (!keyEvents.isEmpty()) {
203 QPair<QPointer<QObject>, QKeyEvent*> event = keyEvents.dequeue();
204 if (event.first)
205 QCoreApplication::postEvent(event.first.data(), event.second);
206 }
207}
208
210
211#include "moc_qspiapplicationadaptor_p.cpp"
212
213#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:304
QString platformName
The name of the underlying platform plugin.
The QKeyEvent class describes a key event.
Definition qevent.h:424
int count() const
Returns the number of keys involved in this event.
Definition qevent.h:445
Qt::KeyboardModifiers modifiers() const
Returns the keyboard modifier flags that existed immediately after the event occurred.
Definition qevent.cpp:1468
quint32 nativeScanCode() const
Definition qevent.h:447
QString text() const
Returns the Unicode text that this key generated.
Definition qevent.h:443
quint32 nativeVirtualKey() const
Definition qevent.h:448
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:444
quint32 nativeModifiers() const
Definition qevent.h:449
int key() const
Returns the code of the key that was pressed or released.
Definition qevent.h:434
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
\inmodule QtCore
Definition qobject.h:103
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 noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
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:536
Combined button and popup list for selecting options.
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool startsWith(QByteArrayView haystack, QByteArrayView needle) noexcept
@ Key_Escape
Definition qnamespace.h:663
@ Key_Tab
Definition qnamespace.h:664
@ Key_Shift
Definition qnamespace.h:683
@ Key_Return
Definition qnamespace.h:667
@ Key_Right
Definition qnamespace.h:679
@ Key_Enter
Definition qnamespace.h:668
@ Key_PageUp
Definition qnamespace.h:681
@ Key_Space
Definition qnamespace.h:513
@ Key_Backspace
Definition qnamespace.h:666
@ Key_Backtab
Definition qnamespace.h:665
@ Key_Insert
Definition qnamespace.h:669
@ Key_Left
Definition qnamespace.h:677
@ Key_Control
Definition qnamespace.h:684
@ Key_Alt
Definition qnamespace.h:686
@ Key_Up
Definition qnamespace.h:678
@ Key_Down
Definition qnamespace.h:680
@ Key_Delete
Definition qnamespace.h:670
@ Key_NumLock
Definition qnamespace.h:688
@ Key_Meta
Definition qnamespace.h:685
@ Key_PageDown
Definition qnamespace.h:682
@ Key_Home
Definition qnamespace.h:675
@ Key_Clear
Definition qnamespace.h:674
@ Key_CapsLock
Definition qnamespace.h:687
@ Key_End
Definition qnamespace.h:676
@ 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:164
#define qWarning
Definition qlogging.h:166
#define SLOT(a)
Definition qobjectdefs.h:52
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