File indexing completed on 2024-04-21 16:11:00

0001 /*
0002  *   SPDX-FileCopyrightText: 2022 Bart Ribbers <bribbers@disroot.org>
0003  *   SPDX-FileCopyrightText: 2022 Aleix Pol Gonzalez <aleixpol@kde.org>
0004  *
0005  *   SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0006  */
0007 
0008 #include "uinputsystem.h"
0009 
0010 #include <linux/uinput.h>
0011 #include <fcntl.h>
0012 #include <unistd.h>
0013 
0014 #include <QDebug>
0015 
0016 UInputSystem::UInputSystem()
0017 {
0018 }
0019 
0020 bool UInputSystem::init()
0021 {
0022     setSupportedKeys({});
0023     return m_fd > 0;
0024 }
0025 
0026 void UInputSystem::emitKey(int key, bool pressed)
0027 {
0028     if (!m_supportedKeys.contains(key)) {
0029         qWarning() << "reporting unannounced key" << key;
0030     }
0031     qWarning() << "key" << key << pressed;
0032     emitEvent(EV_KEY, key, pressed ? 1 : 0);
0033     emitEvent(EV_SYN, SYN_REPORT, 0);
0034 }
0035 
0036 void UInputSystem::emitEvent(int type, int code, int val)
0037 {
0038     struct input_event ie;
0039 
0040     ie.type = type;
0041     ie.code = code;
0042     ie.value = val;
0043     ie.input_event_sec = 0;
0044     ie.input_event_usec = 0;
0045 
0046     write(m_fd, &ie, sizeof(ie));
0047 }
0048 
0049 void UInputSystem::setSupportedKeys(const QSet<int>& keys)
0050 {
0051     if (m_fd > 0 && keys == m_supportedKeys) {
0052         return;
0053     }
0054     if (m_fd > 0) {
0055         close(m_fd);
0056     }
0057 
0058     m_supportedKeys = keys;
0059 
0060     struct uinput_setup usetup;
0061     m_fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
0062 
0063     if (m_fd < 0) {
0064         qCritical() << "Couldn't open /dev/uinput, make sure the kernel module is loaded";
0065         return;
0066     }
0067 
0068     // Register all keys we want to press with this application
0069     ioctl(m_fd, UI_SET_EVBIT, EV_KEY);
0070 
0071     for ( auto x : std::as_const(m_supportedKeys))
0072         ioctl(m_fd, UI_SET_KEYBIT, x);
0073 
0074     memset(&usetup, 0, sizeof(usetup));
0075     usetup.id.bustype = BUS_USB;
0076     usetup.id.vendor = 0x1234; // TODO: change vendor
0077     usetup.id.product = 0x5678; // TODO: change product
0078     strcpy(usetup.name, "PlasmaRemoteControllers");
0079 
0080     ioctl(m_fd, UI_DEV_SETUP, &usetup);
0081     ioctl(m_fd, UI_DEV_CREATE);
0082 }