Switched from raw input to low-level keyboard hook, with -W/--raw to optionally re-enable raw input (needed to debug, so the hook doesn't cause GDB to make system input unusably slow), fixes #4399.
This commit is contained in:
@@ -47,6 +47,7 @@ Q_IMPORT_PLUGIN(QWindowsVistaStylePlugin)
|
||||
# include "qt_winmanagerfilter.hpp"
|
||||
# include <86box/win.h>
|
||||
# include <shobjidl.h>
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
@@ -81,6 +82,7 @@ extern QElapsedTimer elapsed_timer;
|
||||
extern MainWindow *main_window;
|
||||
|
||||
extern "C" {
|
||||
#include <86box/keyboard.h>
|
||||
#include <86box/timer.h>
|
||||
#include <86box/nvr.h>
|
||||
extern int qt_nvr_save(void);
|
||||
@@ -88,6 +90,122 @@ extern int qt_nvr_save(void);
|
||||
|
||||
void qt_set_sequence_auto_mnemonic(bool b);
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
static void
|
||||
keyboard_getkeymap()
|
||||
{
|
||||
const LPCSTR keyName = "SYSTEM\\CurrentControlSet\\Control\\Keyboard Layout";
|
||||
const LPCSTR valueName = "Scancode Map";
|
||||
unsigned char buf[32768];
|
||||
DWORD bufSize;
|
||||
HKEY hKey;
|
||||
int j;
|
||||
UINT32 *bufEx2;
|
||||
int scMapCount;
|
||||
UINT16 *bufEx;
|
||||
int scancode_unmapped;
|
||||
int scancode_mapped;
|
||||
|
||||
/* First, prepare the default scan code map list which is 1:1.
|
||||
* Remappings will be inserted directly into it.
|
||||
* 512 bytes so this takes less memory, bit 9 set means E0
|
||||
* prefix.
|
||||
*/
|
||||
for (j = 0; j < 512; j++)
|
||||
scancode_map[j] = j;
|
||||
|
||||
/* Get the scan code remappings from:
|
||||
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout */
|
||||
bufSize = 32768;
|
||||
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, keyName, 0, 1, &hKey) == ERROR_SUCCESS) {
|
||||
if (RegQueryValueExA(hKey, valueName, NULL, NULL, buf, &bufSize) == ERROR_SUCCESS) {
|
||||
bufEx2 = (UINT32 *) buf;
|
||||
scMapCount = bufEx2[2];
|
||||
if ((bufSize != 0) && (scMapCount != 0)) {
|
||||
bufEx = (UINT16 *) (buf + 12);
|
||||
for (j = 0; j < scMapCount * 2; j += 2) {
|
||||
/* Each scan code is 32-bit: 16 bits of remapped scan code,
|
||||
and 16 bits of original scan code. */
|
||||
scancode_unmapped = bufEx[j + 1];
|
||||
scancode_mapped = bufEx[j];
|
||||
|
||||
scancode_unmapped = convert_scan_code(scancode_unmapped);
|
||||
scancode_mapped = convert_scan_code(scancode_mapped);
|
||||
|
||||
/* Ignore source scan codes with prefixes other than E1
|
||||
that are not E1 1D. */
|
||||
if (scancode_unmapped != 0xFFFF)
|
||||
scancode_map[scancode_unmapped] = scancode_mapped;
|
||||
}
|
||||
}
|
||||
}
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK
|
||||
emu_LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
LPKBDLLHOOKSTRUCT lpKdhs = (LPKBDLLHOOKSTRUCT) lParam;
|
||||
/* Checks if CTRL was pressed. */
|
||||
BOOL bCtrlDown = GetAsyncKeyState (VK_CONTROL) >> ((sizeof(SHORT) * 8) - 1);
|
||||
uint16_t scancode = lpKdhs->scanCode & 0x00ff;
|
||||
|
||||
if (lpKdhs->flags & LLKHF_EXTENDED)
|
||||
scancode |= 0x100;
|
||||
|
||||
/* Translate the scan code to 9-bit */
|
||||
scancode = convert_scan_code(scancode);
|
||||
|
||||
/* Remap it according to the list from the Registry */
|
||||
if ((scancode < (sizeof(scancode_map) / sizeof(scancode_map[0]))) && (scancode != scancode_map[scancode])) {
|
||||
// pclog("Scan code remap: %03X -> %03X\n", scancode, scancode_map[scancode]);
|
||||
scancode = scancode_map[scancode];
|
||||
}
|
||||
|
||||
/* If it's not 0xFFFF, send it to the emulated
|
||||
keyboard.
|
||||
We use scan code 0xFFFF to mean a mapping that
|
||||
has a prefix other than E0 and that is not E1 1D,
|
||||
which is, for our purposes, invalid. */
|
||||
|
||||
/* Translate right CTRL to left ALT if the user has so
|
||||
chosen. */
|
||||
if ((scancode == 0x11d) && rctrl_is_lalt)
|
||||
scancode = 0x038;
|
||||
|
||||
/* Normal scan code pass through, pass it through as is if
|
||||
it's not an invalid scan code. */
|
||||
if (scancode != 0xFFFF)
|
||||
keyboard_input(!(lpKdhs->flags & LLKHF_UP), scancode);
|
||||
|
||||
main_window->checkFullscreenHotkey();
|
||||
|
||||
if ((lpKdhs->scanCode == 0x01) && (lpKdhs->flags & LLKHF_ALTDOWN) &&
|
||||
!(lpKdhs->flags & (LLKHF_UP | LLKHF_EXTENDED)))
|
||||
return TRUE;
|
||||
else if ((lpKdhs->scanCode == 0x01) && bCtrlDown && !(lpKdhs->flags & (LLKHF_UP | LLKHF_EXTENDED)))
|
||||
return TRUE;
|
||||
else if ((lpKdhs->scanCode == 0x0f) && (lpKdhs->flags & LLKHF_ALTDOWN) &&
|
||||
!(lpKdhs->flags & (LLKHF_UP | LLKHF_EXTENDED)))
|
||||
return TRUE;
|
||||
else if ((lpKdhs->scanCode == 0x0f) && bCtrlDown && !(lpKdhs->flags & (LLKHF_UP | LLKHF_EXTENDED)))
|
||||
return TRUE;
|
||||
else if ((lpKdhs->scanCode == 0x39) && (lpKdhs->flags & LLKHF_ALTDOWN) &&
|
||||
!(lpKdhs->flags & (LLKHF_UP | LLKHF_EXTENDED)))
|
||||
return TRUE;
|
||||
else if ((lpKdhs->scanCode == 0x3e) && (lpKdhs->flags & LLKHF_ALTDOWN) &&
|
||||
!(lpKdhs->flags & (LLKHF_UP | LLKHF_EXTENDED)))
|
||||
return TRUE;
|
||||
else if ((lpKdhs->scanCode == 0x51) && bCtrlDown && !(lpKdhs->flags & LLKHF_UP))
|
||||
return TRUE;
|
||||
else if ((lpKdhs->scanCode >= 0x5b) && (lpKdhs->scanCode <= 0x5d) && (lpKdhs->flags & LLKHF_EXTENDED))
|
||||
return TRUE;
|
||||
else
|
||||
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
main_thread_fn()
|
||||
{
|
||||
@@ -165,6 +283,10 @@ main_thread_fn()
|
||||
|
||||
static std::thread *main_thread;
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
static HHOOK llhook = NULL;
|
||||
#endif
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
@@ -176,6 +298,7 @@ main(int argc, char *argv[])
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||
QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
||||
#endif
|
||||
|
||||
QApplication app(argc, argv);
|
||||
QLocale::setDefault(QLocale::C);
|
||||
|
||||
@@ -193,6 +316,13 @@ main(int argc, char *argv[])
|
||||
#endif
|
||||
elapsed_timer.start();
|
||||
|
||||
for (size_t i = 0; i < sizeof(scancode_map) / sizeof(scancode_map[0]); i++)
|
||||
scancode_map[i] = i;
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
keyboard_getkeymap();
|
||||
#endif
|
||||
|
||||
if (!pc_init(argc, argv)) {
|
||||
return 0;
|
||||
}
|
||||
@@ -340,6 +470,13 @@ main(int argc, char *argv[])
|
||||
});
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
if (!raw_input) {
|
||||
llhook = SetWindowsHookEx(WH_KEYBOARD_LL, emu_LowLevelKeyboardProc, NULL, 0);
|
||||
atexit([] () -> void { if (llhook) UnhookWindowsHookEx(llhook); });
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Setup raw input */
|
||||
auto rawInputFilter = WindowsRawInputFilter::Register(main_window);
|
||||
if (rawInputFilter) {
|
||||
|
||||
Reference in New Issue
Block a user