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
qlibinputhandler.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
8
9#include <libudev.h>
10#include <libinput.h>
11#include <QtCore/QLoggingCategory>
12#include <QtCore/QSocketNotifier>
13#include <QtCore/private/qcore_unix_p.h>
14#include <private/qguiapplication_p.h>
15#include <private/qinputdevicemanager_p_p.h>
16
18
19Q_LOGGING_CATEGORY(qLcLibInput, "qt.qpa.input")
20
21static int liOpen(const char *path, int flags, void *user_data)
22{
23 Q_UNUSED(user_data);
24 return qt_safe_open(path, flags);
25}
26
27static void liClose(int fd, void *user_data)
28{
29 Q_UNUSED(user_data);
30 qt_safe_close(fd);
31}
32
33static const struct libinput_interface liInterface = {
34 liOpen,
36};
37
38static void liLogHandler(libinput *libinput, libinput_log_priority priority, const char *format, va_list args)
39{
40 Q_UNUSED(libinput);
41 Q_UNUSED(priority);
42
43 char buf[512];
44 int n = vsnprintf(buf, sizeof(buf), format, args);
45 if (n > 0) {
46 // vsnprintf() returns the length the output would have had, not the
47 // length written, so clamp before indexing to strip a trailing newline.
48 n = qMin(n, int(sizeof(buf)) - 1);
49 if (buf[n - 1] == '\n')
50 buf[n - 1] = '\0';
51 qCDebug(qLcLibInput, "libinput: %s", buf);
52 }
53}
54
55QLibInputHandler::QLibInputHandler(const QString &key, const QString &spec)
56{
57 Q_UNUSED(key);
58 Q_UNUSED(spec);
59
60 m_udev = udev_new();
61 if (Q_UNLIKELY(!m_udev))
62 qFatal("Failed to get udev context for libinput");
63
64 m_li = libinput_udev_create_context(&liInterface, nullptr, m_udev);
65 if (Q_UNLIKELY(!m_li))
66 qFatal("Failed to get libinput context");
67
68 libinput_log_set_handler(m_li, liLogHandler);
69 if (qLcLibInput().isDebugEnabled())
70 libinput_log_set_priority(m_li, LIBINPUT_LOG_PRIORITY_DEBUG);
71
72 if (Q_UNLIKELY(libinput_udev_assign_seat(m_li, "seat0")))
73 qFatal("Failed to assign seat");
74
75 m_liFd = libinput_get_fd(m_li);
76 m_notifier.reset(new QSocketNotifier(m_liFd, QSocketNotifier::Read));
77
78 connect(m_notifier.data(), &QSocketNotifier::activated, this, &QLibInputHandler::onReadyRead);
79
80 m_pointer.reset(new QLibInputPointer);
81 m_keyboard.reset(new QLibInputKeyboard);
82 m_touch.reset(new QLibInputTouch);
83
84 QInputDeviceManager *manager = QGuiApplicationPrivate::inputDeviceManager();
85 connect(manager, &QInputDeviceManager::cursorPositionChangeRequested, this, [this](const QPoint &pos) {
86 m_pointer->setPos(pos);
87 });
88
89 // Process the initial burst of DEVICE_ADDED events.
91}
92
94{
95 if (m_li)
96 libinput_unref(m_li);
97
98 if (m_udev)
99 udev_unref(m_udev);
100}
101
103{
104 if (libinput_dispatch(m_li)) {
105 qWarning("libinput_dispatch failed");
106 return;
107 }
108
109 libinput_event *ev;
110 while ((ev = libinput_get_event(m_li)) != nullptr) {
111 processEvent(ev);
112 libinput_event_destroy(ev);
113 }
114}
115
116void QLibInputHandler::processEvent(libinput_event *ev)
117{
118 libinput_event_type type = libinput_event_get_type(ev);
119 libinput_device *dev = libinput_event_get_device(ev);
120
121 switch (type) {
122 case LIBINPUT_EVENT_DEVICE_ADDED:
123 {
124 // This is not just for hotplugging, it is also called for each input
125 // device libinput reads from on startup. Hence it is suitable for doing
126 // touch device registration.
127 QInputDeviceManagerPrivate *inputManagerPriv = QInputDeviceManagerPrivate::get(
128 QGuiApplicationPrivate::inputDeviceManager());
129 if (libinput_device_has_capability(dev, LIBINPUT_DEVICE_CAP_TOUCH)) {
130 m_touch->registerDevice(dev);
131 int &count(m_devCount[QInputDeviceManager::DeviceTypeTouch]);
132 ++count;
133 inputManagerPriv->setDeviceCount(QInputDeviceManager::DeviceTypeTouch, count);
134 }
135 if (libinput_device_has_capability(dev, LIBINPUT_DEVICE_CAP_POINTER)) {
136 int &count(m_devCount[QInputDeviceManager::DeviceTypePointer]);
137 ++count;
138 inputManagerPriv->setDeviceCount(QInputDeviceManager::DeviceTypePointer, count);
139 }
140 if (libinput_device_has_capability(dev, LIBINPUT_DEVICE_CAP_KEYBOARD)) {
141 int &count(m_devCount[QInputDeviceManager::DeviceTypeKeyboard]);
142 ++count;
143 inputManagerPriv->setDeviceCount(QInputDeviceManager::DeviceTypeKeyboard, count);
144 }
145 break;
146 }
147 case LIBINPUT_EVENT_DEVICE_REMOVED:
148 {
149 QInputDeviceManagerPrivate *inputManagerPriv = QInputDeviceManagerPrivate::get(
150 QGuiApplicationPrivate::inputDeviceManager());
151 if (libinput_device_has_capability(dev, LIBINPUT_DEVICE_CAP_TOUCH)) {
152 m_touch->unregisterDevice(dev);
153 int &count(m_devCount[QInputDeviceManager::DeviceTypeTouch]);
154 --count;
155 inputManagerPriv->setDeviceCount(QInputDeviceManager::DeviceTypeTouch, count);
156 }
157 if (libinput_device_has_capability(dev, LIBINPUT_DEVICE_CAP_POINTER)) {
158 int &count(m_devCount[QInputDeviceManager::DeviceTypePointer]);
159 --count;
160 inputManagerPriv->setDeviceCount(QInputDeviceManager::DeviceTypePointer, count);
161 }
162 if (libinput_device_has_capability(dev, LIBINPUT_DEVICE_CAP_KEYBOARD)) {
163 int &count(m_devCount[QInputDeviceManager::DeviceTypeKeyboard]);
164 --count;
165 inputManagerPriv->setDeviceCount(QInputDeviceManager::DeviceTypeKeyboard, count);
166 }
167 break;
168 }
169 case LIBINPUT_EVENT_POINTER_BUTTON:
170 m_pointer->processButton(libinput_event_get_pointer_event(ev));
171 break;
172 case LIBINPUT_EVENT_POINTER_MOTION:
173 m_pointer->processMotion(libinput_event_get_pointer_event(ev));
174 break;
175 case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
176 m_pointer->processAbsMotion(libinput_event_get_pointer_event(ev));
177 break;
178#if QT_CONFIG(libinput_hires_wheel_support)
179 case LIBINPUT_EVENT_POINTER_SCROLL_WHEEL:
180#else
181 case LIBINPUT_EVENT_POINTER_AXIS:
182#endif
183 m_pointer->processAxis(libinput_event_get_pointer_event(ev));
184 break;
185 case LIBINPUT_EVENT_KEYBOARD_KEY:
186 m_keyboard->processKey(libinput_event_get_keyboard_event(ev));
187 break;
188 case LIBINPUT_EVENT_TOUCH_DOWN:
189 m_touch->processTouchDown(libinput_event_get_touch_event(ev));
190 break;
191 case LIBINPUT_EVENT_TOUCH_MOTION:
192 m_touch->processTouchMotion(libinput_event_get_touch_event(ev));
193 break;
194 case LIBINPUT_EVENT_TOUCH_UP:
195 m_touch->processTouchUp(libinput_event_get_touch_event(ev));
196 break;
197 case LIBINPUT_EVENT_TOUCH_CANCEL:
198 m_touch->processTouchCancel(libinput_event_get_touch_event(ev));
199 break;
200 case LIBINPUT_EVENT_TOUCH_FRAME:
201 m_touch->processTouchFrame(libinput_event_get_touch_event(ev));
202 break;
203 default:
204 break;
205 }
206}
207
208QT_END_NAMESPACE
QLibInputHandler(const QString &key, const QString &spec)
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
static void liClose(int fd, void *user_data)
static QT_BEGIN_NAMESPACE int liOpen(const char *path, int flags, void *user_data)
static const struct libinput_interface liInterface
static void liLogHandler(libinput *libinput, libinput_log_priority priority, const char *format, va_list args)