diff --git a/misc/dconfig/org.deepin.dde.treeland.user.json b/misc/dconfig/org.deepin.dde.treeland.user.json index 2dc0a7254..5252b90a1 100644 --- a/misc/dconfig/org.deepin.dde.treeland.user.json +++ b/misc/dconfig/org.deepin.dde.treeland.user.json @@ -443,6 +443,17 @@ "permissions": "readonly", "visibility": "private" }, + "inputAccelProfile": { + "value": 2, + "serial": 0, + "flags": ["global"], + "name": "Libinput Accel Profile", + "name[zh_CN]": "Libinput 加速曲线", + "description": "Pointer acceleration profile, enum value of libinput_config_accel_profile", + "description[zh_CN]": "指针加速曲线,对应 libinput_config_accel_profile 枚举值", + "permissions": "readwrite", + "visibility": "public" + }, "wallpaperConfig": { "value": "", "serial": 0, diff --git a/src/core/shellhandler.cpp b/src/core/shellhandler.cpp index 459cfba62..a7b4d3610 100644 --- a/src/core/shellhandler.cpp +++ b/src/core/shellhandler.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -336,6 +337,8 @@ void ShellHandler::removeXWayland(WXWayland *xwayland) void ShellHandler::initInputMethodHelper(WServer *server, WSeat *seat) { Q_ASSERT_X(!m_inputMethodHelper, Q_FUNC_INFO, "Only init once!"); + Q_ASSERT_X(!m_virtualInputHelper, Q_FUNC_INFO, "Only init once!"); + m_virtualInputHelper = new WVirtualInputHelper(server, seat); m_inputMethodHelper = new WInputMethodHelper(server, seat); connect(m_inputMethodHelper, diff --git a/src/core/shellhandler.h b/src/core/shellhandler.h index 0613beeda..415e37f53 100644 --- a/src/core/shellhandler.h +++ b/src/core/shellhandler.h @@ -46,6 +46,7 @@ class WInputMethodHelper; class WInputPopupSurface; class WSeat; class WSurface; +class WVirtualInputHelper; class WXWaylandSurface; WAYLIB_SERVER_END_NAMESPACE @@ -161,6 +162,7 @@ private Q_SLOTS: WAYLIB_SERVER_NAMESPACE::WLayerShell *m_layerShell = nullptr; TreelandWallpaperShellInterfaceV1 *m_wallpaperShell = nullptr; WAYLIB_SERVER_NAMESPACE::WInputMethodHelper *m_inputMethodHelper = nullptr; + WAYLIB_SERVER_NAMESPACE::WVirtualInputHelper *m_virtualInputHelper = nullptr; QList m_xwaylands; ForeignToplevelV1 *m_treelandForeignToplevel = nullptr; diff --git a/src/input/inputdevice.cpp b/src/input/inputdevice.cpp index 109c735f5..c9922ae9c 100644 --- a/src/input/inputdevice.cpp +++ b/src/input/inputdevice.cpp @@ -1,8 +1,10 @@ // Copyright (C) 2024-2026 UnionTech Software Technology Co., Ltd. // SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +#include "helper.h" #include "inputdevice.h" #include "common/treelandlogging.h" +#include "treelanduserconfig.hpp" #include @@ -13,6 +15,7 @@ #include #include + QW_USE_NAMESPACE #define MIN_SWIPE_FINGERS 3 @@ -351,24 +354,38 @@ InputDevice *InputDevice::instance() return m_instance; } -bool InputDevice::initTouchPad(WInputDevice *device) +void InputDevice::initDevice(WInputDevice *device) { if (!device) { qCCritical(treelandInput) << "Cannot initialize touchpad for null device"; - return false; + return; } - if (!device->qtDevice()) { + if (!device->qtDevice() || !device->handle()->is_libinput()) { qCCritical(treelandInput) << "Cannot initialize touchpad: device has no qtDevice"; - return false; + return; } - if (device->handle()->is_libinput() - && device->qtDevice()->type() == QInputDevice::DeviceType::TouchPad) { + auto deviceType = device->qtDevice()->type(); + if (deviceType == QInputDevice::DeviceType::TouchPad) { configTapEnabled(libinput_device_handle(device->handle()), LIBINPUT_CONFIG_TAP_ENABLED); - return true; } - return false; + + if (deviceType == QInputDevice::DeviceType::TouchPad + || deviceType == QInputDevice::DeviceType::Mouse) { + return; + } + + auto config = Helper::instance()->config(); + auto applyAccelProfile = [device, config]() { + configAccelProfile(libinput_device_handle(device->handle()), + static_cast(config->inputAccelProfile())); + }; + + connect(config, &TreelandUserConfig::inputAccelProfileChanged, device, applyAccelProfile); + connect(config, &TreelandUserConfig::configInitializeSucceed, device, applyAccelProfile); + + applyAccelProfile(); } [[maybe_unused]] SwipeGesture* InputDevice::registerTouchpadSwipe(const SwipeFeedBack &feed_back) diff --git a/src/input/inputdevice.h b/src/input/inputdevice.h index c48b4fbfb..3f955d40a 100644 --- a/src/input/inputdevice.h +++ b/src/input/inputdevice.h @@ -1,4 +1,4 @@ -// Copyright (C) 2024-2025 UnionTech Software Technology Co., Ltd. +// Copyright (C) 2024-2026 UnionTech Software Technology Co., Ltd. // SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #pragma once @@ -9,7 +9,9 @@ #include +#include #include +#include WAYLIB_SERVER_BEGIN_NAMESPACE class WInputDevice; @@ -40,7 +42,7 @@ class InputDevice : public QObject InputDevice(const InputDevice &) = delete; InputDevice &operator=(const InputDevice &) = delete; - bool initTouchPad(WInputDevice *device); + void initDevice(WInputDevice *device); SwipeGesture* registerTouchpadSwipe(const SwipeFeedBack &feed_back); HoldGesture* registerTouchpadHold(const HoldFeedBack &feed); @@ -62,5 +64,6 @@ class InputDevice : public QObject static InputDevice *m_instance; std::unique_ptr m_touchpadRecognizer; + QHash> m_deviceConnections; uint m_touchpadFingerCount = 0; }; diff --git a/src/seat/helper.cpp b/src/seat/helper.cpp index 8e5cc8a3c..ce707212d 100644 --- a/src/seat/helper.cpp +++ b/src/seat/helper.cpp @@ -112,6 +112,7 @@ #include #include #include +#include #include #include #include @@ -1440,7 +1441,7 @@ void Helper::init(Treeland::Treeland *treeland) connect(m_seatManager, &SeatsManager::deviceAdded, this, [this](WInputDevice *device) { m_seatManager->assignDevice(device, m_renderWindow, m_rootSurfaceContainer->outputLayout(), m_seat); - InputDevice::instance()->initTouchPad(device); + InputDevice::instance()->initDevice(device); }); // Setup drag request handling for all seats @@ -1476,6 +1477,7 @@ void Helper::init(Treeland::Treeland *treeland) // free follow display m_compositor = qw_compositor::create(*m_server->handle(), 6, *m_renderer); qw_subcompositor::create(*m_server->handle()); + qw_single_pixel_buffer_manager_v1::create(m_server->handle()->handle()); qw_screencopy_manager_v1::create(*m_server->handle()); qw_ext_image_copy_capture_manager_v1::create(*m_server->handle(), 1); qw_ext_output_image_capture_source_manager_v1::create(*m_server->handle(), 1); diff --git a/waylib/examples/tinywl/helper.cpp b/waylib/examples/tinywl/helper.cpp index 93dda3144..3c7e5ff2b 100644 --- a/waylib/examples/tinywl/helper.cpp +++ b/waylib/examples/tinywl/helper.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2023 JiDe Zhang . +// Copyright (C) 2024-2026 JiDe Zhang . // SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "helper.h" @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -414,6 +415,7 @@ void Helper::init() }); }); + m_virtualInputHelper = new WVirtualInputHelper(m_server, m_seat); m_inputMethodHelper = new WInputMethodHelper(m_server, m_seat); connect(m_inputMethodHelper, &WInputMethodHelper::inputPopupSurfaceV2Added, this, [this](WInputPopupSurface *inputPopup) { diff --git a/waylib/examples/tinywl/helper.h b/waylib/examples/tinywl/helper.h index d0059c0a7..778b10283 100644 --- a/waylib/examples/tinywl/helper.h +++ b/waylib/examples/tinywl/helper.h @@ -1,4 +1,4 @@ -// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// Copyright (C) 2024-2026 UnionTech Software Technology Co., Ltd. // SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #pragma once @@ -34,6 +34,7 @@ class WOutputLayer; class WOutput; class WXWayland; class WInputMethodHelper; +class WVirtualInputHelper; class WXdgDecorationManager; class WSocket; class WSurface; @@ -161,6 +162,7 @@ public Q_SLOTS: qw_compositor *m_compositor = nullptr; WXWayland *m_xwayland = nullptr; WInputMethodHelper *m_inputMethodHelper = nullptr; + WVirtualInputHelper *m_virtualInputHelper = nullptr; WXdgDecorationManager *m_xdgDecorationManager = nullptr; WForeignToplevel *m_foreignToplevel = nullptr; WExtForeignToplevelListV1 *m_extForeignToplevelListV1 = nullptr; diff --git a/waylib/src/server/CMakeLists.txt b/waylib/src/server/CMakeLists.txt index af94a0f81..9a4d76d07 100644 --- a/waylib/src/server/CMakeLists.txt +++ b/waylib/src/server/CMakeLists.txt @@ -167,12 +167,14 @@ set(SOURCES protocols/wxdgdecorationmanager.cpp protocols/wlayershell.cpp protocols/winputmethodhelper.cpp + protocols/wvirtualinputhelper.cpp protocols/winputpopupsurface.cpp protocols/private/winputmethodv2.cpp protocols/private/wtextinputv1.cpp protocols/private/wtextinputv2.cpp protocols/private/wtextinputv3.cpp protocols/private/wvirtualkeyboardv1.cpp + protocols/private/wvirtualpointerv1.cpp protocols/ext_foreign_toplevel_image_capture_source.c #TODO: Remove after wlroots 0.20 protocols/wcursorshapemanagerv1.cpp protocols/woutputmanagerv1.cpp @@ -263,6 +265,8 @@ set(HEADERS protocols/WXdgOutput protocols/WInputMethodHelper protocols/winputmethodhelper.h + protocols/WVirtualInputHelper + protocols/wvirtualinputhelper.h protocols/winputpopupsurface.h protocols/WInputPopupSurface protocols/wcursorshapemanagerv1.h diff --git a/waylib/src/server/protocols/WVirtualInputHelper b/waylib/src/server/protocols/WVirtualInputHelper new file mode 100644 index 000000000..25e062d3e --- /dev/null +++ b/waylib/src/server/protocols/WVirtualInputHelper @@ -0,0 +1 @@ +#include "wvirtualinputhelper.h" diff --git a/waylib/src/server/protocols/private/wvirtualpointerv1.cpp b/waylib/src/server/protocols/private/wvirtualpointerv1.cpp new file mode 100644 index 000000000..d13226a0a --- /dev/null +++ b/waylib/src/server/protocols/private/wvirtualpointerv1.cpp @@ -0,0 +1,48 @@ +// Copyright (C) 2026 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "wvirtualpointerv1_p.h" +#include "private/wglobal_p.h" + +#include +#include + +QW_USE_NAMESPACE +WAYLIB_SERVER_BEGIN_NAMESPACE + +class Q_DECL_HIDDEN WVirtualPointerManagerV1Private : public WObjectPrivate +{ + W_DECLARE_PUBLIC(WVirtualPointerManagerV1) + +public: + explicit WVirtualPointerManagerV1Private(WVirtualPointerManagerV1 *qq) + : WObjectPrivate(qq) + { + } +}; + +WVirtualPointerManagerV1::WVirtualPointerManagerV1([[maybe_unused]] QObject *parent) + : WObject(*new WVirtualPointerManagerV1Private(this)) +{ +} + +QByteArrayView WVirtualPointerManagerV1::interfaceName() const +{ + return "zwlr_virtual_pointer_manager_v1"; +} + +void WVirtualPointerManagerV1::create(WServer *server) +{ + auto manager = qw_virtual_pointer_manager_v1::create(*server->handle()); + Q_ASSERT(manager); + m_handle = manager; + connect(manager, &qw_virtual_pointer_manager_v1::notify_new_virtual_pointer, + this, &WVirtualPointerManagerV1::newVirtualPointer); +} + +wl_global *WVirtualPointerManagerV1::global() const +{ + return nativeInterface()->handle()->global; +} + +WAYLIB_SERVER_END_NAMESPACE diff --git a/waylib/src/server/protocols/private/wvirtualpointerv1_p.h b/waylib/src/server/protocols/private/wvirtualpointerv1_p.h new file mode 100644 index 000000000..d658583fb --- /dev/null +++ b/waylib/src/server/protocols/private/wvirtualpointerv1_p.h @@ -0,0 +1,34 @@ +// Copyright (C) 2026 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#pragma once + +#include +#include + +#include + +struct wlr_virtual_pointer_v1_new_pointer_event; + +WAYLIB_SERVER_BEGIN_NAMESPACE + +class WVirtualPointerManagerV1Private; +class WAYLIB_SERVER_EXPORT WVirtualPointerManagerV1 : public QObject, public WObject, public WServerInterface +{ + Q_OBJECT + W_DECLARE_PRIVATE(WVirtualPointerManagerV1) + +public: + explicit WVirtualPointerManagerV1(QObject *parent = nullptr); + + QByteArrayView interfaceName() const override; + +Q_SIGNALS: + void newVirtualPointer(wlr_virtual_pointer_v1_new_pointer_event *event); + +private: + void create(WServer *server) override; + wl_global *global() const override; +}; + +WAYLIB_SERVER_END_NAMESPACE diff --git a/waylib/src/server/protocols/winputmethodhelper.cpp b/waylib/src/server/protocols/winputmethodhelper.cpp index dea623dea..0d68ed7e6 100644 --- a/waylib/src/server/protocols/winputmethodhelper.cpp +++ b/waylib/src/server/protocols/winputmethodhelper.cpp @@ -7,17 +7,16 @@ #include "wtextinputv2_p.h" #include "wtextinput_p.h" #include "winputmethodv2_p.h" -#include "wvirtualkeyboardv1_p.h" #include "winputpopupsurface.h" #include "wseat.h" #include "wsurface.h" #include "private/wglobal_p.h" #include +#include #include #include #include -#include #include #include @@ -29,18 +28,16 @@ WAYLIB_SERVER_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(qLcInputMethod, "waylib.server.im", QtInfoMsg) struct Q_DECL_HIDDEN GrabHandlerArg { - const WInputMethodHelper *const helper; qw_input_method_keyboard_grab_v2 *grab; }; void handleKey(struct wlr_seat_keyboard_grab *grab, uint32_t time_msec, uint32_t key, uint32_t state) { auto arg = reinterpret_cast(grab->data); - for (auto vk: arg->helper->virtualKeyboards()) { - if (wlr_keyboard_from_input_device(vk->handle()->handle()) == grab->seat->keyboard_state.keyboard) { - grab->seat->keyboard_state.default_grab->interface->key(grab, time_msec, key, state); - return; - } + if (grab->seat->keyboard_state.keyboard + && wlr_input_device_get_virtual_keyboard(&grab->seat->keyboard_state.keyboard->base)) { + grab->seat->keyboard_state.default_grab->interface->key(grab, time_msec, key, state); + return; } arg->grab->send_key(time_msec, Qt::Key(key), state); } @@ -48,11 +45,10 @@ void handleKey(struct wlr_seat_keyboard_grab *grab, uint32_t time_msec, uint32_t void handleModifiers(struct wlr_seat_keyboard_grab *grab, const struct wlr_keyboard_modifiers *modifiers) { auto arg = reinterpret_cast(grab->data); - for (auto vk: arg->helper->virtualKeyboards()) { - if (wlr_keyboard_from_input_device(vk->handle()->handle()) == grab->seat->keyboard_state.keyboard) { - grab->seat->keyboard_state.default_grab->interface->modifiers(grab, modifiers); - return; - } + if (grab->seat->keyboard_state.keyboard + && wlr_input_device_get_virtual_keyboard(&grab->seat->keyboard_state.keyboard->base)) { + grab->seat->keyboard_state.default_grab->interface->modifiers(grab, modifiers); + return; } arg->grab->send_modifiers(const_cast(modifiers)); } @@ -69,13 +65,12 @@ class Q_DECL_HIDDEN WInputMethodHelperPrivate : public WObjectPrivate , textInputManagerV1(server->attach()) , textInputManagerV2(server->attach()) , textInputManagerV3(server->attach()) - , virtualKeyboardManagerV1(server->attach()) , enabledTextInput(nullptr) , activeInputMethod(nullptr) , activeKeyboardGrab(nullptr) , keyboardGrab{} , grabInterface{} - , handlerArg({.helper = qq, .grab = nullptr}) + , handlerArg({.grab = nullptr}) { Q_ASSERT(server); Q_ASSERT(seat); @@ -91,7 +86,6 @@ class Q_DECL_HIDDEN WInputMethodHelperPrivate : public WObjectPrivate const QPointer textInputManagerV1; const QPointer textInputManagerV2; const QPointer textInputManagerV3; - const QPointer virtualKeyboardManagerV1; WTextInput *enabledTextInput { nullptr }; WInputMethodV2 *activeInputMethod { nullptr }; qw_input_method_keyboard_grab_v2 *activeKeyboardGrab {nullptr}; @@ -101,7 +95,6 @@ class Q_DECL_HIDDEN WInputMethodHelperPrivate : public WObjectPrivate GrabHandlerArg handlerArg; QList textInputs; - QList virtualKeyboards; QList popupSurfaces; }; @@ -113,7 +106,6 @@ WInputMethodHelper::WInputMethodHelper(WServer *server, WSeat *seat) d->seat->safeConnect(&WSeat::keyboardFocusSurfaceChanged, this, &WInputMethodHelper::resendKeyboardFocus); connect(d->inputMethodManagerV2, &WInputMethodManagerV2::newInputMethod, this, &WInputMethodHelper::handleNewIMV2); connect(d->textInputManagerV3, &WTextInputManagerV3::newTextInput, this, &WInputMethodHelper::handleNewTI); - connect(d->virtualKeyboardManagerV1, &WVirtualKeyboardManagerV1::newVirtualKeyboard, this, &WInputMethodHelper::handleNewVKV1); connect(d->textInputManagerV1, &WTextInputManagerV1::newTextInput, this, &WInputMethodHelper::handleNewTI); connect(d->textInputManagerV2, &WTextInputManagerV2::newTextInput, this, &WInputMethodHelper::handleNewTI); } @@ -126,7 +118,6 @@ WInputMethodHelper::~WInputMethodHelper() if (d->textInputManagerV1) d->textInputManagerV1->disconnect(this); if (d->textInputManagerV2) d->textInputManagerV2->disconnect(this); if (d->textInputManagerV3) d->textInputManagerV3->disconnect(this); - if (d->virtualKeyboardManagerV1) d->virtualKeyboardManagerV1->disconnect(this); } WTextInput *WInputMethodHelper::focusedTextInput() const @@ -183,12 +174,6 @@ qw_input_method_keyboard_grab_v2 *WInputMethodHelper::activeKeyboardGrab() const return d->activeKeyboardGrab; } -const QList &WInputMethodHelper::virtualKeyboards() const -{ - W_DC(WInputMethodHelper); - return d->virtualKeyboards; -} - void WInputMethodHelper::handleNewIMV2(qw_input_method_v2 *imv2) { W_D(WInputMethodHelper); @@ -223,7 +208,7 @@ void WInputMethodHelper::handleNewKGV2(qw_input_method_keyboard_grab_v2 *kgv2) }; auto setKeyboard = [](qw_input_method_keyboard_grab_v2 *kgv2, WInputDevice *keyboard) { if (keyboard) { - auto *virtualKeyboard = wlr_input_device_get_virtual_keyboard(*keyboard->handle()); + auto *virtualKeyboard = wlr_input_device_get_virtual_keyboard(keyboard->handle()->handle()); // refer to: // https://github.com/swaywm/sway/blob/master/sway/input/keyboard.c#L391 if (virtualKeyboard @@ -231,7 +216,7 @@ void WInputMethodHelper::handleNewKGV2(qw_input_method_keyboard_grab_v2 *kgv2) == wl_resource_get_client(kgv2->handle()->resource)) { return; } - kgv2->set_keyboard(wlr_keyboard_from_input_device(*keyboard->handle())); + kgv2->set_keyboard(wlr_keyboard_from_input_device(keyboard->handle()->handle())); } else { kgv2->set_keyboard(nullptr); } @@ -281,19 +266,6 @@ void WInputMethodHelper::handleNewIPSV2(qw_input_popup_surface_v2 *ipsv2) } } -void WInputMethodHelper::handleNewVKV1(wlr_virtual_keyboard_v1 *vkv1) -{ - W_D(WInputMethodHelper); - WInputDevice *keyboard = new WInputDevice(qw_input_device::from(&vkv1->keyboard.base)); - d->virtualKeyboards.append(keyboard); - d->seat->attachInputDevice(keyboard); - keyboard->safeConnect(&qw_input_device::before_destroy, this, [d, keyboard] () { - if (d->seat) d->seat->detachInputDevice(keyboard); - d->virtualKeyboards.removeOne(keyboard); - keyboard->safeDeleteLater(); - }); -} - void WInputMethodHelper::resendKeyboardFocus() { W_D(WInputMethodHelper); diff --git a/waylib/src/server/protocols/winputmethodhelper.h b/waylib/src/server/protocols/winputmethodhelper.h index e6cbdff51..dddd224d7 100644 --- a/waylib/src/server/protocols/winputmethodhelper.h +++ b/waylib/src/server/protocols/winputmethodhelper.h @@ -15,15 +15,12 @@ QW_BEGIN_NAMESPACE class qw_input_method_v2; class qw_input_method_keyboard_grab_v2; class qw_input_popup_surface_v2; -class qw_virtual_keyboard_v1; QW_END_NAMESPACE struct wlr_seat_keyboard_grab; -struct wlr_virtual_keyboard_v1; struct wlr_keyboard_modifiers; WAYLIB_SERVER_BEGIN_NAMESPACE class WServer; class WSeat; -class WInputDevice; class WInputMethodV2; class WInputMethodHelperPrivate; class WInputPopupSurface; @@ -42,12 +39,10 @@ class WAYLIB_SERVER_EXPORT WInputMethodHelper : public QObject, public WObject void inputPopupSurfaceV2Removed(WInputPopupSurface *popupSurface); private: - const QList &virtualKeyboards() const; void handleNewTI(WTextInput *ti); void handleNewIMV2(QW_NAMESPACE::qw_input_method_v2 *imv2); void handleNewKGV2(QW_NAMESPACE::qw_input_method_keyboard_grab_v2 *kgv2); void handleNewIPSV2(QW_NAMESPACE::qw_input_popup_surface_v2 *ipsv2); - void handleNewVKV1(wlr_virtual_keyboard_v1 *vkv1); void updateAllPopupSurfaces(QRect cursorRect); void updatePopupSurface(WInputPopupSurface *popup, QRect cursorRect); void notifyLeave(); diff --git a/waylib/src/server/protocols/wvirtualinputhelper.cpp b/waylib/src/server/protocols/wvirtualinputhelper.cpp new file mode 100644 index 000000000..5e1aab272 --- /dev/null +++ b/waylib/src/server/protocols/wvirtualinputhelper.cpp @@ -0,0 +1,159 @@ +// Copyright (C) 2026 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "wvirtualinputhelper.h" + +#include "private/wglobal_p.h" +#include "private/wvirtualkeyboardv1_p.h" +#include "private/wvirtualpointerv1_p.h" +#include "wcursor.h" +#include "winputdevice.h" +#include "woutput.h" +#include "wseat.h" +#include "wserver.h" + +#include +#include +#include +#include +#include + +QW_USE_NAMESPACE +WAYLIB_SERVER_BEGIN_NAMESPACE + +class Q_DECL_HIDDEN WVirtualInputHelperPrivate : public WObjectPrivate +{ + W_DECLARE_PUBLIC(WVirtualInputHelper) + +public: + explicit WVirtualInputHelperPrivate(WServer *s, WSeat *st, WVirtualInputHelper *qq) + : WObjectPrivate(qq) + , server(s) + , seat(st) + , virtualKeyboardManagerV1(server->attach()) + , virtualPointerManagerV1(server->attach()) + { + Q_ASSERT(server); + Q_ASSERT(seat); + Q_ASSERT(virtualKeyboardManagerV1); + Q_ASSERT(virtualPointerManagerV1); + } + + const QPointer server; + const QPointer seat; + const QPointer virtualKeyboardManagerV1; + const QPointer virtualPointerManagerV1; + QList virtualKeyboards; + QList virtualPointers; +}; + +WVirtualInputHelper::WVirtualInputHelper(WServer *server, WSeat *seat) + : QObject(server) + , WObject(*new WVirtualInputHelperPrivate(server, seat, this)) +{ + W_D(WVirtualInputHelper); + connect(d->virtualKeyboardManagerV1, &WVirtualKeyboardManagerV1::newVirtualKeyboard, + this, &WVirtualInputHelper::handleNewVKV1); + connect(d->virtualPointerManagerV1, &WVirtualPointerManagerV1::newVirtualPointer, + this, &WVirtualInputHelper::handleNewVPV1); +} + +WVirtualInputHelper::~WVirtualInputHelper() +{ + W_D(WVirtualInputHelper); + if (d->virtualKeyboardManagerV1) + d->virtualKeyboardManagerV1->disconnect(this); + if (d->virtualPointerManagerV1) + d->virtualPointerManagerV1->disconnect(this); +} + +bool WVirtualInputHelper::shouldAcceptSeat(::wlr_seat *suggestedSeat) const +{ + W_DC(WVirtualInputHelper); + return !suggestedSeat || (d->seat && d->seat->nativeHandle() == suggestedSeat); +} + +WInputDevice *WVirtualInputHelper::ensureDevice(qw_input_device *handle) const +{ + if (!handle) + return nullptr; + + if (auto *device = WInputDevice::fromHandle(handle)) + return device; + + return new WInputDevice(handle); +} + +void WVirtualInputHelper::attachDevice(WInputDevice *device) +{ + W_D(WVirtualInputHelper); + if (!device || !d->seat || device->seat() == d->seat) + return; + + if (device->seat()) + return; + + d->seat->attachInputDevice(device); +} + +void WVirtualInputHelper::detachDevice(WInputDevice *device) +{ + W_D(WVirtualInputHelper); + if (!device || !d->seat || device->seat() == d->seat) + return; + + if (device->seat()) + return; + + d->seat->detachInputDevice(device); +} + +void WVirtualInputHelper::maybeMapToOutput(WInputDevice *device, ::wlr_output *output) const +{ + W_DC(WVirtualInputHelper); + if (!device || !output || !d->seat || !d->seat->cursor()) + return; + + if (!WOutput::fromHandle(qw_output::from(output))) + return; + + d->seat->cursor()->handle()->map_input_to_output(device->handle()->handle(), output); +} + +void WVirtualInputHelper::handleNewVKV1(::wlr_virtual_keyboard_v1 *virtualKeyboard) +{ + W_D(WVirtualInputHelper); + auto *device = ensureDevice(qw_input_device::from(&virtualKeyboard->keyboard.base)); + if (!device || device->seat() || d->virtualKeyboards.contains(device)) + return; + + d->virtualKeyboards.append(device); + attachDevice(device); + device->safeConnect(&qw_input_device::before_destroy, this, [this, d, device] { + detachDevice(device); + d->virtualKeyboards.removeOne(device); + device->safeDeleteLater(); + }); +} + +void WVirtualInputHelper::handleNewVPV1(::wlr_virtual_pointer_v1_new_pointer_event *event) +{ + W_D(WVirtualInputHelper); + if (!event || !shouldAcceptSeat(event->suggested_seat)) + return; + + auto *device = ensureDevice(qw_input_device::from(&event->new_pointer->pointer.base)); + if (!device || device->seat() || d->virtualPointers.contains(device)) + return; + + d->virtualPointers.append(device); + attachDevice(device); + maybeMapToOutput(device, event->suggested_output); + device->safeConnect(&qw_input_device::before_destroy, this, [this, d, device] { + detachDevice(device); + d->virtualPointers.removeOne(device); + device->safeDeleteLater(); + }); +} + +WAYLIB_SERVER_END_NAMESPACE diff --git a/waylib/src/server/protocols/wvirtualinputhelper.h b/waylib/src/server/protocols/wvirtualinputhelper.h new file mode 100644 index 000000000..1525691c6 --- /dev/null +++ b/waylib/src/server/protocols/wvirtualinputhelper.h @@ -0,0 +1,44 @@ +// Copyright (C) 2026 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#pragma once + +#include "wglobal.h" + +#include + +QW_BEGIN_NAMESPACE +class qw_input_device; +QW_END_NAMESPACE + +struct wlr_output; +struct wlr_seat; +struct wlr_virtual_keyboard_v1; +struct wlr_virtual_pointer_v1_new_pointer_event; + +WAYLIB_SERVER_BEGIN_NAMESPACE + +class WInputDevice; +class WSeat; +class WServer; +class WVirtualInputHelperPrivate; +class WAYLIB_SERVER_EXPORT WVirtualInputHelper : public QObject, public WObject +{ + Q_OBJECT + W_DECLARE_PRIVATE(WVirtualInputHelper) + +public: + explicit WVirtualInputHelper(WServer *server, WSeat *seat); + ~WVirtualInputHelper() override; + +private: + void handleNewVKV1(::wlr_virtual_keyboard_v1 *virtualKeyboard); + void handleNewVPV1(::wlr_virtual_pointer_v1_new_pointer_event *event); + bool shouldAcceptSeat(::wlr_seat *suggestedSeat) const; + WInputDevice *ensureDevice(QW_NAMESPACE::qw_input_device *handle) const; + void attachDevice(WInputDevice *device); + void detachDevice(WInputDevice *device); + void maybeMapToOutput(WInputDevice *device, ::wlr_output *output) const; +}; + +WAYLIB_SERVER_END_NAMESPACE