diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index bf65ec4..388ee41 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -22,7 +22,7 @@ jobs: qt5-default libqt5x11extras5-dev - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: # We must fetch at least the immediate parents so that if this is # a pull request then we can checkout the head. diff --git a/55-projecteur.rules.in b/55-projecteur.rules.in index dacce1f..af46131 100644 --- a/55-projecteur.rules.in +++ b/55-projecteur.rules.in @@ -17,6 +17,6 @@ SUBSYSTEMS=="hid", KERNELS=="0005:046D:B503.*", MODE="0660", TAG+="uaccess" # Additional supported Bluetooth devices @EXTRA_BLUETOOTH_UDEV_RULES@ -# Rules for uninput: Essential for creating a virtual input device that -# Projecteur use for forwarding device events to the system after grabbing it +# Rules for uinput: Essential for creating a virtual input device that +# Projecteur uses to forward device events to the system after grabbing it KERNEL=="uinput", SUBSYSTEM=="misc", TAG+="uaccess", OPTIONS+="static_node=uinput" diff --git a/src/aboutdlg.cc b/src/aboutdlg.cc index 1273667..167e084 100644 --- a/src/aboutdlg.cc +++ b/src/aboutdlg.cc @@ -18,7 +18,8 @@ #include namespace { - // ------------------------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------------------- + /// Contributor (name, github_name, email, url) struct Contributor { explicit Contributor(const QString& name = {}, const QString& github_name = {}, @@ -27,8 +28,10 @@ namespace { QString toHtml() const { - auto html = QString("%1").arg(name.isEmpty() ? QString("%1").arg(github_name) - : name); + auto html = QString("%1").arg(name.isEmpty() + ? QString("%1").arg(github_name) + : name); + if (email.size()) { html += QString(" <%1>").arg(email); } @@ -48,7 +51,7 @@ namespace { QString url; }; - // ------------------------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------------------- QString getContributorsHtml() { static std::vector contributors = @@ -66,6 +69,9 @@ namespace { Contributor("Stuart Prescott", "llimeht"), Contributor("Crista Renouard", "Lumnicence"), Contributor("freddii", "freddii"), + Contributor("Matthias Blümel", "Blaimi"), + Contributor("Grzegorz Szymaszek", "gszy"), + Contributor("TheAssassin", "TheAssassin"), }; static std::mt19937 g(std::random_device{}()); diff --git a/src/device.cc b/src/device.cc index a8a4778..32db26a 100644 --- a/src/device.cc +++ b/src/device.cc @@ -63,10 +63,11 @@ const char* toString(ConnectionMode cm, bool withClass) // ------------------------------------------------------------------------------------------------- DeviceConnection::DeviceConnection(const DeviceId& id, const QString& name, - std::shared_ptr vdev) + std::shared_ptr vmouse, + std::shared_ptr vkeyboard) : m_deviceId(id) , m_deviceName(name) - , m_inputMapper(std::make_shared(std::move(vdev))) + , m_inputMapper(std::make_shared(std::move(vmouse), std::move(vkeyboard))) { } @@ -245,7 +246,7 @@ std::shared_ptr SubEventConnection::create(const DeviceScan: connection->m_details.grabbed = [&dc, evfd, &sd]() { // Grab device inputs if a virtual device exists. - if (dc.inputMapper()->virtualDevice()) + if (dc.inputMapper()->hasVirtualDevice()) { const int res = ioctl(evfd, EVIOCGRAB, 1); if (res == 0) { return true; } diff --git a/src/device.h b/src/device.h index 1ce24fe..b23d074 100644 --- a/src/device.h +++ b/src/device.h @@ -29,7 +29,9 @@ class DeviceConnection : public QObject Q_OBJECT public: - DeviceConnection(const DeviceId& id, const QString& name, std::shared_ptr vdev); + DeviceConnection(const DeviceId& id, const QString& name, + std::shared_ptr vmouse, std::shared_ptr vkeyboard); + ~DeviceConnection(); const auto& deviceName() const { return m_deviceName; } diff --git a/src/deviceinput.cc b/src/deviceinput.cc index faf18df..7fc5a36 100644 --- a/src/deviceinput.cc +++ b/src/deviceinput.cc @@ -58,6 +58,29 @@ namespace { return KeyEventSequence{std::move(pressed)}; }; + + // ----------------------------------------------------------------------------------------------- + bool isMouseEvent(const input_event* input_events, size_t num) + { + if (num < 2) { + // no events, or single SYN event + return false; + } + + auto const& ev = [&]() -> input_event const& { + if (input_events[0].type == EV_MSC) { + return input_events[1]; + } + return input_events[0]; + }(); + + if (ev.type == EV_KEY && ev.code >= BTN_MISC && ev.code < KEY_OK) { + return true; + } + + return false; + } + } // end anonymous namespace // ------------------------------------------------------------------------------------------------- @@ -547,16 +570,26 @@ const char* toString(Action::Type at, bool withClass) // ------------------------------------------------------------------------------------------------- struct InputMapper::Impl { - Impl(InputMapper* parent, std::shared_ptr vdev); + Impl(InputMapper* parent, + std::shared_ptr virtualMouse, + std::shared_ptr virtualKeybaord); void sequenceTimeout(); void resetState(); void record(const struct input_event input_events[], size_t num); void emitNativeKeySequence(const NativeKeySequence& ks); void execAction(const std::shared_ptr& action, DeviceKeyMap::Result r); + bool hasVirtualDevices() const; + + void forwardEvents(const struct input_event input_events[], size_t num); + void forwardEvents(const std::vector& input_events); InputMapper* m_parent = nullptr; - std::shared_ptr m_vdev; // can be a nullptr if application is started without uinput + + // virtual devices can be empty shared_ptr's if app is started without uinput + std::shared_ptr m_vmouse; + std::shared_ptr m_vkeyboard; + QTimer* m_seqTimer = nullptr; DeviceKeyMap m_keymap; @@ -569,9 +602,12 @@ struct InputMapper::Impl }; // ------------------------------------------------------------------------------------------------- -InputMapper::Impl::Impl(InputMapper* parent, std::shared_ptr vdev) +InputMapper::Impl::Impl(InputMapper* parent + , std::shared_ptr virtualMouse + , std::shared_ptr virtualKeyboard) : m_parent(parent) - , m_vdev(std::move(vdev)) + , m_vmouse(std::move(virtualMouse)) + , m_vkeyboard(std::move(virtualKeyboard)) , m_seqTimer(new QTimer(parent)) { constexpr int defaultSequenceIntervalMs = 250; @@ -580,6 +616,12 @@ InputMapper::Impl::Impl(InputMapper* parent, std::shared_ptr vdev connect(m_seqTimer, &QTimer::timeout, parent, [this](){ sequenceTimeout(); }); } +// ------------------------------------------------------------------------------------------------- +bool InputMapper::Impl::hasVirtualDevices() const +{ + return (m_vmouse && m_vkeyboard); +} + // ------------------------------------------------------------------------------------------------- void InputMapper::Impl::execAction(const std::shared_ptr& action, DeviceKeyMap::Result r) { @@ -612,9 +654,9 @@ void InputMapper::Impl::sequenceTimeout() if (m_lastState.first == DeviceKeyMap::Result::Valid) { // Last input event was part of a valid key sequence, but timeout hit // So we emit our stored event so far to the virtual device - if (m_vdev && !m_events.empty()) + if (hasVirtualDevices() && !m_events.empty()) { - m_vdev->emitEvents(m_events); + forwardEvents(m_events); } resetState(); } @@ -625,9 +667,10 @@ void InputMapper::Impl::sequenceTimeout() { execAction(m_lastState.second->action, DeviceKeyMap::Result::PartialHit); } - else if (m_vdev && !m_events.empty()) + else if (hasVirtualDevices() && !m_events.empty()) { - m_vdev->emitEvents(m_events); + // TODO differentiate between mouse and keyboard events + forwardEvents(m_events); m_events.resize(0); } resetState(); @@ -644,7 +687,7 @@ void InputMapper::Impl::resetState() // ------------------------------------------------------------------------------------------------- void InputMapper::Impl::emitNativeKeySequence(const NativeKeySequence& ks) { - if (!m_vdev) { return; } + if (!m_vkeyboard) { return; } std::vector events; events.reserve(5); // up to 3 modifier keys + 1 key + 1 syn event @@ -653,7 +696,7 @@ void InputMapper::Impl::emitNativeKeySequence(const NativeKeySequence& ks) for (const auto& ie : ke) { events.emplace_back(input_event{{}, ie.type, ie.code, ie.value}); } - m_vdev->emitEvents(events); + m_vkeyboard->emitEvents(events); events.resize(0); } } @@ -671,25 +714,67 @@ void InputMapper::Impl::record(const struct input_event input_events[], size_t n } // ------------------------------------------------------------------------------------------------- +void InputMapper::Impl::forwardEvents(const std::vector& input_events) +{ + forwardEvents(input_events.data(), input_events.size()); +} + // ------------------------------------------------------------------------------------------------- -InputMapper::InputMapper(std::shared_ptr virtualDevice, QObject* parent) +void InputMapper::Impl::forwardEvents(const struct input_event input_events[], size_t num) +{ + input_event const* beg = input_events; + input_event const* end = input_events + num; + + auto predicate = [](input_event const& e){ + return e.type == EV_SYN; + }; + + // handle each part separated by a SYN event + input_event const* syn = std::find_if(beg, end, predicate); + + while (syn != end) { + auto const len = std::distance(beg, syn) + 1; + + if (isMouseEvent(beg, len)) { + m_vmouse->emitEvents(beg, len); + } else { + m_vkeyboard->emitEvents(beg, len); + } + + beg = syn + 1; + syn = std::find_if(beg, end, predicate); + } +} + +// ------------------------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------------------------- +InputMapper::InputMapper( + std::shared_ptr virtualMouse + , std::shared_ptr virtualKeyboard + , QObject* parent) : QObject(parent) - , impl(std::make_unique(this, std::move(virtualDevice))) + , impl(std::make_unique(this, std::move(virtualMouse), std::move(virtualKeyboard))) {} // ------------------------------------------------------------------------------------------------- InputMapper::~InputMapper() = default; // ------------------------------------------------------------------------------------------------- -std::shared_ptr InputMapper::virtualDevice() const +std::shared_ptr InputMapper::virtualMouse() const { - return impl->m_vdev; + return impl->m_vmouse; +} + +// ------------------------------------------------------------------------------------------------- +std::shared_ptr InputMapper::virtualKeyboard() const +{ + return impl->m_vkeyboard; } // ------------------------------------------------------------------------------------------------- bool InputMapper::hasVirtualDevice() const { - return !!(impl->m_vdev); + return impl->hasVirtualDevices(); } // ------------------------------------------------------------------------------------------------- @@ -728,12 +813,12 @@ void InputMapper::setKeyEventInterval(int interval) // ------------------------------------------------------------------------------------------------- void InputMapper::addEvents(const input_event* input_events, size_t num) { - if (num == 0 || (!impl->m_vdev)) { return; } + if (num == 0 || (!hasVirtualDevice())) { return; } // If no key mapping is configured ... if (!impl->m_recordingMode && !impl->m_keymap.hasConfig()) { - // ... forward events to virtual device if it exists... - impl->m_vdev->emitEvents(input_events, num); + // ... forward events to virtual device + impl->forwardEvents(input_events, num); return; } @@ -774,7 +859,8 @@ void InputMapper::addEvents(const input_event* input_events, size_t num) if (res == DeviceKeyMap::Result::Miss) { // key sequence miss, send all buffered events so far impl->m_seqTimer->stop(); - impl->m_vdev->emitEvents(impl->m_events); + + impl->forwardEvents(impl->m_events); impl->resetState(); } @@ -785,7 +871,7 @@ void InputMapper::addEvents(const input_event* input_events, size_t num) impl->execAction(pos->action, res); } else { - impl->m_vdev->emitEvents(impl->m_events); + impl->forwardEvents(impl->m_events); } impl->resetState(); @@ -808,7 +894,7 @@ void InputMapper::addEvents(const KeyEvent& key_event) return ie; }; - // // Check if key_event does have SYN event at end + // Check if key_event does have SYN event at end const bool hasLastSYN = (key_event.back().type == EV_SYN); std::vector events; diff --git a/src/deviceinput.h b/src/deviceinput.h index 7ed4bff..71c4547 100644 --- a/src/deviceinput.h +++ b/src/deviceinput.h @@ -79,7 +79,7 @@ QDebug operator<<(QDebug debug, const KeyEvent &ke); // Some inputs from Logitech Spotlight device (like Next Hold and Back Hold events) are not a valid // input event (input_event in linux/input.h) in a conventional sense. They are communicated // via HID++ messages from the device. Using the input mapper we need to -// reserve some KeyEventSequence for theese events. These KeyEventSequence should be designed in +// reserve some KeyEventSequence for these events. These KeyEventSequence should be designed in // such a way that they cannot interfere with other valid input events from the device. namespace SpecialKeys { @@ -288,7 +288,11 @@ class InputMapper : public QObject Q_OBJECT public: - InputMapper(std::shared_ptr virtualDevice, QObject* parent = nullptr); + InputMapper( + std::shared_ptr virtualMouse, + std::shared_ptr virtualKeyboard, + QObject* parent = nullptr); + ~InputMapper(); void resetState(); // Reset any stored sequence state. @@ -307,7 +311,8 @@ class InputMapper : public QObject const SpecialMoveInputs& specialMoveInputs(); void setSpecialMoveInputs(SpecialMoveInputs moveInputs); - std::shared_ptr virtualDevice() const; + std::shared_ptr virtualMouse() const; + std::shared_ptr virtualKeyboard() const; bool hasVirtualDevice() const; void setConfiguration(const InputMapConfig& config); diff --git a/src/nativekeyseqedit.cc b/src/nativekeyseqedit.cc index 46d1e9e..1246fd7 100644 --- a/src/nativekeyseqedit.cc +++ b/src/nativekeyseqedit.cc @@ -208,7 +208,7 @@ bool NativeKeySeqEdit::event(QEvent* e) return QWidget::event(e); } -//------------------------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------------------------- void NativeKeySeqEdit::recordKeyPressEvent(QKeyEvent* e) { int key = m_lastKey = e->key(); @@ -261,7 +261,7 @@ void NativeKeySeqEdit::recordKeyPressEvent(QKeyEvent* e) } } -//------------------------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------------------------- void NativeKeySeqEdit::keyPressEvent(QKeyEvent* e) { if (!recording()) @@ -285,7 +285,7 @@ void NativeKeySeqEdit::keyPressEvent(QKeyEvent* e) recordKeyPressEvent(e); } -//------------------------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------------------------- void NativeKeySeqEdit::keyReleaseEvent(QKeyEvent* e) { if (recording()) @@ -312,14 +312,14 @@ void NativeKeySeqEdit::keyReleaseEvent(QKeyEvent* e) QWidget::keyReleaseEvent(e); } -//------------------------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------------------------- void NativeKeySeqEdit::focusOutEvent(QFocusEvent* e) { setRecording(false); QWidget::focusOutEvent(e); } -//------------------------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------------------------- int NativeKeySeqEdit::getQtModifiers(Qt::KeyboardModifiers state) { int result = 0; @@ -331,7 +331,7 @@ int NativeKeySeqEdit::getQtModifiers(Qt::KeyboardModifiers state) return result; } -//------------------------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------------------------- uint16_t NativeKeySeqEdit::getNativeModifiers(const std::set& modifiersPressed) { using Modifier = NativeKeySequence::Modifier; diff --git a/src/spotlight.cc b/src/spotlight.cc index 3633a04..20bd96f 100644 --- a/src/spotlight.cc +++ b/src/spotlight.cc @@ -90,7 +90,10 @@ Spotlight::Spotlight(QObject* parent, Options options, Settings* settings) }); if (m_options.enableUInput) { - m_virtualDevice = VirtualDevice::create(); + m_virtualMouseDevice = VirtualDevice::create( + VirtualDevice::Type::Mouse, "Projecteur_virtual_mouse"); + m_virtualKeyDevice = VirtualDevice::create( + VirtualDevice::Type::Keyboard, "Projecteur_virtual_keyboard"); } else { logInfo(device) << tr("Virtual device initialization was skipped."); @@ -174,7 +177,8 @@ int Spotlight::connectDevices() { auto& dc = m_deviceConnections[dev.id]; if (!dc) { - dc = std::make_shared(dev.id, dev.getName(), m_virtualDevice); + dc = std::make_shared( + dev.id, dev.getName(), m_virtualMouseDevice, m_virtualKeyDevice); } const bool anyConnectedBefore = anySpotlightDeviceConnected(); @@ -283,7 +287,7 @@ int Spotlight::connectDevices() } else if (action->type() == Action::Type::ScrollHorizontal || action->type() == Action::Type::ScrollVertical) { - if (!m_virtualDevice) { return; } + if (!m_virtualMouseDevice) { return; } const int param = (action->type() == Action::Type::ScrollHorizontal) ? static_cast(action.get())->param @@ -293,18 +297,18 @@ int Spotlight::connectDevices() { const uint16_t wheelCode = (action->type() == Action::Type::ScrollHorizontal) ? REL_HWHEEL : REL_WHEEL; const std::vector scrollInputEvents = {{{}, EV_REL, wheelCode, param}, {{}, EV_SYN, SYN_REPORT, 0},}; - m_virtualDevice->emitEvents(scrollInputEvents); + m_virtualMouseDevice->emitEvents(scrollInputEvents); } } else if (action->type() == Action::Type::VolumeControl) { - if (!m_virtualDevice) { return; } + if (!m_virtualMouseDevice) { return; } auto param = static_cast(action.get())->param; uint16_t keyCode = (param > 0)? KEY_VOLUMEUP: KEY_VOLUMEDOWN; const std::vector curVolInputEvents = {{{}, EV_KEY, keyCode, 1}, {{}, EV_SYN, SYN_REPORT, 0}, {{}, EV_KEY, keyCode, 0}, {{}, EV_SYN, SYN_REPORT, 0},}; - if (param) { m_virtualDevice->emitEvents(curVolInputEvents); } + if (param) { m_virtualMouseDevice->emitEvents(curVolInputEvents); } } }); @@ -423,7 +427,10 @@ void Spotlight::onEventDataAvailable(int fd, SubEventConnection& connection) } m_activeTimer->start(); - if (m_virtualDevice) { m_virtualDevice->emitEvents(buf.data(), buf.pos()); } + if (m_virtualMouseDevice) { + // forward events to virtual mouse device + m_virtualMouseDevice->emitEvents(buf.data(), buf.pos()); + } } else { // Forward events to input mapper for the device diff --git a/src/spotlight.h b/src/spotlight.h index ea04e15..d77c9ee 100644 --- a/src/spotlight.h +++ b/src/spotlight.h @@ -76,7 +76,8 @@ class Spotlight : public QObject, public async::Async QTimer* m_connectionTimer = nullptr; QTimer* m_holdMoveEventTimer = nullptr; bool m_spotActive = false; - std::shared_ptr m_virtualDevice; + std::shared_ptr m_virtualMouseDevice; + std::shared_ptr m_virtualKeyDevice; Settings* m_settings = nullptr; std::unique_ptr m_holdButtonStatus; }; diff --git a/src/virtualdevice.cc b/src/virtualdevice.cc index ecdd457..be16375 100644 --- a/src/virtualdevice.cc +++ b/src/virtualdevice.cc @@ -7,34 +7,47 @@ #include #include +#include #include #include LOGGING_CATEGORY(virtualdevice, "virtualdevice") +// KEY_MACRO1 is only defined in newer linux versions +#ifndef KEY_MACRO1 +#define KEY_MACRO1 0x290 +#endif + namespace { class VirtualDevice_ : public QObject {}; // for i18n and logging } // end anonymous namespace struct VirtualDevice::Token {}; -VirtualDevice::VirtualDevice(Token /* token */, int fd) +// ------------------------------------------------------------------------------------------------- +VirtualDevice::VirtualDevice(Token /* token */, int fd, const char* name, const char* sysfs_name) : m_uinpFd(fd) + , m_userName(name) + , m_deviceName(sysfs_name) {} +// ------------------------------------------------------------------------------------------------- VirtualDevice::~VirtualDevice() { if (m_uinpFd >= 0) { ioctl(m_uinpFd, UI_DEV_DESTROY); ::close(m_uinpFd); - logDebug(virtualdevice) << VirtualDevice_::tr("uinput Device Closed"); + logDebug(virtualdevice) + << VirtualDevice_::tr("uinput Device Closed (%1; %2)").arg(m_userName, m_deviceName); } } -// Setup uinput device that can send mouse and keyboard events. -std::shared_ptr VirtualDevice::create(const char* name, +// ------------------------------------------------------------------------------------------------- +// Setup a uinput device that can send mouse or keyboard events. +std::shared_ptr VirtualDevice::create(Type deviceType, + const char* name, uint16_t virtualVendorId, uint16_t virtualProductId, uint16_t virtualVersionId, @@ -44,14 +57,14 @@ std::shared_ptr VirtualDevice::create(const char* name, if (!fi.exists()) { logWarn(virtualdevice) << VirtualDevice_::tr("File not found: %1").arg(location); logWarn(virtualdevice) << VirtualDevice_::tr("Please check if uinput kernel module is loaded"); - return std::unique_ptr(); + return std::shared_ptr(); } const int fd = ::open(location, O_WRONLY | O_NDELAY); if (fd < 0) { logWarn(virtualdevice) << VirtualDevice_::tr("Unable to open: %1").arg(location); logWarn(virtualdevice) << VirtualDevice_::tr("Please check if current user has write access"); - return std::unique_ptr(); + return std::shared_ptr(); } struct uinput_user_dev uinp {}; @@ -67,14 +80,30 @@ std::shared_ptr VirtualDevice::create(const char* name, ioctl(fd, UI_SET_EVBIT, EV_KEY); ioctl(fd, UI_SET_EVBIT, EV_REL); - // Set all rel event code bits on virtual device + // Set all relative event code bits on virtual device for (int i = 0; i < REL_CNT; ++i) { ioctl(fd, UI_SET_RELBIT, i); } - // Set all key code bits on virtual device - for (int i = 1; i < KEY_CNT; ++i) { - ioctl(fd, UI_SET_KEYBIT, i); + // Thank's to Matthias Blümel / https://github.com/Blaimi + // for the detailed investigation on the uinput issue on newer + // Linux distributions. + // See https://github.com/jahnf/Projecteur/issues/175#issuecomment-1432112896 + + if (deviceType == Type::Mouse) { + // Set key code bits for a virtual mouse + for (int i = BTN_MISC; i < KEY_OK; ++i) { + ioctl(fd, UI_SET_KEYBIT, i); + } + } else if (deviceType == Type::Keyboard) { + // Set key code bits for a virtual keyboard + for (int i = 1; i < BTN_MISC; ++i) { + ioctl(fd, UI_SET_KEYBIT, i); + } + for (int i = KEY_OK; i < KEY_MACRO1; ++i) { + ioctl(fd, UI_SET_KEYBIT, i); + } + // will set key bits from i = KEY_MACRO1 to i < KEY_CNT also work? } // Create input device into input sub-system @@ -90,11 +119,13 @@ std::shared_ptr VirtualDevice::create(const char* name, char sysfs_device_name[16]{}; ioctl(fd, UI_GET_SYSNAME(sizeof(sysfs_device_name)), sysfs_device_name); logInfo(virtualdevice) << VirtualDevice_::tr("Created uinput device: %1") - .arg(QString("/sys/devices/virtual/input/%1").arg(sysfs_device_name)); + .arg(QString("%1; /sys/devices/virtual/input/%2") + .arg(name, sysfs_device_name)); - return std::make_shared(Token{}, fd); + return std::make_shared(Token{}, fd, name, sysfs_device_name); } +// ------------------------------------------------------------------------------------------------- void VirtualDevice::emitEvents(const struct input_event input_events[], size_t num) { if (!num) { return; } @@ -107,8 +138,8 @@ void VirtualDevice::emitEvents(const struct input_event input_events[], size_t n } } +// ------------------------------------------------------------------------------------------------- void VirtualDevice::emitEvents(const std::vector& events) { emitEvents(events.data(), events.size()); } - diff --git a/src/virtualdevice.h b/src/virtualdevice.h index e5b73f3..f70d276 100644 --- a/src/virtualdevice.h +++ b/src/virtualdevice.h @@ -7,26 +7,36 @@ # pragma once +#include + #include #include #include -// Device that can act as virtual keyboard and mouse +/// Device that can act as virtual keyboard or mouse class VirtualDevice { private: struct Token; int m_uinpFd = -1; + QString m_userName; + QString m_deviceName; public: - // Return a VirtualDevice shared_ptr or an empty shared_ptr if the creation fails. - static std::shared_ptr create(const char* name = "Projecteur_input_device", + enum class Type { + Mouse, + Keyboard + }; + + /// Return a VirtualDevice shared_ptr or an empty shared_ptr if the creation fails. + static std::shared_ptr create(Type deviceType, + const char* name = "Projecteur_input_device", uint16_t virtualVendorId = 0xfeed, uint16_t virtualProductId = 0xc0de, uint16_t virtualVersionId = 1, const char* location = "/dev/uinput"); - explicit VirtualDevice(Token, int fd); + VirtualDevice(Token, int fd, const char* name, const char* sysfs_name); ~VirtualDevice(); void emitEvents(const struct input_event[], size_t num);