7#include <QCoreApplication>
10#include <QSocketNotifier>
11#include <QLoggingCategory>
14#include <dev/evdev/input.h>
16#include <linux/input.h>
21using namespace Qt::StringLiterals;
25QDeviceDiscovery *QDeviceDiscovery::create(QDeviceTypes types, QObject *parent)
27 qCDebug(lcDD) <<
"udev device discovery for type" << types;
29 QDeviceDiscovery *helper =
nullptr;
34 helper =
new QDeviceDiscoveryUDev(types, udev, parent);
36 qWarning(
"Failed to get udev library context");
42QDeviceDiscoveryUDev::QDeviceDiscoveryUDev(QDeviceTypes types,
struct udev *udev, QObject *parent) :
43 QDeviceDiscovery(types, parent),
49 m_udevMonitor = udev_monitor_new_from_netlink(m_udev,
"udev");
51 qWarning(
"Unable to create an udev monitor. No devices can be detected.");
55 udev_monitor_filter_add_match_subsystem_devtype(m_udevMonitor,
"input", 0);
56 udev_monitor_filter_add_match_subsystem_devtype(m_udevMonitor,
"drm", 0);
57 udev_monitor_enable_receiving(m_udevMonitor);
58 m_udevMonitorFileDescriptor = udev_monitor_get_fd(m_udevMonitor);
60 m_udevSocketNotifier =
new QSocketNotifier(m_udevMonitorFileDescriptor, QSocketNotifier::Read,
this);
61 connect(m_udevSocketNotifier, SIGNAL(activated(QSocketDescriptor)),
this, SLOT(handleUDevNotification()));
64QDeviceDiscoveryUDev::~QDeviceDiscoveryUDev()
67 udev_monitor_unref(m_udevMonitor);
73QStringList QDeviceDiscoveryUDev::scanConnectedDevices()
80 udev_enumerate *ue = udev_enumerate_new(m_udev);
81 udev_enumerate_add_match_subsystem(ue,
"input");
82 udev_enumerate_add_match_subsystem(ue,
"drm");
84 if (m_types & Device_Mouse)
85 udev_enumerate_add_match_property(ue,
"ID_INPUT_MOUSE",
"1");
86 if (m_types & Device_Touchpad)
87 udev_enumerate_add_match_property(ue,
"ID_INPUT_TOUCHPAD",
"1");
88 if (m_types & Device_Touchscreen)
89 udev_enumerate_add_match_property(ue,
"ID_INPUT_TOUCHSCREEN",
"1");
90 if (m_types & Device_Keyboard) {
91 udev_enumerate_add_match_property(ue,
"ID_INPUT_KEYBOARD",
"1");
92 udev_enumerate_add_match_property(ue,
"ID_INPUT_KEY",
"1");
94 if (m_types & Device_Tablet)
95 udev_enumerate_add_match_property(ue,
"ID_INPUT_TABLET",
"1");
96 if (m_types & Device_Joystick)
97 udev_enumerate_add_match_property(ue,
"ID_INPUT_JOYSTICK",
"1");
99 if (udev_enumerate_scan_devices(ue) != 0) {
100 qWarning(
"Failed to scan devices");
104 udev_list_entry *entry;
105 udev_list_entry_foreach (entry, udev_enumerate_get_list_entry(ue)) {
106 const char *syspath = udev_list_entry_get_name(entry);
107 udev_device *udevice = udev_device_new_from_syspath(m_udev, syspath);
108 QString candidate = QString::fromUtf8(udev_device_get_devnode(udevice));
109 if ((m_types & Device_InputMask) && candidate.startsWith(
QT_EVDEV_DEVICE ""_L1))
110 devices << candidate;
111 if ((m_types & Device_VideoMask) && candidate.startsWith(
QT_DRM_DEVICE ""_L1)) {
112 if (m_types & Device_DRM_PrimaryGPU) {
113 udev_device *pci = udev_device_get_parent_with_subsystem_devtype(udevice,
"pci", 0);
115 if (qstrcmp(udev_device_get_sysattr_value(pci,
"boot_vga"),
"1") == 0)
116 devices << candidate;
119 devices << candidate;
122 udev_device_unref(udevice);
124 udev_enumerate_unref(ue);
126 qCDebug(lcDD) <<
"Found matching devices" << devices;
131void QDeviceDiscoveryUDev::handleUDevNotification()
136 struct udev_device *dev;
139 dev = udev_monitor_receive_device(m_udevMonitor);
144 action = udev_device_get_action(dev);
149 str = udev_device_get_devnode(dev);
153 const char *subsystem;
154 devNode = QString::fromUtf8(str);
162 if (!checkDeviceType(dev)) {
164 struct udev_device *parent_dev = udev_device_get_parent_with_subsystem_devtype(dev, subsystem, 0);
168 if (!checkDeviceType(parent_dev))
172 if (qstrcmp(action,
"add") == 0)
173 emit deviceDetected(devNode);
175 if (qstrcmp(action,
"remove") == 0)
176 emit deviceRemoved(devNode);
178 if (qstrcmp(action,
"change") == 0)
179 emit deviceChanged(devNode);
182 udev_device_unref(dev);
185bool QDeviceDiscoveryUDev::checkDeviceType(udev_device *dev)
190 if ((m_types & Device_Keyboard) && (qstrcmp(udev_device_get_property_value(dev,
"ID_INPUT_KEYBOARD"),
"1") == 0 )) {
191 const QString capabilities_key = QString::fromUtf8(udev_device_get_sysattr_value(dev,
"capabilities/key"));
192 const auto val = QStringView{capabilities_key}.split(u' ', Qt::SkipEmptyParts);
193 if (!val.isEmpty()) {
195 unsigned long long keys = val.last().toULongLong(&ok, 16);
198 bool test = (keys >> KEY_Q) & 1;
205 if ((m_types & Device_Keyboard) && (qstrcmp(udev_device_get_property_value(dev,
"ID_INPUT_KEY"),
"1") == 0 ))
208 if ((m_types & Device_Mouse) && (qstrcmp(udev_device_get_property_value(dev,
"ID_INPUT_MOUSE"),
"1") == 0))
211 if ((m_types & Device_Touchpad) && (qstrcmp(udev_device_get_property_value(dev,
"ID_INPUT_TOUCHPAD"),
"1") == 0))
214 if ((m_types & Device_Touchscreen) && (qstrcmp(udev_device_get_property_value(dev,
"ID_INPUT_TOUCHSCREEN"),
"1") == 0))
217 if ((m_types & Device_Tablet) && (qstrcmp(udev_device_get_property_value(dev,
"ID_INPUT_TABLET"),
"1") == 0))
220 if ((m_types & Device_Joystick) && (qstrcmp(udev_device_get_property_value(dev,
"ID_INPUT_JOYSTICK"),
"1") == 0))
223 if ((m_types & Device_DRM) && (qstrcmp(udev_device_get_subsystem(dev),
"drm") == 0))
231#include "moc_qdevicediscovery_udev_p.cpp"
Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core")