Use a separate thread for polling mouse on Windows
This commit is contained in:
@@ -6,15 +6,22 @@
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Windows raw input native filter for QT
|
||||
* Windows raw input native filter for Qt
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Teemu Korhonen
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Sam Latinga
|
||||
* Cacodemon345
|
||||
*
|
||||
* Copyright 2021 Teemu Korhonen
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
* Copyright 1997-2025 Sam Latinga
|
||||
* Copyright 2024-2025 Cacodemon345.
|
||||
*
|
||||
* See this header for SDL3 code license:
|
||||
* https://github.com/libsdl-org/SDL/blob/8e5fe0ea61dc87b29ca9a6119324221df0113bcf/src/video/windows/SDL_windowsrawinput.c#L1
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -31,6 +38,8 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/* Mouse RawInput code taken from SDL3. */
|
||||
|
||||
#include "qt_winrawinputfilter.hpp"
|
||||
|
||||
#include <QMenuBar>
|
||||
@@ -94,30 +103,158 @@ bool windows_is_light_theme() {
|
||||
return i == 1;
|
||||
}
|
||||
|
||||
struct
|
||||
{
|
||||
HANDLE done_event = 0, ready_event = 0;
|
||||
std::atomic_bool done{false};
|
||||
|
||||
size_t rawinput_offset = 0, rawinput_size = 0;
|
||||
uint8_t* rawinput = nullptr;
|
||||
|
||||
HANDLE thread = 0;
|
||||
} win_rawinput_data;
|
||||
|
||||
static void
|
||||
win_poll_mouse(void)
|
||||
{
|
||||
// Yes, this is a thing in C++.
|
||||
auto* data = &win_rawinput_data;
|
||||
uint32_t size, i, count, total = 0;
|
||||
RAWINPUT *input;
|
||||
//static int64_t ms_time = plat_get_ticks();
|
||||
|
||||
if (data->rawinput_offset == 0) {
|
||||
BOOL isWow64;
|
||||
|
||||
data->rawinput_offset = sizeof(RAWINPUTHEADER);
|
||||
if (IsWow64Process(GetCurrentProcess(), &isWow64) && isWow64) {
|
||||
// We're going to get 64-bit data, so use the 64-bit RAWINPUTHEADER size
|
||||
data->rawinput_offset += 8;
|
||||
}
|
||||
}
|
||||
|
||||
input = (RAWINPUT *)data->rawinput;
|
||||
for (;;) {
|
||||
size = data->rawinput_size - (UINT)((BYTE *)input - data->rawinput);
|
||||
count = GetRawInputBuffer(input, &size, sizeof(RAWINPUTHEADER));
|
||||
if (count == 0 || count == (UINT)-1) {
|
||||
if (!data->rawinput || (count == (UINT)-1 && GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
|
||||
const UINT RAWINPUT_BUFFER_SIZE_INCREMENT = 96; // 2 64-bit raw mouse packets
|
||||
BYTE *rawinput = (BYTE *)realloc(data->rawinput, data->rawinput_size + RAWINPUT_BUFFER_SIZE_INCREMENT);
|
||||
if (!rawinput) {
|
||||
break;
|
||||
}
|
||||
input = (RAWINPUT *)(rawinput + ((BYTE *)input - data->rawinput));
|
||||
data->rawinput = rawinput;
|
||||
data->rawinput_size += RAWINPUT_BUFFER_SIZE_INCREMENT;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
total += count;
|
||||
|
||||
// Advance input to the end of the buffer
|
||||
while (count--) {
|
||||
input = NEXTRAWINPUTBLOCK(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (total > 0) {
|
||||
for (i = 0, input = (RAWINPUT *)data->rawinput; i < total; ++i, input = NEXTRAWINPUTBLOCK(input)) {
|
||||
if (input->header.dwType == RIM_TYPEMOUSE) {
|
||||
RAWMOUSE *rawmouse = (RAWMOUSE *)((BYTE *)input + data->rawinput_offset);
|
||||
if (mouse_capture)
|
||||
WindowsRawInputFilter::mouse_handle(rawmouse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//qDebug() << "Mouse delay: " << (plat_get_ticks() - ms_time);
|
||||
//ms_time = plat_get_ticks();
|
||||
}
|
||||
|
||||
static DWORD
|
||||
win_rawinput_thread(void* param)
|
||||
{
|
||||
RAWINPUTDEVICE rid = {
|
||||
.usUsagePage = 0x01,
|
||||
.usUsage = 0x02,
|
||||
.dwFlags = 0,
|
||||
.hwndTarget = nullptr
|
||||
};
|
||||
auto window = CreateWindowEx(0, TEXT("Message"), NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
|
||||
if (!window) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rid.hwndTarget = window;
|
||||
if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) {
|
||||
DestroyWindow(window);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
|
||||
|
||||
SetEvent(win_rawinput_data.ready_event);
|
||||
|
||||
while (!win_rawinput_data.done) {
|
||||
DWORD result = MsgWaitForMultipleObjects(1, &win_rawinput_data.done_event, FALSE, INFINITE, QS_RAWINPUT);
|
||||
|
||||
if (result != (WAIT_OBJECT_0 + 1)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Clear the queue status so MsgWaitForMultipleObjects() will wait again
|
||||
(void)GetQueueStatus(QS_RAWINPUT);
|
||||
|
||||
win_poll_mouse();
|
||||
}
|
||||
|
||||
rid.dwFlags |= RIDEV_REMOVE;
|
||||
rid.hwndTarget = NULL;
|
||||
|
||||
RegisterRawInputDevices(&rid, 1, sizeof(rid));
|
||||
DestroyWindow(window);
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" void win_joystick_handle(PRAWINPUT);
|
||||
std::unique_ptr<WindowsRawInputFilter>
|
||||
WindowsRawInputFilter::Register(MainWindow *window)
|
||||
{
|
||||
RAWINPUTDEVICE rid[2] = {
|
||||
RAWINPUTDEVICE rid[1] = {
|
||||
{
|
||||
.usUsagePage = 0x01,
|
||||
.usUsage = 0x06,
|
||||
.dwFlags = RIDEV_NOHOTKEYS,
|
||||
.hwndTarget = nullptr
|
||||
},
|
||||
{
|
||||
.usUsagePage = 0x01,
|
||||
.usUsage = 0x02,
|
||||
.dwFlags = 0,
|
||||
.hwndTarget = nullptr
|
||||
}
|
||||
};
|
||||
|
||||
if (hook_enabled && (RegisterRawInputDevices(&(rid[1]), 1, sizeof(rid[0])) == FALSE))
|
||||
return std::unique_ptr<WindowsRawInputFilter>(nullptr);
|
||||
else if (!hook_enabled && (RegisterRawInputDevices(rid, 2, sizeof(rid[0])) == FALSE))
|
||||
return std::unique_ptr<WindowsRawInputFilter>(nullptr);
|
||||
if (!hook_enabled) {
|
||||
RegisterRawInputDevices(rid, 1, sizeof(rid[0]));
|
||||
}
|
||||
|
||||
win_rawinput_data.done_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
win_rawinput_data.ready_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
|
||||
if (!win_rawinput_data.done_event || !win_rawinput_data.ready_event) {
|
||||
warning("Failed to create RawInput events.");
|
||||
|
||||
goto conclude;
|
||||
}
|
||||
|
||||
win_rawinput_data.thread = CreateThread(nullptr, 0, win_rawinput_thread, nullptr, 0, nullptr);
|
||||
if (win_rawinput_data.thread) {
|
||||
HANDLE handles[2] = { win_rawinput_data.ready_event, win_rawinput_data.thread };
|
||||
|
||||
WaitForMultipleObjects(2, handles, FALSE, INFINITE);
|
||||
} else {
|
||||
warning("Failed to create RawInput thread.");
|
||||
}
|
||||
|
||||
conclude:
|
||||
std::unique_ptr<WindowsRawInputFilter> inputfilter(new WindowsRawInputFilter(window));
|
||||
|
||||
return inputfilter;
|
||||
@@ -135,25 +272,23 @@ WindowsRawInputFilter::WindowsRawInputFilter(MainWindow *window)
|
||||
|
||||
WindowsRawInputFilter::~WindowsRawInputFilter()
|
||||
{
|
||||
RAWINPUTDEVICE rid[2] = {
|
||||
win_rawinput_data.done = true;
|
||||
if (win_rawinput_data.done_event)
|
||||
SetEvent(win_rawinput_data.done_event);
|
||||
if (win_rawinput_data.thread)
|
||||
WaitForSingleObject(win_rawinput_data.thread, INFINITE);
|
||||
RAWINPUTDEVICE rid =
|
||||
{
|
||||
.usUsagePage = 0x01,
|
||||
.usUsage = 0x06,
|
||||
.dwFlags = RIDEV_REMOVE,
|
||||
.hwndTarget = NULL
|
||||
},
|
||||
{
|
||||
.usUsagePage = 0x01,
|
||||
.usUsage = 0x02,
|
||||
.dwFlags = RIDEV_REMOVE,
|
||||
.hwndTarget = NULL
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
if (hook_enabled)
|
||||
RegisterRawInputDevices(&(rid[1]), 1, sizeof(rid[0]));
|
||||
else
|
||||
RegisterRawInputDevices(rid, 2, sizeof(rid[0]));
|
||||
if (!hook_enabled)
|
||||
RegisterRawInputDevices(&rid, 1, sizeof(rid));
|
||||
|
||||
free(win_rawinput_data.rawinput);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -305,10 +440,6 @@ WindowsRawInputFilter::handle_input(HRAWINPUT input)
|
||||
case RIM_TYPEKEYBOARD:
|
||||
keyboard_handle(raw);
|
||||
break;
|
||||
case RIM_TYPEMOUSE:
|
||||
if (mouse_capture)
|
||||
mouse_handle(raw);
|
||||
break;
|
||||
case RIM_TYPEHID:
|
||||
win_joystick_handle(raw);
|
||||
break;
|
||||
@@ -328,9 +459,9 @@ WindowsRawInputFilter::keyboard_handle(PRAWINPUT raw)
|
||||
}
|
||||
|
||||
void
|
||||
WindowsRawInputFilter::mouse_handle(PRAWINPUT raw)
|
||||
WindowsRawInputFilter::mouse_handle(RAWMOUSE* raw)
|
||||
{
|
||||
RAWMOUSE state = raw->data.mouse;
|
||||
RAWMOUSE state = *raw;
|
||||
static int x, delta_x;
|
||||
static int y, delta_y;
|
||||
static int b, delta_z;
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <QByteArray>
|
||||
|
||||
#include <windows.h>
|
||||
#include <windns.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -59,6 +60,8 @@ public:
|
||||
|
||||
~WindowsRawInputFilter();
|
||||
|
||||
static void mouse_handle(RAWMOUSE* raw);
|
||||
|
||||
private:
|
||||
MainWindow *window;
|
||||
int buttons = 0;
|
||||
@@ -71,7 +74,6 @@ private:
|
||||
|
||||
void handle_input(HRAWINPUT input);
|
||||
void keyboard_handle(PRAWINPUT raw);
|
||||
void mouse_handle(PRAWINPUT raw);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user