From 87c9281e5e367e73fb5bfc26936fef908cd5f4eb Mon Sep 17 00:00:00 2001 From: Aleix Pol Date: Tue, 26 Jul 2022 01:56:46 +0200 Subject: [PATCH] support sending a keymap --- CMakeLists.txt | 2 +- plugins/mousepad/CMakeLists.txt | 7 ++- plugins/mousepad/waylandremoteinput.cpp | 64 +++++++++++++++++++++++-- plugins/mousepad/waylandremoteinput.h | 10 +++- 4 files changed, 76 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9851d0faf..7fe5f7bf8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.16) # KDE Release Service Version, managed by release script set (RELEASE_SERVICE_VERSION_MAJOR "22") diff --git a/plugins/mousepad/CMakeLists.txt b/plugins/mousepad/CMakeLists.txt index 6aa0a51a3..ab0f366af 100644 --- a/plugins/mousepad/CMakeLists.txt +++ b/plugins/mousepad/CMakeLists.txt @@ -14,10 +14,15 @@ if(UNIX AND NOT APPLE) BASENAME fake-input ) + ecm_add_qtwayland_client_protocol(wayland_SRCS + PROTOCOL ${Wayland_DATADIR}/wayland.xml + BASENAME wayland + ) + pkg_check_modules(XkbCommon IMPORTED_TARGET xkbcommon) target_sources(kdeconnect_mousepad PRIVATE ${wayland_SRCS}) - target_link_libraries(kdeconnect_mousepad Wayland::Client Qt5::WaylandClient PkgConfig::XkbCommon) + target_link_libraries(kdeconnect_mousepad Wayland::Client Qt5::WaylandClient PkgConfig::XkbCommon Qt::GuiPrivate) target_sources(kdeconnect_mousepad PUBLIC waylandremoteinput.cpp) set(HAVE_WAYLAND TRUE) diff --git a/plugins/mousepad/waylandremoteinput.cpp b/plugins/mousepad/waylandremoteinput.cpp index 4503d7246..440d052e5 100644 --- a/plugins/mousepad/waylandremoteinput.cpp +++ b/plugins/mousepad/waylandremoteinput.cpp @@ -6,16 +6,23 @@ #include "waylandremoteinput.h" -#include #include +#include +#include +#include #include +#include #include #include "qwayland-fake-input.h" +#include "qwayland-wayland.h" +#include "qwayland-wayland.h" #include #include +#include +#include namespace { @@ -66,17 +73,41 @@ public: } }; +class WlKeyboard : public QtWayland::wl_keyboard +{ +public: + WlKeyboard(WaylandRemoteInput *input) + : m_input(input) + {} + + void keyboard_keymap(uint32_t format, int32_t fd, uint32_t size) override { + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + close(fd); + return; + } + + char *map_str = static_cast(mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0)); + if (map_str == MAP_FAILED) { + close(fd); + return; + } + + m_input->setKeymap(QByteArray(map_str, size)); + } + WaylandRemoteInput *const m_input; +}; WaylandRemoteInput::WaylandRemoteInput(QObject* parent) : AbstractRemoteInput(parent) + , m_fakeInput(new FakeInput) + , m_keyboard(new WlKeyboard(this)) , m_waylandAuthenticationRequested(false) { - m_fakeInput = new FakeInput; + m_keyboard->init(static_cast(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("wl_keyboard"))); } WaylandRemoteInput::~WaylandRemoteInput() { - delete m_fakeInput; } bool WaylandRemoteInput::handlePacket(const NetworkPacket& np) @@ -104,7 +135,6 @@ bool WaylandRemoteInput::handlePacket(const NetworkPacket& np) const int specialKey = np.get(QStringLiteral("specialKey"), 0); if (isSingleClick || isDoubleClick || isMiddleClick || isRightClick || isSingleHold || isSingleRelease || isScroll || !key.isEmpty() || specialKey) { - if (isSingleClick) { m_fakeInput->button(BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED); m_fakeInput->button(BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED); @@ -133,6 +163,32 @@ bool WaylandRemoteInput::handlePacket(const NetworkPacket& np) m_fakeInput->keyboard_key(SpecialKeysMap[specialKey], 1); m_fakeInput->keyboard_key(SpecialKeysMap[specialKey], 0); } else if (!key.isEmpty()) { + if (!m_keymapSent && !m_keymap.isEmpty()) { + m_keymapSent = true; + auto sendKeymap = [this] { + QScopedPointer tmp(new QTemporaryFile()); + if (!tmp->open()) { + return; + } + + unlink(tmp->fileName().toUtf8().constData()); + if (!tmp->resize(m_keymap.size())) { + return; + } + + uchar *address = tmp->map(0, m_keymap.size()); + if (!address) { + return; + } + + qstrncpy(reinterpret_cast(address), m_keymap.constData(), m_keymap.size() + 1); + tmp->unmap(address); + + m_fakeInput->keyboard_keymap(tmp->handle(), tmp->size()); + }; + sendKeymap(); + } + for (const QChar character : key) { const auto keysym = xkb_utf32_to_keysym(character.unicode()); m_fakeInput->keyboard_keysym(keysym, 1); diff --git a/plugins/mousepad/waylandremoteinput.h b/plugins/mousepad/waylandremoteinput.h index 9c805879a..a18e18422 100644 --- a/plugins/mousepad/waylandremoteinput.h +++ b/plugins/mousepad/waylandremoteinput.h @@ -10,6 +10,7 @@ #include "abstractremoteinput.h" class FakeInput; +class WlKeyboard; class WaylandRemoteInput : public AbstractRemoteInput @@ -20,13 +21,20 @@ public: explicit WaylandRemoteInput(QObject* parent); ~WaylandRemoteInput(); + void setKeymap(const QByteArray &keymap) { + m_keymapSent = false; + m_keymap = keymap; + } bool handlePacket(const NetworkPacket& np) override; private: void setupWaylandIntegration(); - FakeInput *m_fakeInput; + QScopedPointer m_fakeInput; + QScopedPointer m_keyboard; bool m_waylandAuthenticationRequested; + bool m_keymapSent = false; + QByteArray m_keymap; }; #endif