diff options
-rwxr-xr-x | CMakeLists.txt | 1 | ||||
-rw-r--r-- | protocols/meson.build | 1 | ||||
-rw-r--r-- | protocols/virtual-keyboard-unstable-v1.xml | 113 | ||||
-rw-r--r-- | src/Compositor.cpp | 4 | ||||
-rw-r--r-- | src/Compositor.hpp | 51 | ||||
-rw-r--r-- | src/events/Devices.cpp | 6 | ||||
-rw-r--r-- | src/events/Events.hpp | 3 | ||||
-rw-r--r-- | src/helpers/WLClasses.hpp | 29 | ||||
-rw-r--r-- | src/includes.hpp | 1 | ||||
-rw-r--r-- | src/managers/ProtocolManager.cpp | 2 | ||||
-rw-r--r-- | src/managers/input/InputManager.cpp | 32 | ||||
-rw-r--r-- | src/managers/input/InputManager.hpp | 4 | ||||
-rw-r--r-- | src/protocols/VirtualKeyboard.cpp | 136 | ||||
-rw-r--r-- | src/protocols/VirtualKeyboard.hpp | 54 |
14 files changed, 370 insertions, 67 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 675844e0..d485977c 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -261,6 +261,7 @@ protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v protocolNew("protocols/wlr-gamma-control-unstable-v1.xml" "wlr-gamma-control-unstable-v1" true) protocolNew("protocols/wlr-foreign-toplevel-management-unstable-v1.xml" "wlr-foreign-toplevel-management-unstable-v1" true) protocolNew("protocols/wlr-output-power-management-unstable-v1.xml" "wlr-output-power-management-unstable-v1" true) +protocolNew("protocols/virtual-keyboard-unstable-v1.xml" "virtual-keyboard-unstable-v1" true) protocolNew("protocols/input-method-unstable-v2.xml" "input-method-unstable-v2" true) protocolNew("staging/tearing-control/tearing-control-v1.xml" "tearing-control-v1" false) protocolNew("staging/fractional-scale/fractional-scale-v1.xml" "fractional-scale-v1" false) diff --git a/protocols/meson.build b/protocols/meson.build index 4017ff27..57bca3d1 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -39,6 +39,7 @@ new_protocols = [ ['wlr-foreign-toplevel-management-unstable-v1.xml'], ['wlr-output-power-management-unstable-v1.xml'], ['input-method-unstable-v2.xml'], + ['virtual-keyboard-unstable-v1.xml'], [wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'], [wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'], [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'], diff --git a/protocols/virtual-keyboard-unstable-v1.xml b/protocols/virtual-keyboard-unstable-v1.xml new file mode 100644 index 00000000..5095c91b --- /dev/null +++ b/protocols/virtual-keyboard-unstable-v1.xml @@ -0,0 +1,113 @@ +<?xml version="1.0" encoding="UTF-8"?> +<protocol name="virtual_keyboard_unstable_v1"> + <copyright> + Copyright © 2008-2011 Kristian Høgsberg + Copyright © 2010-2013 Intel Corporation + Copyright © 2012-2013 Collabora, Ltd. + Copyright © 2018 Purism SPC + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + </copyright> + + <interface name="zwp_virtual_keyboard_v1" version="1"> + <description summary="virtual keyboard"> + The virtual keyboard provides an application with requests which emulate + the behaviour of a physical keyboard. + + This interface can be used by clients on its own to provide raw input + events, or it can accompany the input method protocol. + </description> + + <request name="keymap"> + <description summary="keyboard mapping"> + Provide a file descriptor to the compositor which can be + memory-mapped to provide a keyboard mapping description. + + Format carries a value from the keymap_format enumeration. + </description> + <arg name="format" type="uint" summary="keymap format"/> + <arg name="fd" type="fd" summary="keymap file descriptor"/> + <arg name="size" type="uint" summary="keymap size, in bytes"/> + </request> + + <enum name="error"> + <entry name="no_keymap" value="0" summary="No keymap was set"/> + </enum> + + <request name="key"> + <description summary="key event"> + A key was pressed or released. + The time argument is a timestamp with millisecond granularity, with an + undefined base. All requests regarding a single object must share the + same clock. + + Keymap must be set before issuing this request. + + State carries a value from the key_state enumeration. + </description> + <arg name="time" type="uint" summary="timestamp with millisecond granularity"/> + <arg name="key" type="uint" summary="key that produced the event"/> + <arg name="state" type="uint" summary="physical state of the key"/> + </request> + + <request name="modifiers"> + <description summary="modifier and group state"> + Notifies the compositor that the modifier and/or group state has + changed, and it should update state. + + The client should use wl_keyboard.modifiers event to synchronize its + internal state with seat state. + + Keymap must be set before issuing this request. + </description> + <arg name="mods_depressed" type="uint" summary="depressed modifiers"/> + <arg name="mods_latched" type="uint" summary="latched modifiers"/> + <arg name="mods_locked" type="uint" summary="locked modifiers"/> + <arg name="group" type="uint" summary="keyboard layout"/> + </request> + + <request name="destroy" type="destructor" since="1"> + <description summary="destroy the virtual keyboard keyboard object"/> + </request> + </interface> + + <interface name="zwp_virtual_keyboard_manager_v1" version="1"> + <description summary="virtual keyboard manager"> + A virtual keyboard manager allows an application to provide keyboard + input events as if they came from a physical keyboard. + </description> + + <enum name="error"> + <entry name="unauthorized" value="0" summary="client not authorized to use the interface"/> + </enum> + + <request name="create_virtual_keyboard"> + <description summary="Create a new virtual keyboard"> + Creates a new virtual keyboard associated to a seat. + + If the compositor enables a keyboard to perform arbitrary actions, it + should present an error when an untrusted client requests a new + keyboard. + </description> + <arg name="seat" type="object" interface="wl_seat"/> + <arg name="id" type="new_id" interface="zwp_virtual_keyboard_v1"/> + </request> + </interface> +</protocol> diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 9ed0ea38..80e61a25 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -245,8 +245,6 @@ void CCompositor::initServer() { m_sWLROutputMgr = wlr_output_manager_v1_create(m_sWLDisplay); - m_sWLRVKeyboardMgr = wlr_virtual_keyboard_manager_v1_create(m_sWLDisplay); - m_sWLRVirtPtrMgr = wlr_virtual_pointer_manager_v1_create(m_sWLDisplay); m_sWRLDRMLeaseMgr = wlr_drm_lease_v1_manager_create(m_sWLDisplay, m_sWLRBackend); @@ -308,7 +306,6 @@ void CCompositor::initAllSignals() { addWLSignal(&m_sWLROutputMgr->events.apply, &Events::listen_outputMgrApply, m_sWLROutputMgr, "OutputMgr"); addWLSignal(&m_sWLROutputMgr->events.test, &Events::listen_outputMgrTest, m_sWLROutputMgr, "OutputMgr"); addWLSignal(&m_sWLRVirtPtrMgr->events.new_virtual_pointer, &Events::listen_newVirtPtr, m_sWLRVirtPtrMgr, "VirtPtrMgr"); - addWLSignal(&m_sWLRVKeyboardMgr->events.new_virtual_keyboard, &Events::listen_newVirtualKeyboard, m_sWLRVKeyboardMgr, "VKeyboardMgr"); addWLSignal(&m_sWLRRenderer->events.destroy, &Events::listen_RendererDestroy, m_sWLRRenderer, "WLRRenderer"); if (m_sWRLDRMLeaseMgr) @@ -350,7 +347,6 @@ void CCompositor::removeAllSignals() { removeWLSignal(&Events::listen_outputMgrApply); removeWLSignal(&Events::listen_outputMgrTest); removeWLSignal(&Events::listen_newVirtPtr); - removeWLSignal(&Events::listen_newVirtualKeyboard); removeWLSignal(&Events::listen_RendererDestroy); if (m_sWRLDRMLeaseMgr) diff --git a/src/Compositor.hpp b/src/Compositor.hpp index b867742b..175688c7 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -40,32 +40,31 @@ class CCompositor { ~CCompositor(); // ------------------ WLR BASICS ------------------ // - wl_display* m_sWLDisplay; - wl_event_loop* m_sWLEventLoop; - wlr_backend* m_sWLRBackend; - wlr_session* m_sWLRSession; - wlr_renderer* m_sWLRRenderer; - wlr_allocator* m_sWLRAllocator; - wlr_compositor* m_sWLRCompositor; - wlr_subcompositor* m_sWLRSubCompositor; - wlr_data_device_manager* m_sWLRDataDevMgr; - wlr_drm* m_sWRLDRM; - wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr; - wlr_output_layout* m_sWLROutputLayout; - wlr_layer_shell_v1* m_sWLRLayerShell; - wlr_xdg_shell* m_sWLRXDGShell; - wlr_cursor* m_sWLRCursor; - wlr_virtual_keyboard_manager_v1* m_sWLRVKeyboardMgr; - wlr_output_manager_v1* m_sWLROutputMgr; - wlr_presentation* m_sWLRPresentation; - wlr_egl* m_sWLREGL; - int m_iDRMFD; - wlr_server_decoration_manager* m_sWLRServerDecoMgr; - wlr_virtual_pointer_manager_v1* m_sWLRVirtPtrMgr; - wlr_tablet_manager_v2* m_sWLRTabletManager; - wlr_xdg_foreign_registry* m_sWLRForeignRegistry; - wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf; - wlr_backend* m_sWLRHeadlessBackend; + wl_display* m_sWLDisplay; + wl_event_loop* m_sWLEventLoop; + wlr_backend* m_sWLRBackend; + wlr_session* m_sWLRSession; + wlr_renderer* m_sWLRRenderer; + wlr_allocator* m_sWLRAllocator; + wlr_compositor* m_sWLRCompositor; + wlr_subcompositor* m_sWLRSubCompositor; + wlr_data_device_manager* m_sWLRDataDevMgr; + wlr_drm* m_sWRLDRM; + wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr; + wlr_output_layout* m_sWLROutputLayout; + wlr_layer_shell_v1* m_sWLRLayerShell; + wlr_xdg_shell* m_sWLRXDGShell; + wlr_cursor* m_sWLRCursor; + wlr_output_manager_v1* m_sWLROutputMgr; + wlr_presentation* m_sWLRPresentation; + wlr_egl* m_sWLREGL; + int m_iDRMFD; + wlr_server_decoration_manager* m_sWLRServerDecoMgr; + wlr_virtual_pointer_manager_v1* m_sWLRVirtPtrMgr; + wlr_tablet_manager_v2* m_sWLRTabletManager; + wlr_xdg_foreign_registry* m_sWLRForeignRegistry; + wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf; + wlr_backend* m_sWLRHeadlessBackend; // ------------------------------------------------- // std::string m_szHyprTempDataRoot = ""; diff --git a/src/events/Devices.cpp b/src/events/Devices.cpp index 43433ba2..bf72d89f 100644 --- a/src/events/Devices.cpp +++ b/src/events/Devices.cpp @@ -140,12 +140,6 @@ void Events::listener_pinchEnd(wl_listener* listener, void* data) { PROTO::pointerGestures->pinchEnd(EV->time_msec, EV->cancelled); } -void Events::listener_newVirtualKeyboard(wl_listener* listener, void* data) { - const auto WLRKB = (wlr_virtual_keyboard_v1*)data; - - g_pInputManager->newVirtualKeyboard(&WLRKB->keyboard.base); -} - void Events::listener_touchBegin(wl_listener* listener, void* data) { g_pInputManager->onTouchDown((wlr_touch_down_event*)data); } diff --git a/src/events/Events.hpp b/src/events/Events.hpp index 2dabac11..c7e98e65 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -106,9 +106,6 @@ namespace Events { LISTENER(pinchUpdate); LISTENER(pinchEnd); - // IME - LISTENER(newVirtualKeyboard); - // Touch LISTENER(touchBegin); LISTENER(touchEnd); diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index 2f14059b..d9b3ba20 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -10,6 +10,7 @@ #include "Region.hpp" class CMonitor; +class CVirtualKeyboard; struct SRenderData { CMonitor* pMonitor; @@ -71,23 +72,25 @@ struct SKeyboard { DYNLISTENER(keyboardKeymap); DYNLISTENER(keyboardDestroy); - bool isVirtual = false; - bool active = false; - bool enabled = true; + bool isVirtual = false; + bool active = false; + bool enabled = true; - xkb_layout_index_t activeLayout = 0; - xkb_state* xkbTranslationState = nullptr; + WP<CVirtualKeyboard> virtKeyboard; - std::string name = ""; - std::string xkbFilePath = ""; + xkb_layout_index_t activeLayout = 0; + xkb_state* xkbTranslationState = nullptr; - SStringRuleNames currentRules; - int repeatRate = 0; - int repeatDelay = 0; - int numlockOn = -1; - bool resolveBindsBySym = false; + std::string name = ""; + std::string xkbFilePath = ""; - void updateXKBTranslationState(xkb_keymap* const keymap = nullptr); + SStringRuleNames currentRules; + int repeatRate = 0; + int repeatDelay = 0; + int numlockOn = -1; + bool resolveBindsBySym = false; + + void updateXKBTranslationState(xkb_keymap* const keymap = nullptr); // For the list lookup bool operator==(const SKeyboard& rhs) const { diff --git a/src/includes.hpp b/src/includes.hpp index 15d5c1aa..052c973e 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -62,7 +62,6 @@ extern "C" { #include <wlr/types/wlr_seat.h> #include <wlr/types/wlr_server_decoration.h> #include <wlr/types/wlr_viewporter.h> -#include <wlr/types/wlr_virtual_keyboard_v1.h> #include <wlr/types/wlr_xdg_output_v1.h> #include <wlr/types/wlr_xdg_shell.h> #include <wlr/types/wlr_subcompositor.h> diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 09ca5206..122e2ff1 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -20,6 +20,7 @@ #include "../protocols/IdleNotify.hpp" #include "../protocols/SessionLock.hpp" #include "../protocols/InputMethodV2.hpp" +#include "../protocols/VirtualKeyboard.hpp" CProtocolManager::CProtocolManager() { @@ -43,6 +44,7 @@ CProtocolManager::CProtocolManager() { PROTO::idle = std::make_unique<CIdleNotifyProtocol>(&ext_idle_notifier_v1_interface, 1, "IdleNotify"); PROTO::sessionLock = std::make_unique<CSessionLockProtocol>(&ext_session_lock_manager_v1_interface, 1, "SessionLock"); PROTO::ime = std::make_unique<CInputMethodV2Protocol>(&zwp_input_method_manager_v2_interface, 1, "IMEv2"); + PROTO::virtualKeyboard = std::make_unique<CVirtualKeyboardProtocol>(&zwp_virtual_keyboard_manager_v1_interface, 1, "VirtualKeyboard"); // Old protocol implementations. // TODO: rewrite them to use hyprwayland-scanner. diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 7d14719f..7b851d88 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -11,6 +11,7 @@ #include "../../protocols/IdleNotify.hpp" #include "../../protocols/SessionLock.hpp" #include "../../protocols/InputMethodV2.hpp" +#include "../../protocols/VirtualKeyboard.hpp" CInputManager::CInputManager() { m_sListeners.setCursorShape = PROTO::cursorShape->events.setShape.registerListener([this](std::any data) { @@ -37,6 +38,8 @@ CInputManager::CInputManager() { }); m_sListeners.newIdleInhibitor = PROTO::idleInhibit->events.newIdleInhibitor.registerListener([this](std::any data) { this->newIdleInhibitor(data); }); + m_sListeners.newVirtualKeyboard = + PROTO::virtualKeyboard->events.newKeyboard.registerListener([this](std::any data) { this->newVirtualKeyboard(std::any_cast<SP<CVirtualKeyboard>>(data)); }); } CInputManager::~CInputManager() { @@ -786,23 +789,24 @@ void CInputManager::newKeyboard(wlr_input_device* keyboard) { Debug::log(LOG, "New keyboard created, pointers Hypr: {:x} and WLR: {:x}", (uintptr_t)PNEWKEYBOARD, (uintptr_t)keyboard); } -void CInputManager::newVirtualKeyboard(wlr_input_device* keyboard) { +void CInputManager::newVirtualKeyboard(SP<CVirtualKeyboard> keyboard) { const auto PNEWKEYBOARD = &m_lKeyboards.emplace_back(); - PNEWKEYBOARD->keyboard = keyboard; - PNEWKEYBOARD->isVirtual = true; + PNEWKEYBOARD->keyboard = &keyboard->wlr()->base; + PNEWKEYBOARD->isVirtual = true; + PNEWKEYBOARD->virtKeyboard = keyboard; try { - PNEWKEYBOARD->name = getNameForNewDevice(keyboard->name); + PNEWKEYBOARD->name = getNameForNewDevice(keyboard->wlr()->base.name); } catch (std::exception& e) { Debug::log(ERR, "Keyboard had no name???"); // logic error } - PNEWKEYBOARD->hyprListener_keyboardMod.initCallback(&wlr_keyboard_from_input_device(keyboard)->events.modifiers, &Events::listener_keyboardMod, PNEWKEYBOARD, "Keyboard"); - PNEWKEYBOARD->hyprListener_keyboardKey.initCallback(&wlr_keyboard_from_input_device(keyboard)->events.key, &Events::listener_keyboardKey, PNEWKEYBOARD, "Keyboard"); - PNEWKEYBOARD->hyprListener_keyboardDestroy.initCallback(&keyboard->events.destroy, &Events::listener_keyboardDestroy, PNEWKEYBOARD, "Keyboard"); + PNEWKEYBOARD->hyprListener_keyboardMod.initCallback(&keyboard->wlr()->events.modifiers, &Events::listener_keyboardMod, PNEWKEYBOARD, "VKeyboard"); + PNEWKEYBOARD->hyprListener_keyboardKey.initCallback(&keyboard->wlr()->events.key, &Events::listener_keyboardKey, PNEWKEYBOARD, "VKeyboard"); + PNEWKEYBOARD->hyprListener_keyboardDestroy.initCallback(&keyboard->wlr()->base.events.destroy, &Events::listener_keyboardDestroy, PNEWKEYBOARD, "VKeyboard"); PNEWKEYBOARD->hyprListener_keyboardKeymap.initCallback( - &wlr_keyboard_from_input_device(keyboard)->events.keymap, + &keyboard->wlr()->events.keymap, [&](void* owner, void* data) { const auto PKEYBOARD = (SKeyboard*)owner; const auto LAYOUT = getActiveLayoutForKeyboard(PKEYBOARD); @@ -810,7 +814,7 @@ void CInputManager::newVirtualKeyboard(wlr_input_device* keyboard) { g_pEventManager->postEvent(SHyprIPCEvent{"activelayout", PKEYBOARD->name + "," + LAYOUT}); EMIT_HOOK_EVENT("activeLayout", (std::vector<void*>{PKEYBOARD, (void*)&LAYOUT})); }, - PNEWKEYBOARD, "Keyboard"); + PNEWKEYBOARD, "VKeyboard"); disableAllKeyboards(true); @@ -820,9 +824,9 @@ void CInputManager::newVirtualKeyboard(wlr_input_device* keyboard) { applyConfigToKeyboard(PNEWKEYBOARD); - wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(keyboard)); + wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, keyboard->wlr()); - Debug::log(LOG, "New virtual keyboard created, pointers Hypr: {:x} and WLR: {:x}", (uintptr_t)PNEWKEYBOARD, (uintptr_t)keyboard); + Debug::log(LOG, "New virtual keyboard created, pointers Hypr: {:x} and WLR: {:x}", (uintptr_t)PNEWKEYBOARD, (uintptr_t)keyboard->wlr()); } void CInputManager::setKeyboardLayout() { @@ -1276,8 +1280,10 @@ void CInputManager::onKeyboardMod(void* data, SKeyboard* pKeyboard) { } bool CInputManager::shouldIgnoreVirtualKeyboard(SKeyboard* pKeyboard) { - return !pKeyboard || - (!m_sIMERelay.m_pIME.expired() && m_sIMERelay.m_pIME.lock()->grabClient() == wl_resource_get_client(wlr_input_device_get_virtual_keyboard(pKeyboard->keyboard)->resource)); + if (!pKeyboard->isVirtual) + return false; + + return !pKeyboard || (!m_sIMERelay.m_pIME.expired() && m_sIMERelay.m_pIME.lock()->grabClient() == pKeyboard->virtKeyboard.lock()->client()); } void CInputManager::refocus() { diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 08e9e831..27551249 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -11,6 +11,7 @@ class CPointerConstraint; class CWindow; class CIdleInhibitor; +class CVirtualKeyboard; enum eClickBehaviorMode { CLICKMODE_DEFAULT = 0, @@ -77,7 +78,7 @@ class CInputManager { void onKeyboardMod(void*, SKeyboard*); void newKeyboard(wlr_input_device*); - void newVirtualKeyboard(wlr_input_device*); + void newVirtualKeyboard(SP<CVirtualKeyboard>); void newMouse(wlr_input_device*, bool virt = false); void newTouchDevice(wlr_input_device*); void newSwitch(wlr_input_device*); @@ -199,6 +200,7 @@ class CInputManager { struct { CHyprSignalListener setCursorShape; CHyprSignalListener newIdleInhibitor; + CHyprSignalListener newVirtualKeyboard; } m_sListeners; bool m_bCursorImageOverridden = false; diff --git a/src/protocols/VirtualKeyboard.cpp b/src/protocols/VirtualKeyboard.cpp new file mode 100644 index 00000000..fa364a96 --- /dev/null +++ b/src/protocols/VirtualKeyboard.cpp @@ -0,0 +1,136 @@ +#include "VirtualKeyboard.hpp" +#include <sys/mman.h> + +#define LOGM PROTO::virtualKeyboard->protoLog + +static const struct wlr_keyboard_impl virtualKeyboardImpl = { + .name = "virtual-keyboard", +}; + +CVirtualKeyboard::CVirtualKeyboard(SP<CZwpVirtualKeyboardV1> resource_) : resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CZwpVirtualKeyboardV1* r) { + events.destroy.emit(); + PROTO::virtualKeyboard->destroyResource(this); + }); + resource->setOnDestroy([this](CZwpVirtualKeyboardV1* r) { + events.destroy.emit(); + PROTO::virtualKeyboard->destroyResource(this); + }); + + resource->setKey([this](CZwpVirtualKeyboardV1* r, uint32_t timeMs, uint32_t key, uint32_t state) { + if (!hasKeymap) { + r->error(ZWP_VIRTUAL_KEYBOARD_V1_ERROR_NO_KEYMAP, "Key event received before a keymap was set"); + return; + } + + wlr_keyboard_key_event event = { + .time_msec = timeMs, + .keycode = key, + .update_state = false, + .state = (wl_keyboard_key_state)state, + }; + wlr_keyboard_notify_key(&keyboard, &event); + }); + + resource->setModifiers([this](CZwpVirtualKeyboardV1* r, uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) { + if (!hasKeymap) { + r->error(ZWP_VIRTUAL_KEYBOARD_V1_ERROR_NO_KEYMAP, "Mods event received before a keymap was set"); + return; + } + + wlr_keyboard_notify_modifiers(&keyboard, depressed, latched, locked, group); + }); + + resource->setKeymap([this](CZwpVirtualKeyboardV1* r, uint32_t fmt, int32_t fd, uint32_t len) { + auto xkbContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!xkbContext) { + LOGM(ERR, "xkbContext creation failed"); + r->noMemory(); + close(fd); + return; + } + + auto keymapData = mmap(nullptr, len, PROT_READ, MAP_PRIVATE, fd, 0); + if (keymapData == MAP_FAILED) { + LOGM(ERR, "keymapData alloc failed"); + xkb_context_unref(xkbContext); + r->noMemory(); + close(fd); + return; + } + + auto xkbKeymap = xkb_keymap_new_from_string(xkbContext, (const char*)keymapData, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); + munmap(keymapData, len); + + if (!xkbKeymap) { + LOGM(ERR, "xkbKeymap creation failed"); + xkb_context_unref(xkbContext); + r->noMemory(); + close(fd); + return; + } + + wlr_keyboard_set_keymap(&keyboard, xkbKeymap); + hasKeymap = true; + + xkb_keymap_unref(xkbKeymap); + xkb_context_unref(xkbContext); + close(fd); + }); + + wlr_keyboard_init(&keyboard, &virtualKeyboardImpl, "CVirtualKeyboard"); +} + +CVirtualKeyboard::~CVirtualKeyboard() { + wlr_keyboard_finish(&keyboard); + events.destroy.emit(); +} + +bool CVirtualKeyboard::good() { + return resource->resource(); +} + +wlr_keyboard* CVirtualKeyboard::wlr() { + return &keyboard; +} + +wl_client* CVirtualKeyboard::client() { + return resource->client(); +} + +CVirtualKeyboardProtocol::CVirtualKeyboardProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CVirtualKeyboardProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(std::make_unique<CZwpVirtualKeyboardManagerV1>(client, ver, id)).get(); + RESOURCE->setOnDestroy([this](CZwpVirtualKeyboardManagerV1* p) { this->onManagerResourceDestroy(p->resource()); }); + + RESOURCE->setCreateVirtualKeyboard([this](CZwpVirtualKeyboardManagerV1* pMgr, wl_resource* seat, uint32_t id) { this->onCreateKeeb(pMgr, seat, id); }); +} + +void CVirtualKeyboardProtocol::onManagerResourceDestroy(wl_resource* res) { + std::erase_if(m_vManagers, [&](const auto& other) { return other->resource() == res; }); +} + +void CVirtualKeyboardProtocol::destroyResource(CVirtualKeyboard* keeb) { + std::erase_if(m_vKeyboards, [&](const auto& other) { return other.get() == keeb; }); +} + +void CVirtualKeyboardProtocol::onCreateKeeb(CZwpVirtualKeyboardManagerV1* pMgr, wl_resource* seat, uint32_t id) { + + const auto RESOURCE = m_vKeyboards.emplace_back(std::make_shared<CVirtualKeyboard>(std::make_shared<CZwpVirtualKeyboardV1>(pMgr->client(), pMgr->version(), id))); + + if (!RESOURCE->good()) { + pMgr->noMemory(); + m_vKeyboards.pop_back(); + return; + } + + LOGM(LOG, "New VKeyboard at id {}", id); + + events.newKeyboard.emit(RESOURCE); +}
\ No newline at end of file diff --git a/src/protocols/VirtualKeyboard.hpp b/src/protocols/VirtualKeyboard.hpp new file mode 100644 index 00000000..b922b0c5 --- /dev/null +++ b/src/protocols/VirtualKeyboard.hpp @@ -0,0 +1,54 @@ +#pragma once + +#include <memory> +#include <vector> +#include <cstdint> +#include "WaylandProtocol.hpp" +#include "virtual-keyboard-unstable-v1.hpp" +#include "../helpers/signal/Signal.hpp" + +class CVirtualKeyboard { + public: + CVirtualKeyboard(SP<CZwpVirtualKeyboardV1> resource_); + ~CVirtualKeyboard(); + + struct { + CSignal destroy; + } events; + + bool good(); + wlr_keyboard* wlr(); + wl_client* client(); + + private: + SP<CZwpVirtualKeyboardV1> resource; + wlr_keyboard keyboard; + + bool hasKeymap = false; +}; + +class CVirtualKeyboardProtocol : public IWaylandProtocol { + public: + CVirtualKeyboardProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + struct { + CSignal newKeyboard; // SP<CVirtualKeyboard> + } events; + + private: + void onManagerResourceDestroy(wl_resource* res); + void destroyResource(CVirtualKeyboard* keeb); + void onCreateKeeb(CZwpVirtualKeyboardManagerV1* pMgr, wl_resource* seat, uint32_t id); + + // + std::vector<UP<CZwpVirtualKeyboardManagerV1>> m_vManagers; + std::vector<SP<CVirtualKeyboard>> m_vKeyboards; + + friend class CVirtualKeyboard; +}; + +namespace PROTO { + inline UP<CVirtualKeyboardProtocol> virtualKeyboard; +}; |