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#include "qevdevkeyboardmanager_p.h"
5
6#include <QtInputSupport/private/qevdevutil_p.h>
7
8#include <QStringList>
9#include <QCoreApplication>
10#include <QLoggingCategory>
11
12#include <private/qguiapplication_p.h>
13#include <private/qinputdevicemanager_p_p.h>
14
15QT_BEGIN_NAMESPACE
16
17using namespace Qt::StringLiterals;
18
19Q_DECLARE_LOGGING_CATEGORY(qLcEvdevKey)
20
21QEvdevKeyboardManager::QEvdevKeyboardManager(const QString &key, const QString &specification, QObject *parent)
22 : QObject(parent)
23{
24 Q_UNUSED(key);
25
26
27 QString spec = QString::fromLocal8Bit(ba: qgetenv(varName: "QT_QPA_EVDEV_KEYBOARD_PARAMETERS"));
28
29 if (spec.isEmpty())
30 spec = specification;
31
32 auto parsed = QEvdevUtil::parseSpecification(specification: spec);
33 m_spec = std::move(parsed.spec);
34
35 // add all keyboards for devices specified in the argument list
36 for (const QString &device : std::as_const(t&: parsed.devices))
37 addKeyboard(deviceNode: device);
38
39 if (parsed.devices.isEmpty()) {
40 qCDebug(qLcEvdevKey, "evdevkeyboard: Using device discovery");
41 if (auto deviceDiscovery = QDeviceDiscovery::create(type: QDeviceDiscovery::Device_Keyboard, parent: this)) {
42 // scan and add already connected keyboards
43 const QStringList devices = deviceDiscovery->scanConnectedDevices();
44 for (const QString &device : devices)
45 addKeyboard(deviceNode: device);
46
47 connect(sender: deviceDiscovery, signal: &QDeviceDiscovery::deviceDetected,
48 context: this, slot: &QEvdevKeyboardManager::addKeyboard);
49 connect(sender: deviceDiscovery, signal: &QDeviceDiscovery::deviceRemoved,
50 context: this, slot: &QEvdevKeyboardManager::removeKeyboard);
51 }
52 }
53}
54
55QEvdevKeyboardManager::~QEvdevKeyboardManager()
56{
57}
58
59void QEvdevKeyboardManager::addKeyboard(const QString &deviceNode)
60{
61 qCDebug(qLcEvdevKey, "Adding keyboard at %ls", qUtf16Printable(deviceNode));
62 auto keyboard = QEvdevKeyboardHandler::create(device: deviceNode, specification: m_spec, defaultKeymapFile: m_defaultKeymapFile);
63 if (keyboard) {
64 m_keyboards.add(deviceNode, handler: std::move(keyboard));
65 updateDeviceCount();
66 } else {
67 qWarning(msg: "Failed to open keyboard device %ls", qUtf16Printable(deviceNode));
68 }
69}
70
71void QEvdevKeyboardManager::removeKeyboard(const QString &deviceNode)
72{
73 if (m_keyboards.remove(deviceNode)) {
74 qCDebug(qLcEvdevKey, "Removing keyboard at %ls", qUtf16Printable(deviceNode));
75 updateDeviceCount();
76 }
77}
78
79void QEvdevKeyboardManager::updateDeviceCount()
80{
81 QInputDeviceManagerPrivate::get(mgr: QGuiApplicationPrivate::inputDeviceManager())->setDeviceCount(
82 type: QInputDeviceManager::DeviceTypeKeyboard, count: m_keyboards.count());
83}
84
85void QEvdevKeyboardManager::loadKeymap(const QString &file)
86{
87 m_defaultKeymapFile = file;
88
89 if (file.isEmpty()) {
90 // Restore the default, which is either the built-in keymap or
91 // the one given in the plugin spec.
92 QString keymapFromSpec;
93 const auto specs = QStringView{m_spec}.split(sep: u':');
94 for (const auto &arg : specs) {
95 if (arg.startsWith(s: "keymap="_L1))
96 keymapFromSpec = arg.mid(pos: 7).toString();
97 }
98 for (const auto &keyboard : m_keyboards) {
99 if (keymapFromSpec.isEmpty())
100 keyboard.handler->unloadKeymap();
101 else
102 keyboard.handler->loadKeymap(file: keymapFromSpec);
103 }
104 } else {
105 for (const auto &keyboard : m_keyboards)
106 keyboard.handler->loadKeymap(file);
107 }
108}
109
110void QEvdevKeyboardManager::switchLang()
111{
112 for (const auto &keyboard : m_keyboards)
113 keyboard.handler->switchLang();
114}
115
116QT_END_NAMESPACE
117

source code of qtbase/src/platformsupport/input/evdevkeyboard/qevdevkeyboardmanager.cpp