#include #include #include #include #define private public #include #include #include #include #include #include #include #include #undef private #include #include using namespace Hyprutils::Utils; using namespace Hyprutils::String; #include "globals.hpp" // Do NOT change this function. APICALL EXPORT std::string PLUGIN_API_VERSION() { return HYPRLAND_API_VERSION; } static SDispatchResult test(std::string in) { bool success = true; std::string errors = ""; if (g_pConfigManager->m_configValueNumber != CONFIG_OPTIONS.size() + 1 /* autogenerated is special */) { errors += "config value number mismatches descriptions size\n"; success = false; } return SDispatchResult{ .success = success, .error = errors, }; } // Trigger a snap move event for the active window static SDispatchResult snapMove(std::string in) { const auto PLASTWINDOW = g_pCompositor->m_lastWindow.lock(); if (!PLASTWINDOW->m_isFloating) return {.success = false, .error = "Window must be floating"}; Vector2D pos = PLASTWINDOW->m_realPosition->goal(); Vector2D size = PLASTWINDOW->m_realSize->goal(); g_pLayoutManager->getCurrentLayout()->performSnap(pos, size, PLASTWINDOW, MBIND_MOVE, -1, size); *PLASTWINDOW->m_realPosition = pos.round(); return {}; } class CTestKeyboard : public IKeyboard { public: static SP create(bool isVirtual) { auto keeb = SP(new CTestKeyboard()); keeb->m_self = keeb; keeb->m_isVirtual = isVirtual; keeb->m_shareStates = !isVirtual; return keeb; } virtual bool isVirtual() { return m_isVirtual; } virtual SP aq() { return nullptr; } void sendKey(uint32_t key, bool pressed) { auto event = IKeyboard::SKeyEvent{ .timeMs = sc(Time::millis(Time::steadyNow())), .keycode = key, .state = pressed ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED, }; updatePressed(event.keycode, pressed); m_keyboardEvents.key.emit(event); } void destroy() { m_events.destroy.emit(); } private: bool m_isVirtual = false; }; class CTestMouse : public IPointer { public: static SP create(bool isVirtual) { auto maus = SP(new CTestMouse()); maus->m_self = maus; maus->m_isVirtual = isVirtual; maus->m_deviceName = "test-mouse"; maus->m_hlName = "test-mouse"; return maus; } virtual bool isVirtual() { return m_isVirtual; } virtual SP aq() { return nullptr; } void destroy() { m_events.destroy.emit(); } private: bool m_isVirtual = false; }; SP g_mouse; SP g_keyboard; static SDispatchResult pressAlt(std::string in) { g_pInputManager->m_lastMods = in == "1" ? HL_MODIFIER_ALT : 0; return {.success = true}; } static SDispatchResult simulateGesture(std::string in) { CVarList data(in); uint32_t fingers = 3; try { fingers = std::stoul(data[1]); } catch (...) { return {.success = false}; } if (data[0] == "down") { g_pTrackpadGestures->gestureBegin(IPointer::SSwipeBeginEvent{}); g_pTrackpadGestures->gestureUpdate(IPointer::SSwipeUpdateEvent{.fingers = fingers, .delta = {0, 300}}); g_pTrackpadGestures->gestureEnd(IPointer::SSwipeEndEvent{}); } else if (data[0] == "up") { g_pTrackpadGestures->gestureBegin(IPointer::SSwipeBeginEvent{}); g_pTrackpadGestures->gestureUpdate(IPointer::SSwipeUpdateEvent{.fingers = fingers, .delta = {0, -300}}); g_pTrackpadGestures->gestureEnd(IPointer::SSwipeEndEvent{}); } else if (data[0] == "left") { g_pTrackpadGestures->gestureBegin(IPointer::SSwipeBeginEvent{}); g_pTrackpadGestures->gestureUpdate(IPointer::SSwipeUpdateEvent{.fingers = fingers, .delta = {-300, 0}}); g_pTrackpadGestures->gestureEnd(IPointer::SSwipeEndEvent{}); } else { g_pTrackpadGestures->gestureBegin(IPointer::SSwipeBeginEvent{}); g_pTrackpadGestures->gestureUpdate(IPointer::SSwipeUpdateEvent{.fingers = fingers, .delta = {300, 0}}); g_pTrackpadGestures->gestureEnd(IPointer::SSwipeEndEvent{}); } return {.success = true}; } static SDispatchResult vkb(std::string in) { auto tkb0 = CTestKeyboard::create(false); auto tkb1 = CTestKeyboard::create(false); auto vkb0 = CTestKeyboard::create(true); g_pInputManager->newKeyboard(tkb0); g_pInputManager->newKeyboard(tkb1); g_pInputManager->newKeyboard(vkb0); CScopeGuard x([&] { tkb0->destroy(); tkb1->destroy(); vkb0->destroy(); }); const auto& PRESSED = g_pInputManager->getKeysFromAllKBs(); const uint32_t TESTKEY = 1; tkb0->sendKey(TESTKEY, true); if (!std::ranges::contains(PRESSED, TESTKEY)) { return { .success = false, .error = "Expected pressed key not found", }; } tkb1->sendKey(TESTKEY, true); tkb0->sendKey(TESTKEY, false); if (!std::ranges::contains(PRESSED, TESTKEY)) { return { .success = false, .error = "Expected pressed key not found (kb share state)", }; } vkb0->sendKey(TESTKEY, true); tkb1->sendKey(TESTKEY, false); if (std::ranges::contains(PRESSED, TESTKEY)) { return { .success = false, .error = "Expected released key found in pressed (vkb no share state)", }; } return {}; } static SDispatchResult scroll(std::string in) { double by; try { by = std::stod(in); } catch (...) { return SDispatchResult{.success = false, .error = "invalid input"}; } Debug::log(LOG, "tester: scrolling by {}", by); g_mouse->m_pointerEvents.axis.emit(IPointer::SAxisEvent{ .delta = by, .deltaDiscrete = 120, .mouse = true, }); return {}; } static SDispatchResult keybind(std::string in) { CVarList data(in); // 0 = release, 1 = press bool press; // See src/devices/IKeyboard.hpp : eKeyboardModifiers for modifier bitmasks // 0 = none, eKeyboardModifiers is shifted to start at 1 uint32_t modifier; // keycode uint32_t key; try { press = std::stoul(data[0]) == 1; modifier = std::stoul(data[1]); key = std::stoul(data[2]) - 8; // xkb offset } catch (...) { return {.success = false, .error = "invalid input"}; } uint32_t modifierMask = 0; if (modifier > 0) modifierMask = 1 << (modifier - 1); g_pInputManager->m_lastMods = modifierMask; g_keyboard->sendKey(key, press); return {}; } APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { PHANDLE = handle; HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:test", ::test); HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:snapmove", ::snapMove); HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:vkb", ::vkb); HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:alt", ::pressAlt); HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:gesture", ::simulateGesture); HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:scroll", ::scroll); HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:keybind", ::keybind); // init mouse g_mouse = CTestMouse::create(false); g_pInputManager->newMouse(g_mouse); // init keyboard g_keyboard = CTestKeyboard::create(false); g_pInputManager->newKeyboard(g_keyboard); return {"hyprtestplugin", "hyprtestplugin", "Vaxry", "1.0"}; } APICALL EXPORT void PLUGIN_EXIT() { g_mouse->destroy(); g_mouse.reset(); g_keyboard->destroy(); g_keyboard.reset(); }