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