From d418424c14bedc809fb67b0a27238ff84c847743 Mon Sep 17 00:00:00 2001 From: Jamie Greunbaum Date: Tue, 17 Sep 2024 16:55:02 -0400 Subject: [PATCH] - Keys are now parsed from a QKeySequence and converted to Win32 input events. - Dial rotations send a simultaneous press-release event. --- MacroBinds.pro | 1 + WindowFinder/win32/windowfinderkeymap.h | 224 ++++++++++++++++++++++++ WindowFinder/windowfinder.cpp | 61 +++++-- WindowFinder/windowfinder.h | 5 + qmacrobindswindow.cpp | 2 +- 5 files changed, 273 insertions(+), 20 deletions(-) create mode 100644 WindowFinder/win32/windowfinderkeymap.h diff --git a/MacroBinds.pro b/MacroBinds.pro index b2b8de0..5718156 100644 --- a/MacroBinds.pro +++ b/MacroBinds.pro @@ -30,6 +30,7 @@ HEADERS += \ Widgets/qmacrobutton.h \ Widgets/qprocesslistitem.h \ Widgets/qratiobutton.h \ + WindowFinder/win32/windowfinderkeymap.h \ WindowFinder/windowfinder.h \ qmacrobindswindow.h \ qmacrokeysmanager.h \ diff --git a/WindowFinder/win32/windowfinderkeymap.h b/WindowFinder/win32/windowfinderkeymap.h new file mode 100644 index 0000000..0df9797 --- /dev/null +++ b/WindowFinder/win32/windowfinderkeymap.h @@ -0,0 +1,224 @@ +#ifndef WINDOWFINDERKEYMAP_H +#define WINDOWFINDERKEYMAP_H + +#include +#include + +const uint16_t asciiToWin32[0x80] = { + 0x00, + 0x01, + 0x02, + 0x03, + 0x04, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x0B, + 0x0C, + 0x0D, + 0x0E, + 0x0F, + 0x10, + 0x11, + 0x12, + 0x13, + 0x14, + 0x15, + 0x16, + 0x17, + 0x18, + 0x19, + 0x1A, + 0x1B, + 0x1C, + 0x1D, + 0x1E, + 0x1F, + VK_SPACE, + '!', + '"', + '#', + '$', + '%', + '&', + '\'', + '(', + ')', + '*', + '+', + ',', + '-', + '.', + '/', + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + ':', + ';', + '<', + '=', + '>', + '?', + '@', + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'I', + 'J', + 'K', + 'L', + 'M', + 'N', + 'O', + 'P', + 'Q', + 'R', + 'S', + 'T', + 'U', + 'V', + 'W', + 'X', + 'Y', + 'Z', + '[', + '\\', + ']', + '^', + '_', + '`', + 0x61, + 0x62, + 0x63, + 0x64, + 0x65, + 0x66, + 0x67, + 0x68, + 0x69, + 0x6A, + 0x6B, + 0x6C, + 0x6D, + 0x6E, + 0x6F, + 0x70, + 0x71, + 0x72, + 0x73, + 0x74, + 0x75, + 0x76, + 0x77, + 0x78, + 0x79, + 0x7A, + '{', + '|', + '}', + '~', + 0x7F, +}; + +const uint16_t functionToWin32[0x53] = { + VK_ESCAPE, + VK_TAB, + VK_TAB, + VK_BACK, + VK_RETURN, + VK_RETURN, + VK_INSERT, + VK_DELETE, + VK_PAUSE, + VK_PRINT, + VK_PRINT, + VK_CLEAR, + 0x0C, + 0x0D, + 0x0E, + 0x0F, + VK_HOME, + VK_END, + VK_LEFT, + VK_UP, + VK_RIGHT, + VK_DOWN, + VK_PRIOR, + VK_NEXT, + 0x18, + 0x19, + 0x1A, + 0x1B, + 0x1C, + 0x1D, + 0x1E, + 0x1F, + VK_LSHIFT, + VK_LCONTROL, + VK_LWIN, + VK_LMENU, + VK_CAPITAL, + VK_NUMLOCK, + VK_SCROLL, + 0x27, + 0x28, + 0x29, + 0x2A, + 0x2B, + 0x2C, + 0x2D, + 0x2E, + 0x2F, + VK_F1, + VK_F2, + VK_F3, + VK_F4, + VK_F5, + VK_F6, + VK_F7, + VK_F8, + VK_F9, + VK_F10, + VK_F11, + VK_F12, + VK_F13, + VK_F14, + VK_F15, + VK_F16, + VK_F17, + VK_F18, + VK_F19, + VK_F20, + VK_F21, + VK_F22, + VK_F23, + VK_F24, + VK_F5, + VK_F6, + VK_F7, + VK_F8, + VK_F9, + VK_F10, + VK_F1, + VK_F2, + VK_F3, + VK_F4, + VK_F5, +}; + +#endif // WINDOWFINDERKEYMAP_H diff --git a/WindowFinder/windowfinder.cpp b/WindowFinder/windowfinder.cpp index 025054e..7a0d789 100644 --- a/WindowFinder/windowfinder.cpp +++ b/WindowFinder/windowfinder.cpp @@ -175,26 +175,49 @@ WindowData WindowFinder::getWin32FrontmostWindowProcess() void WindowFinder::sendWin32InputToFrontmostWindow(const QKeySequence &keys, const KeyEventType &type) { - const QString &keyStrings = keys.toString(); - const QStringList &keyStringsList = keyStrings.split(","); - for (const QString &keyString : keyStringsList) { - const QStringList &keys = keyString.split("+"); - for (const QString &key : keys) { - INPUT input[1] = {}; - ZeroMemory(input, sizeof(input)); - input[0].type = INPUT_KEYBOARD; - if (key.compare("Shift", Qt::CaseInsensitive) == 0) { - input[0].ki.wVk = VK_LSHIFT; - } else if (key.compare("X", Qt::CaseInsensitive) == 0) { - input[0].ki.wVk = 'X'; - } else if (key.compare("Y", Qt::CaseInsensitive) == 0) { - input[0].ki.wVk = 'Y'; - } else if (key.compare("Z", Qt::CaseInsensitive) == 0) { - input[0].ki.wVk = 'Z'; - } - input[0].ki.dwFlags = type == KeyEventType::RELEASE ? KEYEVENTF_KEYUP : 0; - SendInput(ARRAYSIZE(input), input, sizeof(INPUT)); + QVector separatedKeys; + for (int i = 0; i < keys.count(); i++) { + Qt::KeyboardModifiers mods = keys[0].keyboardModifiers(); + if (mods & Qt::ShiftModifier) separatedKeys.append(Qt::Key_Shift); + if (mods & Qt::ControlModifier) separatedKeys.append(Qt::Key_Control); + if (mods & Qt::AltModifier) separatedKeys.append(Qt::Key_Alt); + if (mods & Qt::MetaModifier) separatedKeys.append(Qt::Key_Meta); + separatedKeys.append(keys[0].key()); + } + + switch (type) { + case KeyEventType::PRESS_AND_RELEASE: { + // Send all key press events in order, then release events in reverse order, to + // ensure modifier keys are released the way a user would do so on a keyboard. + for (QVector::iterator keyIterator = separatedKeys.begin(); + keyIterator != separatedKeys.end(); + keyIterator++) { + sendWin32InputEvent(*keyIterator, KeyEventType::PRESS); } + for (QVector::reverse_iterator keyIterator = separatedKeys.rbegin(); + keyIterator != separatedKeys.rend(); + keyIterator++) { + sendWin32InputEvent(*keyIterator, KeyEventType::RELEASE); + } + } break; + default: { + for (const Qt::Key &key : separatedKeys) { + sendWin32InputEvent(key, type); + } + } break; } } +void WindowFinder::sendWin32InputEvent(const Qt::Key &key, const KeyEventType &type) +{ + INPUT input[1] = {}; + ZeroMemory(input, sizeof(input)); + input[0].type = INPUT_KEYBOARD; + if (key >= 0x01000000 && key < 0x01000053) { + input[0].ki.wVk = functionToWin32[key & 0x0000007F]; + } else { + input[0].ki.wVk = asciiToWin32[key & 0x0000007F]; + } + input[0].ki.dwFlags = type == KeyEventType::RELEASE ? KEYEVENTF_KEYUP : 0; + SendInput(ARRAYSIZE(input), input, sizeof(INPUT)); +} #endif // Q_OS_WIN diff --git a/WindowFinder/windowfinder.h b/WindowFinder/windowfinder.h index c8ac953..a94dd4d 100644 --- a/WindowFinder/windowfinder.h +++ b/WindowFinder/windowfinder.h @@ -4,6 +4,10 @@ #include #include +#ifdef Q_OS_WIN +#include "win32/windowfinderkeymap.h" +#endif // Q_OS_WIN + #ifdef Q_OS_WIN struct IconDirEntry @@ -56,6 +60,7 @@ private: static WindowData getWin32FrontmostWindowProcess(); // static bool getWin32IconData(HICON hIcon, int nColorBits, QByteArray &buffer); static void sendWin32InputToFrontmostWindow(const QKeySequence &keys, const KeyEventType &type); + static void sendWin32InputEvent(const Qt::Key &key, const KeyEventType &type); #endif // Q_OS_WIN }; diff --git a/qmacrobindswindow.cpp b/qmacrobindswindow.cpp index 7bd9ca6..f9ebc39 100644 --- a/qmacrobindswindow.cpp +++ b/qmacrobindswindow.cpp @@ -123,7 +123,7 @@ void QMacroBindsWindow::newEncoderRotation(const quint8 &column, const EncoderRo { const QVector &encoderButtons = this->vButtonWidgets.last(); if (column < encoderButtons.size()) { - WindowFinder::sendInputToFrontmostWindow(direction == EncoderRotation::CCW ? QKeySequence(tr("Shift+Y")) : QKeySequence(tr("Shift+X")), KeyEventType::PRESS_AND_RELEASE); + WindowFinder::sendInputToFrontmostWindow(direction == EncoderRotation::CCW ? QKeySequence(tr("Shift+Y")) : QKeySequence(tr("Shift+A")), KeyEventType::PRESS_AND_RELEASE); } }