Skip to content

Commit

Permalink
[optimize] Using RAWINPUT to listen for keyboard events
Browse files Browse the repository at this point in the history
  • Loading branch information
SkyD666 committed Dec 12, 2024
1 parent 60e997c commit dea600c
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 95 deletions.
1 change: 1 addition & 0 deletions EliteSpeedrunTool/AcknowledgementDialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,6 @@ class AcknowledgementDialog : public QDialog {
"巨大糖丸🐷",
"GodfatherCDW",
"9527_SSR",
"Capucino_ovo",
};
};
8 changes: 4 additions & 4 deletions EliteSpeedrunTool/App.rc
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
2 ICON "icon.ico"

VS_VERSION_INFO VERSIONINFO
FILEVERSION 10,10,1,69
PRODUCTVERSION 10,10,1,69
FILEVERSION 11,0,1,70
PRODUCTVERSION 11,0,1,70
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
Expand All @@ -26,8 +26,8 @@ VS_VERSION_INFO VERSIONINFO
BEGIN
VALUE "CompanyName", "SkyD666\0"
VALUE "FileDescription", "Elite Speedrun Tool\0"
VALUE "FileVersion", "10.10.1.69\0"
VALUE "ProductVersion", "10.10.1.69\0"
VALUE "FileVersion", "11.0.1.70\0"
VALUE "ProductVersion", "11.0.1.70\0"
VALUE "ProductName", "Elite Speedrun Tool\0"
END
END
Expand Down
2 changes: 1 addition & 1 deletion EliteSpeedrunTool/GlobalData.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ class GlobalData : public QObject {

private:
bool mMinimizeToTray = false;
QString mStyleName = "windowsvista";
QString mStyleName = "windows11";
// 版本
bool mAutoCheckUpdate = true;
QString mVersion = "0.0";
Expand Down
139 changes: 86 additions & 53 deletions EliteSpeedrunTool/HotkeyUtil.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
#include "HotkeyUtil.h"
#include <QDebug>
#include <hidusage.h>

Q_GLOBAL_STATIC(HotkeyUtil, hotkeyUtilInstance)

LRESULT CALLBACK keyboardProc(int nCode, WPARAM wParam, LPARAM lParam);

QHotkey::QHotkey(QKeySequence keySeq, bool autoRegister, QObject* parent)
: keySeq { keySeq }
, QObject { parent }
Expand All @@ -13,7 +12,7 @@ QHotkey::QHotkey(QKeySequence keySeq, bool autoRegister, QObject* parent)
hotkeyUtil->registerHotkey(this);
}
auto hotkey = keySeq[0];
nativeKeycode = hotkeyUtil->nativeKeycode(hotkey.key(), nativeKeycodeOk);
nativeKeycode = hotkeyUtil->escapeNumPad(hotkeyUtil->nativeKeycode(hotkey.key(), nativeKeycodeOk));
nativeModifiers = hotkeyUtil->nativeModifiers(hotkey.keyboardModifiers());
}

Expand All @@ -36,18 +35,11 @@ void QHotkey::emitSignal()
emit activated();
}

HotkeyUtil::HotkeyUtil(QObject* parent)
: QObject { parent }
HotkeyUtil::HotkeyUtil(QWidget* parent)
: QWidget { parent }
{
hhkKeyboard = SetWindowsHookEx(WH_KEYBOARD_LL, keyboardProc, 0, 0);
}

HotkeyUtil::~HotkeyUtil()
{
if (hhkKeyboard) {
UnhookWindowsHookEx(hhkKeyboard);
hhkKeyboard = nullptr;
}
qInfo() << "HotkeyUtil initializing...";
registerRawInputDevice();
}

