From 067b953526d9bd1e03ada6901d8c502683a91631 Mon Sep 17 00:00:00 2001 From: Elias Steurer Date: Fri, 3 Nov 2023 12:44:54 +0100 Subject: [PATCH] Add key input support to qml wallpaper --- Content/wallpaper_qml/main.qml | 12 ++ ScreenPlayWallpaper/qml/Test.qml | 33 +++- .../src/windowsintegration.cpp | 43 +++++ ScreenPlayWallpaper/src/windowsintegration.h | 13 +- ScreenPlayWallpaper/src/winwindow.cpp | 176 +++++++++++++++++- ScreenPlayWallpaper/src/winwindow.h | 1 + 6 files changed, 263 insertions(+), 15 deletions(-) diff --git a/Content/wallpaper_qml/main.qml b/Content/wallpaper_qml/main.qml index 92e21a65..441b898c 100644 --- a/Content/wallpaper_qml/main.qml +++ b/Content/wallpaper_qml/main.qml @@ -3,6 +3,7 @@ import QtQuick import QtQuick.Layouts import QtQuick.Controls import QtQuick.Controls.Material +import ScreenPlayWallpaper Rectangle { id: root @@ -23,5 +24,16 @@ Rectangle { Layout.fillWidth: true onClicked: root.counter++ } + TextField { + placeholderText: "Edit me" + } + Button { + text: "Exit" + onClicked: { + Qt.callLater(function () { + Wallpaper.terminate(); + }); + } + } } } diff --git a/ScreenPlayWallpaper/qml/Test.qml b/ScreenPlayWallpaper/qml/Test.qml index 76fa0f6d..befb8cc3 100644 --- a/ScreenPlayWallpaper/qml/Test.qml +++ b/ScreenPlayWallpaper/qml/Test.qml @@ -164,6 +164,7 @@ Rectangle { } Row { + id: rowCounter spacing: 20 anchors { @@ -205,18 +206,30 @@ Rectangle { } } - // WebView { - // width: 1000 - // height: 400 - // url: "https://screen-play.app" + Column { + + anchors { + horizontalCenter: parent.horizontalCenter + top: rowCounter.bottom + topMargin: 20 + } + spacing: 20 + TextField { + placeholderText: "Edit me" + + } + Button { + text: "Exit" + onClicked: { + Qt.callLater(function () { + Wallpaper.terminate(); + }); + } + } + + } - // anchors { - // horizontalCenter: parent.horizontalCenter - // bottom: parent.bottom - // bottomMargin: 50 - // } - // } MultimediaView { width: 1000 height: 400 diff --git a/ScreenPlayWallpaper/src/windowsintegration.cpp b/ScreenPlayWallpaper/src/windowsintegration.cpp index 1dc3d9b8..de23690b 100644 --- a/ScreenPlayWallpaper/src/windowsintegration.cpp +++ b/ScreenPlayWallpaper/src/windowsintegration.cpp @@ -442,3 +442,46 @@ void WindowsIntegration::setupWindowMouseHook() return; } } + +void WindowsIntegration::setupWindowKeyboardHook() +{ + HINSTANCE hInstance = GetModuleHandle(NULL); + if (!(m_keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookCallback, hInstance, 0))) { + OutputDebugStringW(L"Failed to install keyboard hook!"); + return; + } +} + +void WindowsIntegration::setKeyboardEventHandler(KeyboardEventHandler handler) +{ + m_keyboardEventHandler = std::move(handler); +} + +LRESULT __stdcall WindowsIntegration::KeyboardHookCallback(int nCode, WPARAM wParam, LPARAM lParam) +{ + if (nCode >= 0) { + KBDLLHOOKSTRUCT* kbStruct = (KBDLLHOOKSTRUCT*)lParam; + bool keyDown = wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN; + // Check if the callback function is set and call it + if (m_keyboardEventHandler) { + m_keyboardEventHandler(kbStruct->vkCode, keyDown); + } + } + return CallNextHookEx(NULL, nCode, wParam, lParam); +} + +void WindowsIntegration::unhookMouse() +{ + if (m_mouseHook != NULL) { + UnhookWindowsHookEx(m_mouseHook); + m_mouseHook = NULL; + } +} + +void WindowsIntegration::unhookKeyboard() +{ + if (m_keyboardHook != NULL) { + UnhookWindowsHookEx(m_keyboardHook); + m_keyboardHook = NULL; + } +} diff --git a/ScreenPlayWallpaper/src/windowsintegration.h b/ScreenPlayWallpaper/src/windowsintegration.h index d39991fc..dc5285c6 100644 --- a/ScreenPlayWallpaper/src/windowsintegration.h +++ b/ScreenPlayWallpaper/src/windowsintegration.h @@ -87,6 +87,10 @@ struct sEnumInfo { using MouseEventHandler = std::function; static MouseEventHandler m_mouseEventHandler; static HHOOK m_mouseHook; +// Define a callback type for keyboard events +typedef std::function KeyboardEventHandler; +static HHOOK m_keyboardHook; +static KeyboardEventHandler m_keyboardEventHandler; class WindowsIntegration { public: @@ -111,9 +115,14 @@ public: void setWindowHandleWorker(HWND windowHandleWorker); void setupWindowMouseHook(); - static LRESULT __stdcall MouseHookCallback(int nCode, WPARAM wParam, LPARAM lParam); - // Set the mouse event handler function + void unhookMouse(); void setMouseEventHandler(MouseEventHandler handler); + static LRESULT __stdcall MouseHookCallback(int nCode, WPARAM wParam, LPARAM lParam); + + void setupWindowKeyboardHook(); + void unhookKeyboard(); + void setKeyboardEventHandler(KeyboardEventHandler handler); + static LRESULT __stdcall KeyboardHookCallback(int nCode, WPARAM wParam, LPARAM lParam); private: HWND m_windowHandle {}; diff --git a/ScreenPlayWallpaper/src/winwindow.cpp b/ScreenPlayWallpaper/src/winwindow.cpp index 7c3a10f6..e4f66f3b 100644 --- a/ScreenPlayWallpaper/src/winwindow.cpp +++ b/ScreenPlayWallpaper/src/winwindow.cpp @@ -112,6 +112,26 @@ ScreenPlay::WallpaperExitCode WinWindow::start() // Post the event to the target widget QCoreApplication::postEvent(&m_window, qEvent); }); + + // Inside your main application or somewhere appropriate + m_windowsIntegration.setupWindowKeyboardHook(); + // Set up the keyboard event handler + m_windowsIntegration.setKeyboardEventHandler([this](UINT vkCode, bool keyDown) { + QEvent::Type eventType = keyDown ? QEvent::KeyPress : QEvent::KeyRelease; + + // Map the vkCode to Qt key code if necessary + auto [qtKey, text] = mapVirtualKeyToQtKey(vkCode); // Implement this function based on your needs + + // Create the QKeyEvent + QKeyEvent* qEvent = new QKeyEvent(eventType, qtKey, Qt::NoModifier, text); + + // Handle the keyboard event + // For example, logging the key press + qDebug() << "Keyboard event: Key=" << vkCode << ", Type=" << (keyDown ? "KeyDown" : "KeyUp") << qEvent; + + // Post the event to the target widget + QCoreApplication::postEvent(&m_window, qEvent); + }); }); return ScreenPlay::WallpaperExitCode::Ok; } @@ -209,6 +229,155 @@ void WinWindow::configureWindowGeometry() m_window.show(); } +std::tuple WinWindow::mapVirtualKeyToQtKey(UINT vkCode) +{ + switch (vkCode) { + case VK_BACK: + return { Qt::Key_Backspace, QString() }; + case VK_TAB: + return { Qt::Key_Tab, QString("\t") }; + case VK_CLEAR: + return { Qt::Key_Clear, QString() }; + case VK_RETURN: + return { Qt::Key_Return, QString("\r") }; + // ... rest of the cases ... + case VK_SPACE: + return { Qt::Key_Space, QString(" ") }; + // Extra keys + case 0x21: // '!' + return { Qt::Key_Exclam, QString("!") }; + case 0x40: // '@' + return { Qt::Key_At, QString("@") }; + case 0x23: // '#' + return { Qt::Key_NumberSign, QString("#") }; + case 0x24: // '$' + return { Qt::Key_Dollar, QString("$") }; + case 0x25: // '%' + return { Qt::Key_Percent, QString("%") }; + case 0x5E: // '^' + return { Qt::Key_AsciiCircum, QString("^") }; + case 0x26: // '&' + return { Qt::Key_Ampersand, QString("&") }; + case 0x2A: // '*' + return { Qt::Key_Asterisk, QString("*") }; + case 0x28: // '(' + return { Qt::Key_ParenLeft, QString("(") }; + case 0x29: // ')' + return { Qt::Key_ParenRight, QString(")") }; + case 0x5F: // '_' + return { Qt::Key_Underscore, QString("_") }; + case 0x2B: // '+' + return { Qt::Key_Plus, QString("+") }; + case 0x2D: // '-' + return { Qt::Key_Minus, QString("-") }; + case 0x3D: // '=' + return { Qt::Key_Equal, QString("=") }; + case 0x5B: // '[' + return { Qt::Key_BracketLeft, QString("[") }; + case 0x5D: // ']' + return { Qt::Key_BracketRight, QString("]") }; + case 0x7B: // '{' + return { Qt::Key_BraceLeft, QString("{") }; + case 0x7D: // '}' + return { Qt::Key_BraceRight, QString("}") }; + case 0x3B: // ';' + return { Qt::Key_Semicolon, QString(";") }; + case 0x27: // ''' + return { Qt::Key_Apostrophe, QString("'") }; + case 0x3A: // ':' + return { Qt::Key_Colon, QString(":") }; + case 0x22: // '"' + return { Qt::Key_QuoteDbl, QString("\"") }; + case 0x2F: // '/' + return { Qt::Key_Slash, QString("/") }; + case 0x2E: // '.' + return { Qt::Key_Period, QString(".") }; + case 0x3E: // '>' + return { Qt::Key_Greater, QString(">") }; + case 0x2C: // ',' + return { Qt::Key_Comma, QString(",") }; + case 0x3F: // '?' + return { Qt::Key_Question, QString("?") }; + // Numeric keys + case 0x30: + return { Qt::Key_0, QString("0") }; + case 0x31: + return { Qt::Key_1, QString("1") }; + case 0x32: + return { Qt::Key_2, QString("2") }; + case 0x33: + return { Qt::Key_3, QString("3") }; + case 0x34: + return { Qt::Key_4, QString("4") }; + case 0x35: + return { Qt::Key_5, QString("5") }; + case 0x36: + return { Qt::Key_6, QString("6") }; + case 0x37: + return { Qt::Key_7, QString("7") }; + case 0x38: + return { Qt::Key_8, QString("8") }; + case 0x39: + return { Qt::Key_9, QString("9") }; + + // Alphabet keys + case 0x41: + return { Qt::Key_A, QString("a") }; + case 0x42: + return { Qt::Key_B, QString("b") }; + case 0x43: + return { Qt::Key_C, QString("c") }; + case 0x44: + return { Qt::Key_D, QString("d") }; + case 0x45: + return { Qt::Key_E, QString("e") }; + case 0x46: + return { Qt::Key_F, QString("f") }; + case 0x47: + return { Qt::Key_G, QString("g") }; + case 0x48: + return { Qt::Key_H, QString("h") }; + case 0x49: + return { Qt::Key_I, QString("i") }; + case 0x4A: + return { Qt::Key_J, QString("j") }; + case 0x4B: + return { Qt::Key_K, QString("k") }; + case 0x4C: + return { Qt::Key_L, QString("l") }; + case 0x4D: + return { Qt::Key_M, QString("m") }; + case 0x4E: + return { Qt::Key_N, QString("n") }; + case 0x4F: + return { Qt::Key_O, QString("o") }; + case 0x50: + return { Qt::Key_P, QString("p") }; + case 0x51: + return { Qt::Key_Q, QString("q") }; + case 0x52: + return { Qt::Key_R, QString("r") }; + case 0x53: + return { Qt::Key_S, QString("s") }; + case 0x54: + return { Qt::Key_T, QString("t") }; + case 0x55: + return { Qt::Key_U, QString("u") }; + case 0x56: + return { Qt::Key_V, QString("v") }; + case 0x57: + return { Qt::Key_W, QString("w") }; + case 0x58: + return { Qt::Key_X, QString("x") }; + case 0x59: + return { Qt::Key_Y, QString("y") }; + case 0x5A: + return { Qt::Key_Z, QString("z") }; + default: + return { Qt::Key_unknown, QString() }; + } +} + /*! \brief Custom exit method to force a redraw of the window so that the default desktop wallpaper can be seen agian. @@ -216,9 +385,7 @@ void WinWindow::configureWindowGeometry() void WinWindow::terminate() { using ScreenPlay::InstalledType::InstalledType; - if (type() != InstalledType::VideoWallpaper && type() != InstalledType::GifWallpaper) { - // UnhookWindowsHookEx(g_mouseHook); - } + ShowWindow(m_windowsIntegration.windowHandle(), SW_HIDE); // Force refresh so that we display the regular @@ -226,6 +393,9 @@ void WinWindow::terminate() ShowWindow(m_windowsIntegration.windowHandleWorker(), SW_HIDE); ShowWindow(m_windowsIntegration.windowHandleWorker(), SW_SHOW); + m_windowsIntegration.unhookKeyboard(); + m_windowsIntegration.unhookMouse(); + QGuiApplication::quit(); } diff --git a/ScreenPlayWallpaper/src/winwindow.h b/ScreenPlayWallpaper/src/winwindow.h index b9cee345..b9a781c8 100644 --- a/ScreenPlayWallpaper/src/winwindow.h +++ b/ScreenPlayWallpaper/src/winwindow.h @@ -54,6 +54,7 @@ private: void setupWallpaperForAllScreens(); void setupWallpaperForMultipleScreens(const QVector& activeScreensList); void configureWindowGeometry(); + std::tuple mapVirtualKeyToQtKey(UINT vkCode); private slots: void checkForFullScreenWindow();