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

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