Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqnxbuttoneventnotifier.cpp
Go to the documentation of this file.
1// Copyright (C) 2012 Research In Motion
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
7#include <QtGui/QGuiApplication>
8#include <qpa/qwindowsysteminterface.h>
9
10#include <QtCore/qhash.h>
11#include <QtCore/qbytearray.h>
12#include <QtCore/QDebug>
13#include <QtCore/QMetaEnum>
14#include <QtCore/QSocketNotifier>
15#include <QtCore/private/qcore_unix_p.h>
16
18
19Q_LOGGING_CATEGORY(lcQpaInputHwButton, "qt.qpa.input.hwbutton");
20
21const char *QQnxButtonEventNotifier::ppsPath = "/pps/system/buttons/status";
22const size_t QQnxButtonEventNotifier::ppsBufferSize = 256;
23
25 : QObject(parent),
26 m_fd(-1),
27 m_readNotifier(0)
28{
29 // Set initial state of buttons to ButtonUp and
30 // fetch the new button ids
31 int enumeratorIndex = QQnxButtonEventNotifier::staticMetaObject.indexOfEnumerator(QByteArrayLiteral("ButtonId"));
32 QMetaEnum enumerator = QQnxButtonEventNotifier::staticMetaObject.enumerator(enumeratorIndex);
33 m_buttonKeys.reserve(ButtonCount - bid_minus);
34 for (int buttonId = bid_minus; buttonId < ButtonCount; ++buttonId) {
35 m_buttonKeys.append(enumerator.valueToKey(buttonId));
36 m_state[buttonId] = ButtonUp;
37 }
38}
39
44
46{
47 qCDebug(lcQpaInputHwButton) << "Starting hardware button event processing";
48 if (m_fd != -1)
49 return;
50
51 // Open the pps interface
52 errno = 0;
53 m_fd = qt_safe_open(ppsPath, O_RDONLY);
54 if (m_fd == -1) {
55#if defined (QQNXBUTTON_DEBUG)
56 qWarning("QQNX: failed to open buttons pps, errno=%d", errno);
57#endif
58 return;
59 }
60
61 m_readNotifier = new QSocketNotifier(m_fd, QSocketNotifier::Read);
62 QObject::connect(m_readNotifier, SIGNAL(activated(QSocketDescriptor)), this, SLOT(updateButtonStates()));
63
64 qCDebug(lcQpaInputHwButton, "successfully connected to Navigator. fd = %d", m_fd);
65}
66
67void QQnxButtonEventNotifier::updateButtonStates()
68{
69 // Allocate buffer for pps data
70 char buffer[ppsBufferSize];
71
72 // Attempt to read pps data
73 errno = 0;
74 int bytes = qt_safe_read(m_fd, buffer, ppsBufferSize - 1);
75 qCDebug(lcQpaInputHwButton) << "Read" << bytes << "bytes of data";
76
77 if (bytes == -1) {
78 qWarning("QQNX: failed to read hardware buttons pps object, errno=%d", errno);
79 return;
80 }
81
82 // We seem to get a spurious read notification after the real one. Ignore it
83 if (bytes == 0)
84 return;
85
86 // Ensure data is null terminated
87 buffer[bytes] = '\0';
88
89 qCDebug(lcQpaInputHwButton, "Received PPS message:\n%s", buffer);
90
91 // Process received message
92 QByteArray ppsData = QByteArray::fromRawData(buffer, bytes);
93 QHash<QByteArray, QByteArray> fields;
94 if (!parsePPS(ppsData, &fields))
95 return;
96
97 // Update our state and inject key events as needed
98 for (int buttonId = bid_minus; buttonId < ButtonCount; ++buttonId) {
99 // Extract the new button state
100 QByteArray key = m_buttonKeys.at(buttonId);
101 ButtonState newState = (fields.value(key) == "b_up" ? ButtonUp : ButtonDown);
102
103 // If state has changed, update our state and inject a keypress event
104 if (m_state[buttonId] != newState) {
105 qCDebug(lcQpaInputHwButton) << "Hardware button event: button =" << key << "state =" << fields.value(key);
106
107 m_state[buttonId] = newState;
108
109 // Is it a key press or key release event?
110 QEvent::Type type = (newState == ButtonDown) ? QEvent::KeyPress : QEvent::KeyRelease;
111
112 Qt::Key key;
113 switch (buttonId) {
114 case bid_minus:
115 key = Qt::Key_VolumeDown;
116 break;
117
118 case bid_playpause:
119 key = Qt::Key_Play;
120 break;
121
122 case bid_plus:
123 key = Qt::Key_VolumeUp;
124 break;
125
126 case bid_power:
127 key = Qt::Key_PowerDown;
128 break;
129
130 default:
131 qCDebug(lcQpaInputHwButton) << "Unknown hardware button";
132 continue;
133 }
134
135 // No modifiers
136 Qt::KeyboardModifiers modifier = Qt::NoModifier;
137
138 // Post the event
139 QWindowSystemInterface::handleKeyEvent(QGuiApplication::focusWindow(), type, key, modifier);
140 }
141 }
142}
143
144void QQnxButtonEventNotifier::close()
145{
146 delete m_readNotifier;
147 m_readNotifier = 0;
148
149 if (m_fd != -1) {
150 qt_safe_close(m_fd);
151 m_fd = -1;
152 }
153}
154
155bool QQnxButtonEventNotifier::parsePPS(const QByteArray &ppsData, QHash<QByteArray, QByteArray> *messageFields) const
156{
157 // tokenize pps data into lines
158 QList<QByteArray> lines = ppsData.split('\n');
159
160 // validate pps object
161 if (lines.size() == 0 || !lines.at(0).contains(QByteArrayLiteral("@status"))) {
162 qWarning("QQNX: unrecognized pps object, data=%s", ppsData.constData());
163 return false;
164 }
165
166 // parse pps object attributes and extract values
167 for (int i = 1; i < lines.size(); i++) {
168
169 // tokenize current attribute
170 const QByteArray &attr = lines.at(i);
171
172 qCDebug(lcQpaInputHwButton) << Q_FUNC_INFO << "attr =" << attr;
173
174 int doubleColon = attr.indexOf(QByteArrayLiteral("::"));
175 if (doubleColon == -1) {
176 // abort - malformed attribute
177 continue;
178 }
179
180 QByteArray key = attr.left(doubleColon);
181 QByteArray value = attr.mid(doubleColon + 2);
182 messageFields->insert(key, value);
183 }
184 return true;
185}
186
187QT_END_NAMESPACE
QQnxButtonEventNotifier(QObject *parent=nullptr)
Combined button and popup list for selecting options.