- Keys are now parsed from a QKeySequence and converted to Win32 input events.

- Dial rotations send a simultaneous press-release event.
This commit is contained in:
Jamie Greunbaum 2024-09-17 16:55:02 -04:00
parent b40cb2f692
commit d418424c14
5 changed files with 273 additions and 20 deletions

View File

@ -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 \

View File

@ -0,0 +1,224 @@
#ifndef WINDOWFINDERKEYMAP_H
#define WINDOWFINDERKEYMAP_H
#include <cstdint>
#include <Windows.h>
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

View File

@ -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<Qt::Key> 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<Qt::Key>::iterator keyIterator = separatedKeys.begin();
keyIterator != separatedKeys.end();
keyIterator++) {
sendWin32InputEvent(*keyIterator, KeyEventType::PRESS);
}
for (QVector<Qt::Key>::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

View File

@ -4,6 +4,10 @@
#include <QMetaType>
#include <QString>
#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
};

View File

@ -123,7 +123,7 @@ void QMacroBindsWindow::newEncoderRotation(const quint8 &column, const EncoderRo
{
const QVector<QPushButton *> &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);
}
}