From: Zebediah Figura zfigura@codeweavers.com
--- dlls/user32/rawinput.c | 111 ---------------- dlls/user32/user32.spec | 2 +- dlls/user32/user_private.h | 4 - dlls/win32u/gdiobj.c | 1 + dlls/win32u/ntuser_private.h | 4 + dlls/win32u/rawinput.c | 245 +++++++++++++++++++++++++++++++++++ dlls/win32u/win32u.spec | 2 +- dlls/win32u/win32u_private.h | 1 + dlls/win32u/wrappers.c | 6 + include/ntuser.h | 1 + 10 files changed, 260 insertions(+), 117 deletions(-)
diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c index b1c79b4e186..f8980f03e9e 100644 --- a/dlls/user32/rawinput.c +++ b/dlls/user32/rawinput.c @@ -593,117 +593,6 @@ BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(const RAWINPUTDEVICE *devi return ret; }
-#ifdef _WIN64 -typedef RAWINPUTHEADER RAWINPUTHEADER64; -typedef RAWINPUT RAWINPUT64; -#else -typedef struct -{ - DWORD dwType; - DWORD dwSize; - ULONGLONG hDevice; - ULONGLONG wParam; -} RAWINPUTHEADER64; - -typedef struct -{ - RAWINPUTHEADER64 header; - union { - RAWMOUSE mouse; - RAWKEYBOARD keyboard; - RAWHID hid; - } data; -} RAWINPUT64; -#endif - -/*********************************************************************** - * GetRawInputBuffer (USER32.@) - */ -UINT WINAPI DECLSPEC_HOTPATCH GetRawInputBuffer(RAWINPUT *data, UINT *data_size, UINT header_size) -{ - struct hardware_msg_data *msg_data; - struct rawinput_thread_data *thread_data; - RAWINPUT *rawinput; - UINT count = 0, remaining, rawinput_size, next_size, overhead; - BOOL is_wow64; - int i; - - if (IsWow64Process( GetCurrentProcess(), &is_wow64 ) && is_wow64) - rawinput_size = sizeof(RAWINPUT64); - else - rawinput_size = sizeof(RAWINPUT); - overhead = rawinput_size - sizeof(RAWINPUT); - - if (header_size != sizeof(RAWINPUTHEADER)) - { - WARN("Invalid structure size %u.\n", header_size); - SetLastError(ERROR_INVALID_PARAMETER); - return ~0U; - } - - if (!data_size) - { - SetLastError(ERROR_INVALID_PARAMETER); - return ~0U; - } - - if (!data) - { - TRACE("data %p, data_size %p (%u), header_size %u\n", data, data_size, *data_size, header_size); - SERVER_START_REQ( get_rawinput_buffer ) - { - req->rawinput_size = rawinput_size; - req->buffer_size = 0; - if (wine_server_call( req )) return ~0U; - *data_size = reply->next_size; - } - SERVER_END_REQ; - return 0; - } - - if (!(thread_data = rawinput_thread_data())) return ~0U; - rawinput = thread_data->buffer; - - /* first RAWINPUT block in the buffer is used for WM_INPUT message data */ - msg_data = (struct hardware_msg_data *)NEXTRAWINPUTBLOCK(rawinput); - SERVER_START_REQ( get_rawinput_buffer ) - { - req->rawinput_size = rawinput_size; - req->buffer_size = *data_size; - wine_server_set_reply( req, msg_data, RAWINPUT_BUFFER_SIZE - rawinput->header.dwSize ); - if (wine_server_call( req )) return ~0U; - next_size = reply->next_size; - count = reply->count; - } - SERVER_END_REQ; - - remaining = *data_size; - for (i = 0; i < count; ++i) - { - data->header.dwSize = remaining; - if (!rawinput_from_hardware_message(data, msg_data)) break; - if (overhead) memmove((char *)&data->data + overhead, &data->data, - data->header.dwSize - sizeof(RAWINPUTHEADER)); - data->header.dwSize += overhead; - remaining -= data->header.dwSize; - data = NEXTRAWINPUTBLOCK(data); - msg_data = (struct hardware_msg_data *)((char *)msg_data + msg_data->size); - } - - if (count == 0 && next_size == 0) *data_size = 0; - else if (next_size == 0) next_size = rawinput_size; - - if (next_size && *data_size <= next_size) - { - SetLastError(ERROR_INSUFFICIENT_BUFFER); - *data_size = next_size; - count = ~0U; - } - - if (count) TRACE("data %p, data_size %p (%u), header_size %u, count %u\n", data, data_size, *data_size, header_size, count); - return count; -} - /*********************************************************************** * GetRawInputDeviceInfoA (USER32.@) */ diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index de20e692157..70f523da804 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -366,7 +366,7 @@ @ stdcall GetPropA(long str) @ stdcall GetPropW(long wstr) @ stdcall GetQueueStatus(long) NtUserGetQueueStatus -@ stdcall GetRawInputBuffer(ptr ptr long) +@ stdcall GetRawInputBuffer(ptr ptr long) NtUserGetRawInputBuffer @ stdcall GetRawInputData(ptr long ptr ptr long) NtUserGetRawInputData @ stdcall GetRawInputDeviceInfoA(ptr long ptr ptr) @ stdcall GetRawInputDeviceInfoW(ptr long ptr ptr) diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index a31a2bd8a01..9a2b7de4509 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -47,10 +47,6 @@ struct wm_char_mapping_data MSG get_msg; };
-/* on windows the buffer capacity is quite large as well, enough to */ -/* hold up to 10s of 1kHz mouse rawinput events */ -#define RAWINPUT_BUFFER_SIZE (512*1024) - extern BOOL (WINAPI *imm_register_window)(HWND) DECLSPEC_HIDDEN; extern void (WINAPI *imm_unregister_window)(HWND) DECLSPEC_HIDDEN;
diff --git a/dlls/win32u/gdiobj.c b/dlls/win32u/gdiobj.c index 77c3e16242a..3eb24a7bc32 100644 --- a/dlls/win32u/gdiobj.c +++ b/dlls/win32u/gdiobj.c @@ -1183,6 +1183,7 @@ static struct unix_funcs unix_funcs = NtUserGetMessage, NtUserGetPriorityClipboardFormat, NtUserGetQueueStatus, + NtUserGetRawInputBuffer, NtUserGetRawInputData, NtUserGetSystemMenu, NtUserGetUpdateRect, diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index babbc8208bc..e8051ac39d3 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -68,6 +68,10 @@ struct rawinput_thread_data RAWINPUT buffer[1]; /* rawinput message data buffer */ };
+/* on windows the buffer capacity is quite large as well, enough to */ +/* hold up to 10s of 1kHz mouse rawinput events */ +#define RAWINPUT_BUFFER_SIZE (512 * 1024) + struct user_object { HANDLE handle; diff --git a/dlls/win32u/rawinput.c b/dlls/win32u/rawinput.c index 0d2c585c36e..d6f38382b4b 100644 --- a/dlls/win32u/rawinput.c +++ b/dlls/win32u/rawinput.c @@ -23,6 +23,7 @@ #pragma makedep unix #endif
+#include <stdbool.h> #include "win32u_private.h" #include "ntuser_private.h" #include "wine/server.h" @@ -30,6 +31,250 @@
WINE_DEFAULT_DEBUG_CHANNEL(rawinput);
+#define WINE_MOUSE_HANDLE ((HANDLE)1) +#define WINE_KEYBOARD_HANDLE ((HANDLE)2) + +#ifdef _WIN64 +typedef RAWINPUTHEADER RAWINPUTHEADER64; +typedef RAWINPUT RAWINPUT64; +#else +typedef struct +{ + DWORD dwType; + DWORD dwSize; + ULONGLONG hDevice; + ULONGLONG wParam; +} RAWINPUTHEADER64; + +typedef struct +{ + RAWINPUTHEADER64 header; + union + { + RAWMOUSE mouse; + RAWKEYBOARD keyboard; + RAWHID hid; + } data; +} RAWINPUT64; +#endif + +static bool rawinput_from_hardware_message( RAWINPUT *rawinput, const struct hardware_msg_data *msg_data ) +{ + SIZE_T size; + + rawinput->header.dwType = msg_data->rawinput.type; + if (msg_data->rawinput.type == RIM_TYPEMOUSE) + { + static const unsigned int button_flags[] = + { + 0, /* MOUSEEVENTF_MOVE */ + RI_MOUSE_LEFT_BUTTON_DOWN, /* MOUSEEVENTF_LEFTDOWN */ + RI_MOUSE_LEFT_BUTTON_UP, /* MOUSEEVENTF_LEFTUP */ + RI_MOUSE_RIGHT_BUTTON_DOWN, /* MOUSEEVENTF_RIGHTDOWN */ + RI_MOUSE_RIGHT_BUTTON_UP, /* MOUSEEVENTF_RIGHTUP */ + RI_MOUSE_MIDDLE_BUTTON_DOWN, /* MOUSEEVENTF_MIDDLEDOWN */ + RI_MOUSE_MIDDLE_BUTTON_UP, /* MOUSEEVENTF_MIDDLEUP */ + }; + unsigned int i; + + rawinput->header.dwSize = FIELD_OFFSET(RAWINPUT, data) + sizeof(RAWMOUSE); + rawinput->header.hDevice = WINE_MOUSE_HANDLE; + rawinput->header.wParam = 0; + + rawinput->data.mouse.usFlags = MOUSE_MOVE_RELATIVE; + rawinput->data.mouse.usButtonFlags = 0; + rawinput->data.mouse.usButtonData = 0; + for (i = 1; i < ARRAY_SIZE(button_flags); ++i) + { + if (msg_data->flags & (1 << i)) + rawinput->data.mouse.usButtonFlags |= button_flags[i]; + } + if (msg_data->flags & MOUSEEVENTF_WHEEL) + { + rawinput->data.mouse.usButtonFlags |= RI_MOUSE_WHEEL; + rawinput->data.mouse.usButtonData = msg_data->rawinput.mouse.data; + } + if (msg_data->flags & MOUSEEVENTF_HWHEEL) + { + rawinput->data.mouse.usButtonFlags |= RI_MOUSE_HORIZONTAL_WHEEL; + rawinput->data.mouse.usButtonData = msg_data->rawinput.mouse.data; + } + if (msg_data->flags & MOUSEEVENTF_XDOWN) + { + if (msg_data->rawinput.mouse.data == XBUTTON1) + rawinput->data.mouse.usButtonFlags |= RI_MOUSE_BUTTON_4_DOWN; + else if (msg_data->rawinput.mouse.data == XBUTTON2) + rawinput->data.mouse.usButtonFlags |= RI_MOUSE_BUTTON_5_DOWN; + } + if (msg_data->flags & MOUSEEVENTF_XUP) + { + if (msg_data->rawinput.mouse.data == XBUTTON1) + rawinput->data.mouse.usButtonFlags |= RI_MOUSE_BUTTON_4_UP; + else if (msg_data->rawinput.mouse.data == XBUTTON2) + rawinput->data.mouse.usButtonFlags |= RI_MOUSE_BUTTON_5_UP; + } + + rawinput->data.mouse.ulRawButtons = 0; + rawinput->data.mouse.lLastX = msg_data->rawinput.mouse.x; + rawinput->data.mouse.lLastY = msg_data->rawinput.mouse.y; + rawinput->data.mouse.ulExtraInformation = msg_data->info; + } + else if (msg_data->rawinput.type == RIM_TYPEKEYBOARD) + { + rawinput->header.dwSize = FIELD_OFFSET(RAWINPUT, data) + sizeof(RAWKEYBOARD); + rawinput->header.hDevice = WINE_KEYBOARD_HANDLE; + rawinput->header.wParam = 0; + + rawinput->data.keyboard.MakeCode = msg_data->rawinput.kbd.scan; + rawinput->data.keyboard.Flags = (msg_data->flags & KEYEVENTF_KEYUP) ? RI_KEY_BREAK : RI_KEY_MAKE; + if (msg_data->flags & KEYEVENTF_EXTENDEDKEY) + rawinput->data.keyboard.Flags |= RI_KEY_E0; + rawinput->data.keyboard.Reserved = 0; + + switch (msg_data->rawinput.kbd.vkey) + { + case VK_LSHIFT: + case VK_RSHIFT: + rawinput->data.keyboard.VKey = VK_SHIFT; + rawinput->data.keyboard.Flags &= ~RI_KEY_E0; + break; + + case VK_LCONTROL: + case VK_RCONTROL: + rawinput->data.keyboard.VKey = VK_CONTROL; + break; + + case VK_LMENU: + case VK_RMENU: + rawinput->data.keyboard.VKey = VK_MENU; + break; + + default: + rawinput->data.keyboard.VKey = msg_data->rawinput.kbd.vkey; + break; + } + + rawinput->data.keyboard.Message = msg_data->rawinput.kbd.message; + rawinput->data.keyboard.ExtraInformation = msg_data->info; + } + else if (msg_data->rawinput.type == RIM_TYPEHID) + { + size = msg_data->size - sizeof(*msg_data); + if (size > rawinput->header.dwSize - sizeof(*rawinput)) return false; + + rawinput->header.dwSize = FIELD_OFFSET( RAWINPUT, data.hid.bRawData ) + size; + rawinput->header.hDevice = ULongToHandle( msg_data->rawinput.hid.device ); + rawinput->header.wParam = 0; + + rawinput->data.hid.dwCount = msg_data->rawinput.hid.count; + rawinput->data.hid.dwSizeHid = msg_data->rawinput.hid.length; + memcpy( rawinput->data.hid.bRawData, msg_data + 1, size ); + } + else + { + FIXME( "Unhandled rawinput type %#x.\n", msg_data->rawinput.type ); + return false; + } + + return true; +} + +/********************************************************************** + * NtUserGetRawInputBuffer (win32u.@) + */ +UINT WINAPI NtUserGetRawInputBuffer( RAWINPUT *data, UINT *data_size, UINT header_size ) +{ + unsigned int count = 0, remaining, rawinput_size, next_size, overhead; + struct rawinput_thread_data *thread_data; + struct hardware_msg_data *msg_data; + RAWINPUT *rawinput; + int i; + + if (NtCurrentTeb()->WowTebOffset) + rawinput_size = sizeof(RAWINPUT64); + else + rawinput_size = sizeof(RAWINPUT); + overhead = rawinput_size - sizeof(RAWINPUT); + + if (header_size != sizeof(RAWINPUTHEADER)) + { + WARN( "Invalid structure size %u.\n", header_size ); + SetLastError( ERROR_INVALID_PARAMETER ); + return ~0u; + } + + if (!data_size) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return ~0u; + } + + if (!data) + { + TRACE( "data %p, data_size %p (%u), header_size %u\n", data, data_size, *data_size, header_size ); + SERVER_START_REQ( get_rawinput_buffer ) + { + req->rawinput_size = rawinput_size; + req->buffer_size = 0; + if (wine_server_call( req )) return ~0u; + *data_size = reply->next_size; + } + SERVER_END_REQ; + return 0; + } + + if (!user_callbacks || !(thread_data = user_callbacks->get_rawinput_thread_data())) return ~0u; + rawinput = thread_data->buffer; + + /* first RAWINPUT block in the buffer is used for WM_INPUT message data */ + msg_data = (struct hardware_msg_data *)NEXTRAWINPUTBLOCK(rawinput); + SERVER_START_REQ( get_rawinput_buffer ) + { + req->rawinput_size = rawinput_size; + req->buffer_size = *data_size; + wine_server_set_reply( req, msg_data, RAWINPUT_BUFFER_SIZE - rawinput->header.dwSize ); + if (wine_server_call( req )) return ~0u; + next_size = reply->next_size; + count = reply->count; + } + SERVER_END_REQ; + + remaining = *data_size; + for (i = 0; i < count; ++i) + { + data->header.dwSize = remaining; + if (!rawinput_from_hardware_message( data, msg_data )) break; + if (overhead) + { + memmove( (char *)&data->data + overhead, &data->data, + data->header.dwSize - sizeof(RAWINPUTHEADER) ); + } + data->header.dwSize += overhead; + remaining -= data->header.dwSize; + data = NEXTRAWINPUTBLOCK(data); + msg_data = (struct hardware_msg_data *)((char *)msg_data + msg_data->size); + } + + if (!next_size) + { + if (!count) + *data_size = 0; + else + next_size = rawinput_size; + } + + if (next_size && *data_size <= next_size) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + *data_size = next_size; + count = ~0u; + } + + TRACE( "data %p, data_size %p (%u), header_size %u, count %u\n", + data, data_size, *data_size, header_size, count ); + return count; +} + /********************************************************************** * NtUserGetRawInputData (win32u.@) */ diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index c984316e7c9..02c2cddcf5e 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -983,7 +983,7 @@ @ stdcall -syscall NtUserGetProp(long wstr) @ stdcall NtUserGetQueueStatus(long) @ stub NtUserGetQueueStatusReadonly -@ stub NtUserGetRawInputBuffer +@ stdcall NtUserGetRawInputBuffer(ptr ptr long) @ stdcall NtUserGetRawInputData(ptr long ptr ptr long) @ stub NtUserGetRawInputDeviceInfo @ stub NtUserGetRawInputDeviceList diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index f431b967c32..d6885e97291 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -245,6 +245,7 @@ struct unix_funcs BOOL (WINAPI *pNtUserGetMessage)( MSG *msg, HWND hwnd, UINT first, UINT last ); INT (WINAPI *pNtUserGetPriorityClipboardFormat)( UINT *list, INT count ); DWORD (WINAPI *pNtUserGetQueueStatus)( UINT flags ); + UINT (WINAPI *pNtUserGetRawInputBuffer)( RAWINPUT *data, UINT *data_size, UINT header_size ); UINT (WINAPI *pNtUserGetRawInputData)( HRAWINPUT rawinput, UINT command, void *data, UINT *data_size, UINT header_size ); HMENU (WINAPI *pNtUserGetSystemMenu)( HWND hwnd, BOOL revert ); diff --git a/dlls/win32u/wrappers.c b/dlls/win32u/wrappers.c index 56ffef8f478..40c037b3fd7 100644 --- a/dlls/win32u/wrappers.c +++ b/dlls/win32u/wrappers.c @@ -1041,6 +1041,12 @@ DWORD WINAPI NtUserGetQueueStatus( UINT flags ) return unix_funcs->pNtUserGetQueueStatus( flags ); }
+UINT WINAPI DECLSPEC_HOTPATCH NtUserGetRawInputBuffer( RAWINPUT *data, UINT *data_size, UINT header_size ) +{ + if (!unix_funcs) return ~0u; + return unix_funcs->pNtUserGetRawInputBuffer( data, data_size, header_size ); +} + UINT WINAPI NtUserGetRawInputData( HRAWINPUT rawinput, UINT command, void *data, UINT *data_size, UINT header_size ) { if (!unix_funcs) return ~0u; diff --git a/include/ntuser.h b/include/ntuser.h index 269ba3ae490..bacba52db76 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -604,6 +604,7 @@ HWINSTA WINAPI NtUserGetProcessWindowStation(void); HANDLE WINAPI NtUserGetProp( HWND hwnd, const WCHAR *str ); ULONG WINAPI NtUserGetProcessDpiAwarenessContext( HANDLE process ); DWORD WINAPI NtUserGetQueueStatus( UINT flags ); +UINT WINAPI NtUserGetRawInputBuffer( RAWINPUT *data, UINT *data_size, UINT header_size ); UINT WINAPI NtUserGetRawInputData( HRAWINPUT rawinput, UINT command, void *data, UINT *data_size, UINT header_size ); ULONG WINAPI NtUserGetSystemDpiForProcess( HANDLE process ); HMENU WINAPI NtUserGetSystemMenu( HWND hwnd, BOOL revert );