HotkeyUtil* HotkeyUtil::instance()
Expand All @@ -70,12 +62,12 @@ void HotkeyUtil::unregisterHotkey(QHotkey* key)
void HotkeyUtil::keyDown(DWORD key)
{
if (isModifier(key)) {
modifiers |= vkToMod(key);
modifiers |= modifierVkToMod(key);
return;
}
key = escapeNumPad(key);
for (const auto& hotkeySeq : hotkeys) {
qDebug() << hotkeySeq->nativeModifiers << modifiers << hotkeySeq->nativeKeycodeOk << hotkeySeq->nativeKeycode << key;
// qDebug() << hotkeySeq->nativeModifiers << modifiers << hotkeySeq->nativeKeycodeOk << hotkeySeq->nativeKeycode << key;
if (hotkeySeq->nativeModifiers != modifiers || !hotkeySeq->nativeKeycodeOk || hotkeySeq->nativeKeycode != key) {
continue;
}
Expand All @@ -86,39 +78,74 @@ void HotkeyUtil::keyDown(DWORD key)
void HotkeyUtil::keyUp(DWORD key)
{
if (isModifier(key)) {
modifiers &= ~vkToMod(key);
modifiers &= ~modifierVkToMod(key);
return;
}
key = escapeNumPad(key);
// key = escapeNumPad(key);
}

LRESULT CALLBACK keyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
bool HotkeyUtil::nativeEvent(const QByteArray& eventType, void* message, qintptr* result)
{
if (nCode == HC_ACTION) {
switch (wParam) {
case WM_SYSKEYDOWN:
case WM_KEYDOWN:
// qDebug() << PKBDLLHOOKSTRUCT(lParam)->vkCode;
hotkeyUtil->keyDown(PKBDLLHOOKSTRUCT(lParam)->vkCode);
break;
case WM_SYSKEYUP:
case WM_KEYUP:
hotkeyUtil->keyUp(PKBDLLHOOKSTRUCT(lParam)->vkCode);
break;
if (eventType == "windows_generic_MSG" || eventType == "windows_dispatcher_MSG") {
MSG* msg = static_cast<MSG*>(message);

if (msg->message == WM_INPUT) {
processRawInput(msg->lParam);
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
return QWidget::nativeEvent(eventType, message, result);
}

quint32 HotkeyUtil::nativeKeycode(Qt::Key keycode, bool& ok)
bool HotkeyUtil::registerRawInputDevice()
{
ok = true;
if (keycode <= 0xFFFF) { // Try to obtain the key from it's "character"
const SHORT vKey = VkKeyScanW(static_cast<WCHAR>(keycode));
if (vKey > -1)
return LOBYTE(vKey);
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-rawinputdevice
RAWINPUTDEVICE rid;
rid.usUsagePage = HID_USAGE_PAGE_GENERIC; // Generic Desktop Controls
rid.usUsage = HID_USAGE_GENERIC_KEYBOARD; // Keyboard
rid.dwFlags = RIDEV_INPUTSINK; // Enables the caller to receive the input even when the caller is not in the foreground
rid.hwndTarget = reinterpret_cast<HWND>(winId()); // Window hwnd

return RegisterRawInputDevices(&rid, 1, sizeof(rid));
}

void HotkeyUtil::processRawInput(LPARAM lParam)
{
UINT dwSize = 0;
// Get the input data size
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, nullptr, &dwSize, sizeof(RAWINPUTHEADER));

// Allocate buffer
LPBYTE lpb = new BYTE[dwSize];
if (!lpb) {
return;
}

// Get the input data
if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)) != dwSize) {
qCritical() << "GetRawInputData does not return correct size!";
}

// Parse RAWINPUT
RAWINPUT* raw = (RAWINPUT*)lpb;
if (raw->header.dwType == RIM_TYPEKEYBOARD) {
RAWKEYBOARD keyboard = raw->data.keyboard;
UINT vKey = keyboard.VKey; // Virtual key code
// UINT scanCode = keyboard.MakeCode; // Scan code
UINT flags = keyboard.Flags; // Key Down / Key Up

if (flags & RI_KEY_BREAK) {
keyUp(vKey);
} else {
keyDown(vKey);
}
}

delete[] lpb;
}

quint32 HotkeyUtil::nativeKeycode(Qt::Key keycode, bool& ok)
{
ok = true;
// find key from switch/case --> Only finds a very small subset of keys
switch (keycode) {
case Qt::Key_Escape:
Expand Down Expand Up @@ -247,6 +274,14 @@ quint32 HotkeyUtil::nativeKeycode(Qt::Key keycode, bool& ok)
return VK_PLAY;
case Qt::Key_Cancel:
return VK_CANCEL;
case Qt::Key_Plus:
return VK_ADD;
case Qt::Key_Minus:
return VK_SUBTRACT;
case Qt::Key_Slash:
return VK_DIVIDE;
case Qt::Key_Asterisk:
return VK_MULTIPLY;

case Qt::Key_Forward:
return VK_BROWSER_FORWARD;
Expand Down Expand Up @@ -276,9 +311,14 @@ quint32 HotkeyUtil::nativeKeycode(Qt::Key keycode, bool& ok)
return VK_OEM_FJ_TOUROKU;

default:
if (keycode <= 0xFFFF)
return static_cast<BYTE>(keycode);
else {
if (keycode <= 0xFFFF) { // Try to obtain the key from it's "character"
const SHORT vKey = VkKeyScanW(static_cast<WCHAR>(keycode));
if (vKey > -1) {
return LOBYTE(vKey);
} else {
return static_cast<BYTE>(keycode);
}
} else {
ok = false;
return 0;
}
Expand All @@ -299,7 +339,7 @@ quint32 HotkeyUtil::nativeModifiers(Qt::KeyboardModifiers modifiers)
return nMods;
}

quint32 HotkeyUtil::vkToMod(DWORD key)
quint32 HotkeyUtil::modifierVkToMod(DWORD key)
{
switch (key) {
case VK_LMENU:
Expand All @@ -310,6 +350,8 @@ quint32 HotkeyUtil::vkToMod(DWORD key)
case VK_RCONTROL:
case VK_CONTROL:
return MOD_CONTROL;
case VK_LSHIFT:
case VK_RSHIFT:
case VK_SHIFT:
return MOD_SHIFT;
case VK_LWIN:
Expand All @@ -324,21 +366,12 @@ DWORD HotkeyUtil::escapeNumPad(DWORD key)
if (key >= VK_NUMPAD0 && key <= VK_NUMPAD9) {
return key - (VK_NUMPAD0 - 0x30); // 0x30 == 1
}
if (key == VK_OEM_PLUS) {
return '+';
}
return key;
}

bool HotkeyUtil::isModifier(DWORD key)
{
return key == VK_LMENU
|| key == VK_RMENU
|| key == VK_MENU
|| key == VK_LCONTROL
|| key == VK_RCONTROL
|| key == VK_CONTROL
|| key == VK_SHIFT
|| key == VK_LWIN
|| key == VK_RWIN;
return key >= VK_LSHIFT && key <= VK_RMENU
|| key >= VK_SHIFT && key <= VK_MENU
|| key >= VK_LWIN && key <= VK_RWIN;
}
18 changes: 10 additions & 8 deletions EliteSpeedrunTool/HotkeyUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#include <QKeySequence>
#include <QList>
#include <QObject>
#include <QWidget >
#include <windows.h>

#define hotkeyUtil (HotkeyUtil::instance())
Expand All @@ -25,12 +25,10 @@ class QHotkey : public QObject {
void activated();
};

class HotkeyUtil : public QObject {
class HotkeyUtil : public QWidget {
Q_OBJECT
public:
explicit HotkeyUtil(QObject* parent = nullptr);

~HotkeyUtil();
explicit HotkeyUtil(QWidget* parent = nullptr);

static HotkeyUtil* instance();

Expand All @@ -40,14 +38,18 @@ class HotkeyUtil : public QObject {
void keyDown(DWORD key);
void keyUp(DWORD key);

bool registerRawInputDevice();
void processRawInput(LPARAM lParam);

quint32 nativeKeycode(Qt::Key keycode, bool& ok);
quint32 nativeModifiers(Qt::KeyboardModifiers modifiers);
quint32 vkToMod(DWORD key);
quint32 modifierVkToMod(DWORD key);
DWORD escapeNumPad(DWORD key);

private:
HHOOK hhkKeyboard = nullptr;
protected:
bool nativeEvent(const QByteArray& eventType, void* message, qintptr* result) override;

private:
int modifiers;

QList<QHotkey*> hotkeys;
Expand Down
2 changes: 1 addition & 1 deletion EliteSpeedrunTool/MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ class MainWindow : public QMainWindow {
+ tr("游戏逆向:Zerkalo2147")
+ "</p>"
+ "<p>"
+ tr("加入 QQ 群:431228020") + "<br>"
+ tr("加入 QQ 群:827680900") + "<br>"
+ "<a href='https://t.me/SkyD666Chat'>" + tr("加入 Telegram 群组一起划水~") + "</a><br>"
+ "<a href='https://discord.gg/pEWEjeJTa3'>" + tr("加入 Discord 一起划水~") + "</a>"
+ "</p>"
Expand Down
Loading

0 comments on commit dea600c

Please sign in to comment.