windows: enable raw keyboard input when raw mouse input is enabled

This commit is contained in:
Sam Lantinga 2024-03-25 09:49:35 -07:00
parent 35d335e61f
commit 012fc1e32b
4 changed files with 96 additions and 58 deletions

View File

@ -512,9 +512,13 @@ WIN_KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
}
if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) {
if (data->raw_input_enable_count == 0) {
SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, SDL_PRESSED, scanCode);
}
} else {
if (data->raw_input_enable_count == 0) {
SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, SDL_RELEASED, scanCode);
}
/* If the key was down prior to our hook being installed, allow the
key up message to pass normally the first time. This ensures other
@ -532,8 +536,14 @@ WIN_KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
static void WIN_HandleRawMouseInput(Uint64 timestamp, SDL_WindowData *data, HANDLE hDevice, RAWMOUSE *rawmouse)
{
SDL_Mouse *mouse = SDL_GetMouse();
SDL_MouseID mouseID;
/* We only use raw mouse input in relative mode */
if (!mouse->relative_mode || mouse->relative_mode_warp) {
return;
}
if (GetMouseMessageSource(rawmouse->ulExtraInformation) == SDL_MOUSE_EVENT_SOURCE_TOUCH) {
return;
}
@ -619,17 +629,34 @@ static void WIN_HandleRawMouseInput(Uint64 timestamp, SDL_WindowData *data, HAND
WIN_CheckRawMouseButtons(timestamp, hDevice, rawmouse->usButtonFlags, data, mouseID);
}
void WIN_PollRawMouseInput(void)
static void WIN_HandleRawKeyboardInput(Uint64 timestamp, SDL_WindowData *data, HANDLE hDevice, RAWKEYBOARD *rawkeyboard)
{
SDL_KeyboardID keyboardID = (SDL_KeyboardID)(uintptr_t)hDevice;
Uint8 state = (rawkeyboard->Flags & RI_KEY_BREAK) ? SDL_RELEASED : SDL_PRESSED;
Uint16 scanCode = rawkeyboard->MakeCode;
if (rawkeyboard->Flags & RI_KEY_E0) {
scanCode |= (0xE0 << 8);
} else if (rawkeyboard->Flags & RI_KEY_E1) {
scanCode |= (0xE1 << 8);
}
// Pack scan code into one byte to make the index
Uint8 index = LOBYTE(scanCode) | (HIBYTE(scanCode) ? 0x80 : 0x00);
SDL_Scancode code = windows_scancode_table[index];
SDL_SendKeyboardKey(timestamp, keyboardID, state, code);
}
void WIN_PollRawInput(SDL_VideoDevice *_this)
{
SDL_Mouse *mouse = SDL_GetMouse();
SDL_Window *window;
SDL_WindowData *data;
UINT size, count, i, total = 0;
RAWINPUT *input;
Uint64 now;
/* We only use raw mouse input in relative mode */
if (!mouse->relative_mode || mouse->relative_mode_warp) {
if (_this->driverdata->raw_input_enable_count == 0) {
return;
}
@ -695,6 +722,9 @@ void WIN_PollRawMouseInput(void)
if (input->header.dwType == RIM_TYPEMOUSE) {
RAWMOUSE *rawmouse = (RAWMOUSE *)((BYTE *)input + data->rawinput_offset);
WIN_HandleRawMouseInput(timestamp, window->driverdata, input->header.hDevice, rawmouse);
} else if (input->header.dwType == RIM_TYPEKEYBOARD) {
RAWKEYBOARD *rawkeyboard = (RAWKEYBOARD *)((BYTE *)input + data->rawinput_offset);
WIN_HandleRawKeyboardInput(timestamp, window->driverdata, input->header.hDevice, rawkeyboard);
}
}
}
@ -1024,13 +1054,11 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
#if 0 /* We handle raw input all at once instead of using a syscall for each mouse event */
case WM_INPUT:
{
SDL_Mouse *mouse = SDL_GetMouse();
HRAWINPUT hRawInput = (HRAWINPUT)lParam;
RAWINPUT inp;
UINT size = sizeof(inp);
/* We only use raw mouse input in relative mode */
if (!mouse->relative_mode || mouse->relative_mode_warp) {
if (data->raw_input_enable_count == 0) {
break;
}
@ -1040,10 +1068,10 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
}
GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER));
/* Mouse data (ignoring synthetic mouse events generated for touchscreens) */
if (inp.header.dwType == RIM_TYPEMOUSE) {
WIN_HandleRawMouseInput(WIN_GetEventTimestamp(), data, inp.header.hDevice, &inp.data.mouse);
} else if (inp.header.dwType == RIM_TYPEKEYBOARD) {
WIN_HandleRawKeyboardInput(WIN_GetEventTimestamp(), data, inp.header.hDevice, &inp.data.keyboard);
}
} break;
#endif
@ -1107,7 +1135,7 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
}
}
if (code != SDL_SCANCODE_UNKNOWN) {
if (data->videodata->raw_input_enable_count == 0 && code != SDL_SCANCODE_UNKNOWN) {
SDL_SendKeyboardKey(WIN_GetEventTimestamp(), SDL_GLOBAL_KEYBOARD_ID, SDL_PRESSED, code);
}
}
@ -1121,7 +1149,7 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
SDL_Scancode code = WindowsScanCodeToSDLScanCode(lParam, wParam);
const Uint8 *keyboardState = SDL_GetKeyboardState(NULL);
if (code != SDL_SCANCODE_UNKNOWN) {
if (data->videodata->raw_input_enable_count == 0 && code != SDL_SCANCODE_UNKNOWN) {
if (code == SDL_SCANCODE_PRINTSCREEN &&
keyboardState[code] == SDL_RELEASED) {
SDL_SendKeyboardKey(WIN_GetEventTimestamp(), SDL_GLOBAL_KEYBOARD_ID, SDL_PRESSED, code);

View File

@ -30,7 +30,7 @@ extern HINSTANCE SDL_Instance;
extern LRESULT CALLBACK WIN_KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam);
extern LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam);
extern void WIN_PollRawMouseInput(void);
extern void WIN_PollRawInput(SDL_VideoDevice *_this);
extern void WIN_CheckKeyboardAndMouseHotplug(SDL_VideoDevice *_this, SDL_bool initial_check);
extern void WIN_PumpEvents(SDL_VideoDevice *_this);
extern void WIN_SendWakeupEvent(SDL_VideoDevice *_this, SDL_Window *window);

View File

@ -33,24 +33,24 @@ DWORD SDL_last_warp_time = 0;
HCURSOR SDL_cursor = NULL;
static SDL_Cursor *SDL_blank_cursor = NULL;
static int rawInputEnableCount = 0;
typedef struct
{
HANDLE ready_event;
HANDLE done_event;
HANDLE thread;
} RawMouseThreadData;
} RawInputThreadData;
static RawMouseThreadData thread_data = {
static RawInputThreadData thread_data = {
INVALID_HANDLE_VALUE,
INVALID_HANDLE_VALUE,
INVALID_HANDLE_VALUE
};
static DWORD WINAPI WIN_RawMouseThread(LPVOID param)
static DWORD WINAPI WIN_RawInputThread(LPVOID param)
{
RAWINPUTDEVICE rawMouse;
SDL_VideoDevice *_this = SDL_GetVideoDevice();
RawInputThreadData *data = (RawInputThreadData *)param;
RAWINPUTDEVICE devices[2];
HWND window;
window = CreateWindowEx(0, TEXT("Message"), NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
@ -58,76 +58,83 @@ static DWORD WINAPI WIN_RawMouseThread(LPVOID param)
return 0;
}
rawMouse.usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP;
rawMouse.usUsage = USB_USAGE_GENERIC_MOUSE;
rawMouse.dwFlags = 0;
rawMouse.hwndTarget = window;
devices[0].usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP;
devices[0].usUsage = USB_USAGE_GENERIC_MOUSE;
devices[0].dwFlags = 0;
devices[0].hwndTarget = window;
if (!RegisterRawInputDevices(&rawMouse, 1, sizeof(rawMouse))) {
devices[1].usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP;
devices[1].usUsage = USB_USAGE_GENERIC_KEYBOARD;
devices[1].dwFlags = 0;
devices[1].hwndTarget = window;
if (!RegisterRawInputDevices(devices, SDL_arraysize(devices), sizeof(devices[0]))) {
DestroyWindow(window);
return 0;
}
/* Make sure we get mouse events as soon as possible */
/* Make sure we get events as soon as possible */
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
/* Tell the parent we're ready to go! */
SetEvent(thread_data.ready_event);
SetEvent(data->ready_event);
for ( ; ; ) {
if (MsgWaitForMultipleObjects(1, &thread_data.done_event, 0, INFINITE, QS_RAWINPUT) != WAIT_OBJECT_0 + 1) {
if (MsgWaitForMultipleObjects(1, &data->done_event, 0, INFINITE, QS_RAWINPUT) != WAIT_OBJECT_0 + 1) {
break;
}
/* Clear the queue status so MsgWaitForMultipleObjects() will wait again */
(void)GetQueueStatus(QS_RAWINPUT);
WIN_PollRawMouseInput();
WIN_PollRawInput(_this);
}
rawMouse.dwFlags |= RIDEV_REMOVE;
RegisterRawInputDevices(&rawMouse, 1, sizeof(rawMouse));
devices[0].dwFlags |= RIDEV_REMOVE;
devices[1].dwFlags |= RIDEV_REMOVE;
RegisterRawInputDevices(devices, SDL_arraysize(devices), sizeof(devices[0]));
DestroyWindow(window);
return 0;
}
static void CleanupRawMouseThreadData(void)
static void CleanupRawInputThreadData(RawInputThreadData *data)
{
if (thread_data.thread != INVALID_HANDLE_VALUE) {
SetEvent(thread_data.done_event);
WaitForSingleObject(thread_data.thread, 500);
CloseHandle(thread_data.thread);
thread_data.thread = INVALID_HANDLE_VALUE;
if (data->thread != INVALID_HANDLE_VALUE) {
SetEvent(data->done_event);
WaitForSingleObject(data->thread, 500);
CloseHandle(data->thread);
data->thread = INVALID_HANDLE_VALUE;
}
if (thread_data.ready_event != INVALID_HANDLE_VALUE) {
CloseHandle(thread_data.ready_event);
thread_data.ready_event = INVALID_HANDLE_VALUE;
if (data->ready_event != INVALID_HANDLE_VALUE) {
CloseHandle(data->ready_event);
data->ready_event = INVALID_HANDLE_VALUE;
}
if (thread_data.done_event != INVALID_HANDLE_VALUE) {
CloseHandle(thread_data.done_event);
thread_data.done_event = INVALID_HANDLE_VALUE;
if (data->done_event != INVALID_HANDLE_VALUE) {
CloseHandle(data->done_event);
data->done_event = INVALID_HANDLE_VALUE;
}
}
static int ToggleRawInput(SDL_bool enabled)
static int ToggleRawInput(SDL_VideoDevice *_this, SDL_bool enabled)
{
SDL_VideoData *data = _this->driverdata;
int result = -1;
if (enabled) {
rawInputEnableCount++;
if (rawInputEnableCount > 1) {
++data->raw_input_enable_count;
if (data->raw_input_enable_count > 1) {
return 0; /* already done. */
}
} else {
if (rawInputEnableCount == 0) {
if (data->raw_input_enable_count == 0) {
return 0; /* already done. */
}
rawInputEnableCount--;
if (rawInputEnableCount > 0) {
--data->raw_input_enable_count;
if (data->raw_input_enable_count > 0) {
return 0; /* not time to disable yet */
}
}
@ -147,7 +154,7 @@ static int ToggleRawInput(SDL_bool enabled)
goto done;
}
thread_data.thread = CreateThread(NULL, 0, WIN_RawMouseThread, &thread_data, 0, NULL);
thread_data.thread = CreateThread(NULL, 0, WIN_RawInputThread, &thread_data, 0, NULL);
if (thread_data.thread == INVALID_HANDLE_VALUE) {
WIN_SetError("CreateThread");
goto done;
@ -162,16 +169,16 @@ static int ToggleRawInput(SDL_bool enabled)
}
result = 0;
} else {
CleanupRawMouseThreadData();
CleanupRawInputThreadData(&thread_data);
result = 0;
}
done:
if (enabled && result < 0) {
CleanupRawMouseThreadData();
CleanupRawInputThreadData(&thread_data);
/* Reset rawInputEnableCount so we can try again */
rawInputEnableCount = 0;
/* Reset so we can try again */
data->raw_input_enable_count = 0;
}
return result;
}
@ -509,7 +516,7 @@ static int WIN_WarpMouseGlobal(float x, float y)
static int WIN_SetRelativeMouseMode(SDL_bool enabled)
{
return ToggleRawInput(enabled);
return ToggleRawInput(SDL_GetVideoDevice(), enabled);
}
static int WIN_CaptureMouse(SDL_Window *window)
@ -574,9 +581,10 @@ void WIN_InitMouse(SDL_VideoDevice *_this)
void WIN_QuitMouse(SDL_VideoDevice *_this)
{
if (rawInputEnableCount) { /* force RAWINPUT off here. */
rawInputEnableCount = 1;
ToggleRawInput(SDL_FALSE);
SDL_VideoData *data = _this->driverdata;
if (data->raw_input_enable_count) { /* force RAWINPUT off here. */
data->raw_input_enable_count = 1;
ToggleRawInput(_this, SDL_FALSE);
}
if (SDL_blank_cursor) {

View File

@ -406,6 +406,8 @@ struct SDL_VideoData
SDL_bool cleared;
int raw_input_enable_count;
#ifndef SDL_DISABLE_WINDOWS_IME
SDL_bool ime_com_initialized;
struct ITfThreadMgr *ime_threadmgr;