[PATCH v11 0/9] MR10649: win32u: Initial implementation for GetPointer{,Frame}Info{,History} and GetPointerDeviceRects
-- v11: win32u: Implement NtUserGetPointerInfoList. win32u: Update pointerid 1 from mouse_in_pointer events. win32u: Implement NtUserGetPointerType. win32u: Keep track of pointer types. https://gitlab.winehq.org/wine/wine/-/merge_requests/10649
From: "Anna (navi) Figueiredo Gomes" <navi@vlhl.dev> --- dlls/win32u/input.c | 10 ++++++++++ dlls/win32u/main.c | 5 +++++ dlls/win32u/win32syscalls.h | 5 ++--- dlls/win32u/win32u.spec | 2 +- dlls/wow64win/user.c | 8 ++++++++ include/ntuser.h | 1 + 6 files changed, 27 insertions(+), 4 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index ab09c3b7d42..16f9b33ebe5 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2852,3 +2852,13 @@ INT WINAPI NtUserScheduleDispatchNotification( HWND hwnd ) return 0; } + +/********************************************************************** + * NtUserGetPointerType (win32u.@) + */ +BOOL WINAPI NtUserGetPointerType(UINT32 id, POINTER_INPUT_TYPE *type) +{ + FIXME( "(%u, %p) stub!\n", id, type ); + RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} diff --git a/dlls/win32u/main.c b/dlls/win32u/main.c index 73a6ae32448..80f309474f3 100644 --- a/dlls/win32u/main.c +++ b/dlls/win32u/main.c @@ -1743,6 +1743,11 @@ BOOL SYSCALL_API NtUserGetPointerInfoList( UINT32 id, POINTER_INPUT_TYPE type, U SYSCALL_FUNC( NtUserGetPointerInfoList ); } +BOOL SYSCALL_API NtUserGetPointerType( UINT32 id, POINTER_INPUT_TYPE *type ) +{ + SYSCALL_FUNC( NtUserGetPointerType ); +} + INT SYSCALL_API NtUserGetPriorityClipboardFormat( UINT *list, INT count ) { SYSCALL_FUNC( NtUserGetPriorityClipboardFormat ); diff --git a/dlls/win32u/win32syscalls.h b/dlls/win32u/win32syscalls.h index aa0ceec4072..36e7d5ff116 100644 --- a/dlls/win32u/win32syscalls.h +++ b/dlls/win32u/win32syscalls.h @@ -1074,7 +1074,7 @@ SYSCALL_ENTRY( 0x142e, NtUserGetPointerInfoList, 32 ) \ SYSCALL_ENTRY( 0x142f, NtUserGetPointerInputTransform, 0 ) \ SYSCALL_ENTRY( 0x1430, NtUserGetPointerProprietaryId, 0 ) \ - SYSCALL_ENTRY( 0x1431, NtUserGetPointerType, 0 ) \ + SYSCALL_ENTRY( 0x1431, NtUserGetPointerType, 8 ) \ SYSCALL_ENTRY( 0x1432, NtUserGetPrecisionTouchPadConfiguration, 0 ) \ SYSCALL_ENTRY( 0x1433, NtUserGetPriorityClipboardFormat, 8 ) \ SYSCALL_ENTRY( 0x1434, NtUserGetProcessDefaultLayout, 4 ) \ @@ -2616,7 +2616,7 @@ SYSCALL_ENTRY( 0x142e, NtUserGetPointerInfoList, 64 ) \ SYSCALL_ENTRY( 0x142f, NtUserGetPointerInputTransform, 0 ) \ SYSCALL_ENTRY( 0x1430, NtUserGetPointerProprietaryId, 0 ) \ - SYSCALL_ENTRY( 0x1431, NtUserGetPointerType, 0 ) \ + SYSCALL_ENTRY( 0x1431, NtUserGetPointerType, 16 ) \ SYSCALL_ENTRY( 0x1432, NtUserGetPrecisionTouchPadConfiguration, 0 ) \ SYSCALL_ENTRY( 0x1433, NtUserGetPriorityClipboardFormat, 16 ) \ SYSCALL_ENTRY( 0x1434, NtUserGetProcessDefaultLayout, 8 ) \ @@ -3837,7 +3837,6 @@ SYSCALL_STUB( NtUserGetPointerFrameTimes ) \ SYSCALL_STUB( NtUserGetPointerInputTransform ) \ SYSCALL_STUB( NtUserGetPointerProprietaryId ) \ - SYSCALL_STUB( NtUserGetPointerType ) \ SYSCALL_STUB( NtUserGetPrecisionTouchPadConfiguration ) \ SYSCALL_STUB( NtUserGetProcessUIContextInformation ) \ SYSCALL_STUB( NtUserGetProp2 ) \ diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 2f657aa854e..965264c8ef6 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -1072,7 +1072,7 @@ @ stdcall -syscall NtUserGetPointerInfoList(long long long long long ptr ptr ptr) @ stub -syscall NtUserGetPointerInputTransform @ stub -syscall NtUserGetPointerProprietaryId -@ stub -syscall NtUserGetPointerType +@ stdcall -syscall NtUserGetPointerType(long ptr) @ stub -syscall NtUserGetPrecisionTouchPadConfiguration @ stdcall -syscall NtUserGetPriorityClipboardFormat(ptr long) @ stdcall -syscall NtUserGetProcessDefaultLayout(ptr) diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index 0a570d79ff7..ec5f8b6bbd9 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -2853,6 +2853,14 @@ NTSTATUS WINAPI wow64_NtUserGetPointerInfoList( UINT *args ) return NtUserGetPointerInfoList( id, type, unk0, unk1, size, entry_count, pointer_count, pointer_info ); } +NTSTATUS WINAPI wow64_NtUserGetPointerType( UINT *args ) +{ + UINT id = get_ulong( &args ); + POINTER_INPUT_TYPE *type = get_ptr( &args ); + + return NtUserGetPointerType( id, type ); +} + NTSTATUS WINAPI wow64_NtUserGetPriorityClipboardFormat( UINT *args ) { UINT *list = get_ptr( &args ); diff --git a/include/ntuser.h b/include/ntuser.h index 939771c9121..a73066ba29b 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -894,6 +894,7 @@ W32KAPI BOOL WINAPI NtUserGetObjectInformation( HANDLE handle, INT index, voi W32KAPI HWND WINAPI NtUserGetOpenClipboardWindow(void); W32KAPI BOOL WINAPI NtUserGetPointerInfoList( UINT32 id, POINTER_INPUT_TYPE type, UINT_PTR, UINT_PTR, SIZE_T size, UINT32 *entry_count, UINT32 *pointer_count, void *pointer_info ); +W32KAPI BOOL WINAPI NtUserGetPointerType( UINT32 id, POINTER_INPUT_TYPE *type ); W32KAPI INT WINAPI NtUserGetPriorityClipboardFormat( UINT *list, INT count ); W32KAPI BOOL WINAPI NtUserGetProcessDefaultLayout( ULONG *layout ); W32KAPI ULONG WINAPI NtUserGetProcessDpiAwarenessContext( HANDLE process ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10649
From: "Anna (navi) Figueiredo Gomes" <navi@vlhl.dev> --- dlls/user32/input.c | 6 ++---- dlls/win32u/input.c | 33 +++++++++++++++++++++++++++++++++ dlls/win32u/main.c | 5 +++++ dlls/win32u/win32syscalls.h | 5 ++--- dlls/win32u/win32u.spec | 2 +- dlls/wow64win/user.c | 9 +++++++++ include/ntuser.h | 1 + 7 files changed, 53 insertions(+), 8 deletions(-) diff --git a/dlls/user32/input.c b/dlls/user32/input.c index 48b38166b75..d9a354f9a25 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -752,10 +752,8 @@ BOOL WINAPI GetPointerDeviceProperties( HANDLE device, UINT32 *count, BOOL WINAPI GetPointerDeviceRects( HANDLE device, RECT *device_rect, RECT *display_rect ) { - FIXME( "device %p, device_rect %p, display_rect %p stub!\n", - device, device_rect, display_rect ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + TRACE( "device %p, device_rect %p, display_rect %p\n", device, device_rect, display_rect ); + return NtUserGetPointerDeviceRects( device, device_rect, display_rect ); } BOOL WINAPI GetPointerPenInfo( UINT32 id, POINTER_PEN_INFO *info ) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 16f9b33ebe5..f723ae15a71 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -40,6 +40,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(win); WINE_DECLARE_DEBUG_CHANNEL(keyboard); +#define HIMETRIC 2540 + static const WCHAR keyboard_layouts_keyW[] = { '\\','R','e','g','i','s','t','r','y', @@ -2862,3 +2864,34 @@ BOOL WINAPI NtUserGetPointerType(UINT32 id, POINTER_INPUT_TYPE *type) RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED ); return FALSE; } + +/********************************************************************** + * NtUserGetPointerDeviceRects (win32u.@) + */ +BOOL WINAPI NtUserGetPointerDeviceRects( HANDLE handle, RECT *pointerDeviceRect, RECT *displayRect ) +{ + UINT dpi = get_system_dpi(); + RECT monitor; + + TRACE( "%p, %p, %p\n", handle, pointerDeviceRect, displayRect ); + + if (handle != INVALID_HANDLE_VALUE) + { + FIXME( "Pointer devices are not implemented!\n" ); + RtlSetLastWin32Error( ERROR_NO_DATA ); + return FALSE; + } + + monitor = get_virtual_screen_rect( dpi, MDT_DEFAULT ); + + dpi = HIMETRIC / dpi; + *pointerDeviceRect = (RECT) { + .left = monitor.left * dpi, + .top = monitor.top * dpi, + .right = monitor.right * dpi, + .bottom = monitor.bottom * dpi, + }; + *displayRect = monitor; + + return TRUE; +} diff --git a/dlls/win32u/main.c b/dlls/win32u/main.c index 80f309474f3..08e7c87314d 100644 --- a/dlls/win32u/main.c +++ b/dlls/win32u/main.c @@ -1748,6 +1748,11 @@ BOOL SYSCALL_API NtUserGetPointerType( UINT32 id, POINTER_INPUT_TYPE *type ) SYSCALL_FUNC( NtUserGetPointerType ); } +BOOL SYSCALL_API NtUserGetPointerDeviceRects( HANDLE handle, RECT *pointerDeviceRect, RECT *displayRect ) +{ + SYSCALL_FUNC( NtUserGetPointerDeviceRects ); +} + INT SYSCALL_API NtUserGetPriorityClipboardFormat( UINT *list, INT count ) { SYSCALL_FUNC( NtUserGetPriorityClipboardFormat ); diff --git a/dlls/win32u/win32syscalls.h b/dlls/win32u/win32syscalls.h index 36e7d5ff116..b298d8d4bc9 100644 --- a/dlls/win32u/win32syscalls.h +++ b/dlls/win32u/win32syscalls.h @@ -1068,7 +1068,7 @@ SYSCALL_ENTRY( 0x1428, NtUserGetPointerDeviceInputSpace, 0 ) \ SYSCALL_ENTRY( 0x1429, NtUserGetPointerDeviceOrientation, 0 ) \ SYSCALL_ENTRY( 0x142a, NtUserGetPointerDeviceProperties, 0 ) \ - SYSCALL_ENTRY( 0x142b, NtUserGetPointerDeviceRects, 0 ) \ + SYSCALL_ENTRY( 0x142b, NtUserGetPointerDeviceRects, 12 ) \ SYSCALL_ENTRY( 0x142c, NtUserGetPointerDevices, 0 ) \ SYSCALL_ENTRY( 0x142d, NtUserGetPointerFrameTimes, 0 ) \ SYSCALL_ENTRY( 0x142e, NtUserGetPointerInfoList, 32 ) \ @@ -2610,7 +2610,7 @@ SYSCALL_ENTRY( 0x1428, NtUserGetPointerDeviceInputSpace, 0 ) \ SYSCALL_ENTRY( 0x1429, NtUserGetPointerDeviceOrientation, 0 ) \ SYSCALL_ENTRY( 0x142a, NtUserGetPointerDeviceProperties, 0 ) \ - SYSCALL_ENTRY( 0x142b, NtUserGetPointerDeviceRects, 0 ) \ + SYSCALL_ENTRY( 0x142b, NtUserGetPointerDeviceRects, 24 ) \ SYSCALL_ENTRY( 0x142c, NtUserGetPointerDevices, 0 ) \ SYSCALL_ENTRY( 0x142d, NtUserGetPointerFrameTimes, 0 ) \ SYSCALL_ENTRY( 0x142e, NtUserGetPointerInfoList, 64 ) \ @@ -3832,7 +3832,6 @@ SYSCALL_STUB( NtUserGetPointerDeviceInputSpace ) \ SYSCALL_STUB( NtUserGetPointerDeviceOrientation ) \ SYSCALL_STUB( NtUserGetPointerDeviceProperties ) \ - SYSCALL_STUB( NtUserGetPointerDeviceRects ) \ SYSCALL_STUB( NtUserGetPointerDevices ) \ SYSCALL_STUB( NtUserGetPointerFrameTimes ) \ SYSCALL_STUB( NtUserGetPointerInputTransform ) \ diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 965264c8ef6..4979bf8dd53 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -1066,7 +1066,7 @@ @ stub -syscall NtUserGetPointerDeviceInputSpace @ stub -syscall NtUserGetPointerDeviceOrientation @ stub -syscall NtUserGetPointerDeviceProperties -@ stub -syscall NtUserGetPointerDeviceRects +@ stdcall -syscall NtUserGetPointerDeviceRects(long ptr ptr) @ stub -syscall NtUserGetPointerDevices @ stub -syscall NtUserGetPointerFrameTimes @ stdcall -syscall NtUserGetPointerInfoList(long long long long long ptr ptr ptr) diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index ec5f8b6bbd9..a25aa76c44b 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -2861,6 +2861,15 @@ NTSTATUS WINAPI wow64_NtUserGetPointerType( UINT *args ) return NtUserGetPointerType( id, type ); } +NTSTATUS WINAPI wow64_NtUserGetPointerDeviceRects( UINT *args ) +{ + HANDLE device = get_handle( &args ); + RECT *device_rect = get_ptr( &args ); + RECT *display_rect = get_ptr( &args ); + + return NtUserGetPointerDeviceRects(device, device_rect, display_rect); +} + NTSTATUS WINAPI wow64_NtUserGetPriorityClipboardFormat( UINT *args ) { UINT *list = get_ptr( &args ); diff --git a/include/ntuser.h b/include/ntuser.h index a73066ba29b..aef22700926 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -895,6 +895,7 @@ W32KAPI HWND WINAPI NtUserGetOpenClipboardWindow(void); W32KAPI BOOL WINAPI NtUserGetPointerInfoList( UINT32 id, POINTER_INPUT_TYPE type, UINT_PTR, UINT_PTR, SIZE_T size, UINT32 *entry_count, UINT32 *pointer_count, void *pointer_info ); W32KAPI BOOL WINAPI NtUserGetPointerType( UINT32 id, POINTER_INPUT_TYPE *type ); +W32KAPI BOOL WINAPI NtUserGetPointerDeviceRects( HANDLE handle, RECT *pointerDeviceRect, RECT *displayRect ); W32KAPI INT WINAPI NtUserGetPriorityClipboardFormat( UINT *list, INT count ); W32KAPI BOOL WINAPI NtUserGetProcessDefaultLayout( ULONG *layout ); W32KAPI ULONG WINAPI NtUserGetProcessDpiAwarenessContext( HANDLE process ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10649
From: "Anna (navi) Figueiredo Gomes" <navi@vlhl.dev> --- dlls/win32u/input.c | 11 +++++++++++ dlls/win32u/message.c | 11 ----------- dlls/win32u/win32u_private.h | 1 + 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index f723ae15a71..441c8cbeb9b 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2855,6 +2855,17 @@ INT WINAPI NtUserScheduleDispatchNotification( HWND hwnd ) return 0; } +/*********************************************************************** + * process_pointer_message + g* + * returns TRUE if the contents of 'msg' should be passed to the application + */ +BOOL process_pointer_message( MSG *msg, UINT hw_id, const struct hardware_msg_data *msg_data ) +{ + msg->pt = point_phys_to_win_dpi( msg->hwnd, msg->pt ); + return TRUE; +} + /********************************************************************** * NtUserGetPointerType (win32u.@) */ diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index fe0cd2a61fe..62115515fb2 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2456,17 +2456,6 @@ static void send_parent_notify( HWND hwnd, WORD event, WORD idChild, POINT pt ) } } -/*********************************************************************** - * process_pointer_message - * - * returns TRUE if the contents of 'msg' should be passed to the application - */ -static BOOL process_pointer_message( MSG *msg, UINT hw_id, const struct hardware_msg_data *msg_data ) -{ - msg->pt = point_phys_to_win_dpi( msg->hwnd, msg->pt ); - return TRUE; -} - /*********************************************************************** * process_keyboard_message * diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index cab58dfd499..d68cba0dc50 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -110,6 +110,7 @@ extern void update_current_mouse_window( HWND hwnd, INT hittest, POINT pos ); extern BOOL process_wine_clipcursor( HWND hwnd, UINT flags, BOOL reset ); extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ); extern USHORT map_scan_to_kbd_vkey( USHORT scan, HKL layout ); +extern BOOL process_pointer_message( MSG *msg, UINT hw_id, const struct hardware_msg_data *msg_data ); /* menu.c */ extern UINT draw_nc_menu_bar( HDC hdc, RECT *rect, HWND hwnd ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10649
From: "Anna (navi) Figueiredo Gomes" <navi@vlhl.dev> --- dlls/win32u/input.c | 113 +++++++++++++++++++++++++++++++++++ dlls/win32u/ntuser_private.h | 1 + 2 files changed, 114 insertions(+) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 441c8cbeb9b..1df60d5e2bc 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -407,6 +407,19 @@ static const KBDTABLES kbdus_tables = static LONG clipping_cursor; /* clipping thread counter */ static LONG enable_mouse_in_pointer = -1; +static LONG last_frame = 0; + +struct pointer +{ + UINT32 id; + struct list entry; + POINTER_INFO info; +}; + +struct pointer_thread_data +{ + struct list known_pointers; +}; BOOL grab_pointer = TRUE; BOOL grab_fullscreen = FALSE; @@ -2855,6 +2868,98 @@ INT WINAPI NtUserScheduleDispatchNotification( HWND hwnd ) return 0; } +static struct pointer_thread_data *get_pointer_thread_data(void) +{ + struct user_thread_info *thread_info = get_user_thread_info(); + if (!thread_info->pointer_data && (thread_info->pointer_data = calloc( 1, sizeof(*thread_info->pointer_data) ))) + list_init( &thread_info->pointer_data->known_pointers ); + return thread_info->pointer_data; +}; + +static struct pointer *find_pointerid(UINT32 id) +{ + struct pointer_thread_data *thread_data = get_pointer_thread_data(); + struct pointer *pointer; + + TRACE( "looking for pointer id %d\n", id ); + + LIST_FOR_EACH_ENTRY(pointer, &thread_data->known_pointers, struct pointer, entry) + if (pointer->id == id) + return pointer; + + TRACE( "allocating pointer id %d\n", id ); + + if (!thread_data || !(pointer = calloc( 1, sizeof(*pointer) ))) + return NULL; + + pointer->id = id; + list_add_tail( &thread_data->known_pointers, &pointer->entry ); + + return pointer; +} + +static POINT pixel_to_himetric( POINT px ) +{ + UINT dpi = HIMETRIC / get_system_dpi(); + + return (POINT) { + .x = px.x * dpi, + .y = px.y * dpi, + }; +} + +static POINTER_INFO pointer_info_from_msg( const MSG *msg ) +{ + POINT location = { LOWORD( msg->lParam ), HIWORD( msg->lParam ) }; + LARGE_INTEGER counter; + POINTER_INFO info = { + .pointerId = GET_POINTERID_WPARAM( msg->wParam ), + .sourceDevice = INVALID_HANDLE_VALUE, + .frameId = InterlockedIncrement( &last_frame ), + .hwndTarget = msg->hwnd, + .historyCount = 1, + .dwTime = msg->time, + }; + + info.pointerFlags = HIWORD( msg->wParam ); + switch (msg->message) + { + case WM_POINTERUPDATE: info.pointerFlags |= POINTER_FLAG_UPDATE; break; + case WM_POINTERDOWN: info.pointerFlags |= POINTER_FLAG_DOWN; break; + case WM_POINTERUP: info.pointerFlags |= POINTER_FLAG_UP; break; + } + info.ptPixelLocation = info.ptPixelLocationRaw = location; + info.ptHimetricLocation = info.ptHimetricLocationRaw = pixel_to_himetric( location ); + + NtQueryPerformanceCounter( &counter, NULL ); + info.PerformanceCount = counter.QuadPart; + + return info; +} + +static POINTER_BUTTON_CHANGE_TYPE compare_button( const POINTER_INFO *old, const POINTER_INFO *new ) +{ + POINTER_BUTTON_CHANGE_TYPE change = POINTER_CHANGE_NONE; + static const struct + { + POINTER_FLAGS flag; + POINTER_BUTTON_CHANGE_TYPE down, up; + } map[] = { + { POINTER_FLAG_FIRSTBUTTON, POINTER_CHANGE_FIRSTBUTTON_DOWN, POINTER_CHANGE_FIRSTBUTTON_UP }, + { POINTER_FLAG_SECONDBUTTON, POINTER_CHANGE_SECONDBUTTON_DOWN, POINTER_CHANGE_SECONDBUTTON_UP }, + { POINTER_FLAG_THIRDBUTTON, POINTER_CHANGE_THIRDBUTTON_DOWN, POINTER_CHANGE_THIRDBUTTON_UP }, + { POINTER_FLAG_FOURTHBUTTON, POINTER_CHANGE_FOURTHBUTTON_DOWN, POINTER_CHANGE_FOURTHBUTTON_UP }, + { POINTER_FLAG_FIFTHBUTTON, POINTER_CHANGE_FIFTHBUTTON_DOWN, POINTER_CHANGE_FIFTHBUTTON_UP }, + }; + + for (size_t i = 0; i < ARRAY_SIZE(map); i++) + if (!(old->pointerFlags & map[i].flag) && new->pointerFlags & map[i].flag) + change |= map[i].down; + else if (old->pointerFlags & map[i].flag && !(new->pointerFlags & map[i].flag)) + change |= map[i].up; + return change; +} + /*********************************************************************** * process_pointer_message g* @@ -2862,7 +2967,15 @@ INT WINAPI NtUserScheduleDispatchNotification( HWND hwnd ) */ BOOL process_pointer_message( MSG *msg, UINT hw_id, const struct hardware_msg_data *msg_data ) { + struct pointer *pointer; + POINTER_INFO info; + msg->pt = point_phys_to_win_dpi( msg->hwnd, msg->pt ); + if (!(pointer = find_pointerid( GET_POINTERID_WPARAM( msg->wParam ) ))) + return TRUE; + info = pointer_info_from_msg( msg ); + info.ButtonChangeType = compare_button( &pointer->info, &info ); + pointer->info = info; return TRUE; } diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 2f9bc9c2ccc..2fa6944b820 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -130,6 +130,7 @@ struct user_thread_info DWORD clipping_reset; /* time when clipping was last reset */ struct session_thread_data *session_data; /* shared session thread data */ struct mouse_tracking_info *mouse_tracking_info; /* NtUserTrackMouseEvent handling */ + struct pointer_thread_data *pointer_data; /* list of known pointers */ }; C_ASSERT( sizeof(struct user_thread_info) <= sizeof(((TEB *)0)->Win32ClientInfo) ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10649
From: "Anna (navi) Figueiredo Gomes" <navi@vlhl.dev> Seems like pointerId 1 is always the mouse, regardless of EnableMouseInPointer. --- dlls/win32u/input.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 1df60d5e2bc..bf4a072e706 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2868,36 +2868,47 @@ INT WINAPI NtUserScheduleDispatchNotification( HWND hwnd ) return 0; } +static struct pointer *allocate_pointerid( UINT32 id ); + static struct pointer_thread_data *get_pointer_thread_data(void) { struct user_thread_info *thread_info = get_user_thread_info(); if (!thread_info->pointer_data && (thread_info->pointer_data = calloc( 1, sizeof(*thread_info->pointer_data) ))) + { list_init( &thread_info->pointer_data->known_pointers ); + allocate_pointerid( 1 ); + } return thread_info->pointer_data; }; -static struct pointer *find_pointerid(UINT32 id) +static struct pointer *allocate_pointerid( UINT32 id ) { struct pointer_thread_data *thread_data = get_pointer_thread_data(); struct pointer *pointer; - TRACE( "looking for pointer id %d\n", id ); - - LIST_FOR_EACH_ENTRY(pointer, &thread_data->known_pointers, struct pointer, entry) - if (pointer->id == id) - return pointer; - TRACE( "allocating pointer id %d\n", id ); if (!thread_data || !(pointer = calloc( 1, sizeof(*pointer) ))) return NULL; - pointer->id = id; list_add_tail( &thread_data->known_pointers, &pointer->entry ); return pointer; } +static struct pointer *find_pointerid( UINT32 id ) { + struct pointer_thread_data *thread_data = get_pointer_thread_data(); + struct pointer *pointer; + + TRACE( "looking for pointer id %d\n", id ); + + LIST_FOR_EACH_ENTRY(pointer, &thread_data->known_pointers, struct pointer, entry) + if (pointer->id == id) + return pointer; + + return allocate_pointerid( id ); +} + static POINT pixel_to_himetric( POINT px ) { UINT dpi = HIMETRIC / get_system_dpi(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10649
From: "Anna (navi) Figueiredo Gomes" <navi@vlhl.dev> --- dlls/win32u/input.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index bf4a072e706..1b06dcd21dc 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -413,6 +413,7 @@ struct pointer { UINT32 id; struct list entry; + POINTER_INPUT_TYPE type; POINTER_INFO info; }; @@ -2868,7 +2869,7 @@ INT WINAPI NtUserScheduleDispatchNotification( HWND hwnd ) return 0; } -static struct pointer *allocate_pointerid( UINT32 id ); +static struct pointer *allocate_pointerid( UINT32 id, POINTER_INPUT_TYPE type ); static struct pointer_thread_data *get_pointer_thread_data(void) { @@ -2876,27 +2877,29 @@ static struct pointer_thread_data *get_pointer_thread_data(void) if (!thread_info->pointer_data && (thread_info->pointer_data = calloc( 1, sizeof(*thread_info->pointer_data) ))) { list_init( &thread_info->pointer_data->known_pointers ); - allocate_pointerid( 1 ); + allocate_pointerid( 1, PT_MOUSE ); } return thread_info->pointer_data; }; -static struct pointer *allocate_pointerid( UINT32 id ) +static struct pointer *allocate_pointerid( UINT32 id, POINTER_INPUT_TYPE type ) { struct pointer_thread_data *thread_data = get_pointer_thread_data(); struct pointer *pointer; - TRACE( "allocating pointer id %d\n", id ); + TRACE( "allocating pointer id %d, type %#x\n", id, type ); if (!thread_data || !(pointer = calloc( 1, sizeof(*pointer) ))) return NULL; pointer->id = id; + pointer->type = type; list_add_tail( &thread_data->known_pointers, &pointer->entry ); return pointer; } -static struct pointer *find_pointerid( UINT32 id ) { +static struct pointer *find_pointerid( UINT32 id, POINTER_INPUT_TYPE type ) +{ struct pointer_thread_data *thread_data = get_pointer_thread_data(); struct pointer *pointer; @@ -2906,7 +2909,7 @@ static struct pointer *find_pointerid( UINT32 id ) { if (pointer->id == id) return pointer; - return allocate_pointerid( id ); + return allocate_pointerid( id, type ); } static POINT pixel_to_himetric( POINT px ) @@ -2971,6 +2974,18 @@ static POINTER_BUTTON_CHANGE_TYPE compare_button( const POINTER_INFO *old, const return change; } +static POINTER_INPUT_TYPE pointer_type_from_hw( const struct hw_msg_source *source ) +{ + switch (source->origin) + { + case IMDT_PEN: return PT_PEN; + case IMDT_MOUSE: return PT_MOUSE; + case IMDT_TOUCH: + case IMDT_TOUCHPAD: return PT_TOUCH; + default: return PT_POINTER; + } +} + /*********************************************************************** * process_pointer_message g* @@ -2982,11 +2997,12 @@ BOOL process_pointer_message( MSG *msg, UINT hw_id, const struct hardware_msg_da POINTER_INFO info; msg->pt = point_phys_to_win_dpi( msg->hwnd, msg->pt ); - if (!(pointer = find_pointerid( GET_POINTERID_WPARAM( msg->wParam ) ))) + if (!(pointer = find_pointerid( GET_POINTERID_WPARAM( msg->wParam ), pointer_type_from_hw( &msg_data->source ) ))) return TRUE; info = pointer_info_from_msg( msg ); info.ButtonChangeType = compare_button( &pointer->info, &info ); pointer->info = info; + pointer->info.pointerType = pointer->type; return TRUE; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10649
From: "Anna (navi) Figueiredo Gomes" <navi@vlhl.dev> --- dlls/user32/misc.c | 11 ++--------- dlls/user32/tests/input.c | 2 -- dlls/win32u/input.c | 23 +++++++++++++++++------ 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/dlls/user32/misc.c b/dlls/user32/misc.c index 6333fcb48b4..16f02958135 100644 --- a/dlls/user32/misc.c +++ b/dlls/user32/misc.c @@ -512,16 +512,9 @@ LRESULT WINAPI PackTouchHitTestingProximityEvaluation(const TOUCH_HIT_TESTING_IN */ BOOL WINAPI GetPointerType(UINT32 id, POINTER_INPUT_TYPE *type) { - FIXME("(%d %p): stub\n", id, type); + TRACE( "%d %p\n", id, type ); - if(!id || !type) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - *type = PT_MOUSE; - return TRUE; + return NtUserGetPointerType( id, type ); } BOOL WINAPI GetPointerInfo(UINT32 id, POINTER_INFO *info) diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 905ff0dd922..d6fb9830d76 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -5527,9 +5527,7 @@ static void test_GetPointerInfo( BOOL mouse_in_pointer_enabled ) ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = pGetPointerType( 0xdead, &type ); - todo_wine ok( !ret, "GetPointerType succeeded\n" ); - todo_wine ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); ret = pGetPointerType( 1, &type ); ok( ret, "GetPointerType failed, error %lu\n", GetLastError() ); diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 1b06dcd21dc..c27ba4a6e9d 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2898,7 +2898,7 @@ static struct pointer *allocate_pointerid( UINT32 id, POINTER_INPUT_TYPE type ) return pointer; } -static struct pointer *find_pointerid( UINT32 id, POINTER_INPUT_TYPE type ) +static struct pointer *find_pointerid( UINT32 id ) { struct pointer_thread_data *thread_data = get_pointer_thread_data(); struct pointer *pointer; @@ -2909,7 +2909,7 @@ static struct pointer *find_pointerid( UINT32 id, POINTER_INPUT_TYPE type ) if (pointer->id == id) return pointer; - return allocate_pointerid( id, type ); + return NULL; } static POINT pixel_to_himetric( POINT px ) @@ -2993,11 +2993,13 @@ static POINTER_INPUT_TYPE pointer_type_from_hw( const struct hw_msg_source *sour */ BOOL process_pointer_message( MSG *msg, UINT hw_id, const struct hardware_msg_data *msg_data ) { + UINT32 pointer_id = GET_POINTERID_WPARAM( msg->wParam ); struct pointer *pointer; POINTER_INFO info; msg->pt = point_phys_to_win_dpi( msg->hwnd, msg->pt ); - if (!(pointer = find_pointerid( GET_POINTERID_WPARAM( msg->wParam ), pointer_type_from_hw( &msg_data->source ) ))) + if (!(pointer = find_pointerid( pointer_id )) && + !(pointer = allocate_pointerid( pointer_id, pointer_type_from_hw( &msg_data->source ) ))) return TRUE; info = pointer_info_from_msg( msg ); info.ButtonChangeType = compare_button( &pointer->info, &info ); @@ -3011,9 +3013,18 @@ BOOL process_pointer_message( MSG *msg, UINT hw_id, const struct hardware_msg_da */ BOOL WINAPI NtUserGetPointerType(UINT32 id, POINTER_INPUT_TYPE *type) { - FIXME( "(%u, %p) stub!\n", id, type ); - RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + struct pointer *pointer; + + TRACE( "%u, %p\n", id, type ); + + if (!id || !type || !(pointer = find_pointerid( id )) ) + { + RtlSetLastWin32Error( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + *type = pointer->type; + return TRUE; } /********************************************************************** -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10649
From: "Anna (navi) Figueiredo Gomes" <navi@vlhl.dev> --- dlls/win32u/input.c | 45 +++++++++++++++++++++--------------- dlls/win32u/message.c | 11 ++++++++- dlls/win32u/win32u_private.h | 2 ++ 3 files changed, 38 insertions(+), 20 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index c27ba4a6e9d..453ba810783 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2922,21 +2922,21 @@ static POINT pixel_to_himetric( POINT px ) }; } -static POINTER_INFO pointer_info_from_msg( const MSG *msg ) +POINTER_INFO pointer_info_from_msg( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, DWORD time ) { - POINT location = { LOWORD( msg->lParam ), HIWORD( msg->lParam ) }; + POINT location = { LOWORD( lParam ), HIWORD( lParam ) }; LARGE_INTEGER counter; POINTER_INFO info = { - .pointerId = GET_POINTERID_WPARAM( msg->wParam ), + .pointerId = GET_POINTERID_WPARAM( wParam ), .sourceDevice = INVALID_HANDLE_VALUE, .frameId = InterlockedIncrement( &last_frame ), - .hwndTarget = msg->hwnd, + .hwndTarget = hwnd, .historyCount = 1, - .dwTime = msg->time, + .dwTime = time, }; - info.pointerFlags = HIWORD( msg->wParam ); - switch (msg->message) + info.pointerFlags = HIWORD( wParam ); + switch (msg) { case WM_POINTERUPDATE: info.pointerFlags |= POINTER_FLAG_UPDATE; break; case WM_POINTERDOWN: info.pointerFlags |= POINTER_FLAG_DOWN; break; @@ -2974,6 +2974,23 @@ static POINTER_BUTTON_CHANGE_TYPE compare_button( const POINTER_INFO *old, const return change; } +void pointer_update( UINT32 id, POINTER_INPUT_TYPE type, POINTER_INFO *info ) +{ + POINTER_BUTTON_CHANGE_TYPE buttons; + struct pointer *pointer; + + TRACE( "updating pointer id %d.\n", id ); + + if (!(pointer = find_pointerid( id )) && !(pointer = allocate_pointerid( id, type ))) + return; + + buttons = compare_button(&pointer->info, info); + + pointer->info = *info; + pointer->info.pointerType = pointer->type; + pointer->info.ButtonChangeType = buttons; +} + static POINTER_INPUT_TYPE pointer_type_from_hw( const struct hw_msg_source *source ) { switch (source->origin) @@ -2993,18 +3010,8 @@ static POINTER_INPUT_TYPE pointer_type_from_hw( const struct hw_msg_source *sour */ BOOL process_pointer_message( MSG *msg, UINT hw_id, const struct hardware_msg_data *msg_data ) { - UINT32 pointer_id = GET_POINTERID_WPARAM( msg->wParam ); - struct pointer *pointer; - POINTER_INFO info; - - msg->pt = point_phys_to_win_dpi( msg->hwnd, msg->pt ); - if (!(pointer = find_pointerid( pointer_id )) && - !(pointer = allocate_pointerid( pointer_id, pointer_type_from_hw( &msg_data->source ) ))) - return TRUE; - info = pointer_info_from_msg( msg ); - info.ButtonChangeType = compare_button( &pointer->info, &info ); - pointer->info = info; - pointer->info.pointerType = pointer->type; + POINTER_INFO info = pointer_info_from_msg( msg->hwnd, msg->message, msg->wParam, msg->lParam, msg->time ); + pointer_update( GET_POINTERID_WPARAM( msg->wParam ), pointer_type_from_hw( &msg_data->source ), &info ); return TRUE; } diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 62115515fb2..c694e88f77d 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2666,7 +2666,16 @@ static BOOL process_mouse_message( MSG *msg, UINT hw_id, ULONG_PTR extra_info, H break; } - if (message) send_message( msg->hwnd, message, MAKELONG( 1, flags ), MAKELONG( msg->pt.x, msg->pt.y ) ); + if (message) + { + LPARAM lParam = MAKELONG( msg->pt.x, msg->pt.y ); + WPARAM wParam = MAKELONG( 1, flags ); + POINTER_INFO info; + + info = pointer_info_from_msg( msg->hwnd, message, wParam, lParam, msg->time ); + pointer_update( 1, PT_MOUSE, &info ); + send_message( msg->hwnd, message, wParam, lParam ); + } } /* FIXME: is this really the right place for this hook? */ diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index d68cba0dc50..0217f52e5da 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -111,6 +111,8 @@ extern BOOL process_wine_clipcursor( HWND hwnd, UINT flags, BOOL reset ); extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ); extern USHORT map_scan_to_kbd_vkey( USHORT scan, HKL layout ); extern BOOL process_pointer_message( MSG *msg, UINT hw_id, const struct hardware_msg_data *msg_data ); +extern POINTER_INFO pointer_info_from_msg( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, DWORD time ); +extern void pointer_update( UINT32 id, POINTER_INPUT_TYPE type, POINTER_INFO *info ); /* menu.c */ extern UINT draw_nc_menu_bar( HDC hdc, RECT *rect, HWND hwnd ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10649
From: "Anna (navi) Figueiredo Gomes" <navi@vlhl.dev> --- dlls/user32/input.c | 63 ++++++++++++++++++++++++++++++++------ dlls/user32/misc.c | 32 +++++++++++++++++-- dlls/user32/tests/input.c | 17 ++++------ dlls/user32/user32.spec | 16 +++++----- dlls/win32u/input.c | 62 +++++++++++++++++++++++++++++-------- dlls/win32u/tests/win32u.c | 8 ++--- 6 files changed, 151 insertions(+), 47 deletions(-) diff --git a/dlls/user32/input.c b/dlls/user32/input.c index d9a354f9a25..da4efbc7377 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -758,16 +758,20 @@ BOOL WINAPI GetPointerDeviceRects( HANDLE device, RECT *device_rect, RECT *displ BOOL WINAPI GetPointerPenInfo( UINT32 id, POINTER_PEN_INFO *info ) { - FIXME( "id %u, info %p stub!\n", id, info ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + UINT32 count = 1; + + TRACE( "id %u, info %p\n", id, info ); + + return NtUserGetPointerInfoList( id, PT_PEN, 0, 0, sizeof(*info), &count, &count, info ); } BOOL WINAPI GetPointerTouchInfo( UINT32 id, POINTER_TOUCH_INFO *info ) { - FIXME( "id %u, info %p stub!\n", id, info ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + UINT32 count = 1; + + TRACE( "id %u, info %p stub!\n", id, info ); + + return NtUserGetPointerInfoList( id, PT_TOUCH, 0, 0, sizeof(*info), &count, &count, info ); } BOOL WINAPI GetRawPointerDeviceData( UINT32 id, UINT32 hist_count, UINT32 prop_count, @@ -781,9 +785,50 @@ BOOL WINAPI GetRawPointerDeviceData( UINT32 id, UINT32 hist_count, UINT32 prop_c BOOL WINAPI GetPointerTouchInfoHistory( UINT32 id, UINT32 *count, POINTER_TOUCH_INFO *info ) { - FIXME( "id %u, count %p, info %p stub!\n", id, count, info ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + UINT32 pointers = 1; + + TRACE( "id %u, count %p, info %p\n", id, count, info ); + + return NtUserGetPointerInfoList( id, PT_TOUCH, 0, 0, sizeof(*info), count, &pointers, info ); +} + +BOOL WINAPI GetPointerPenInfoHistory( UINT32 id, UINT32 *count, POINTER_PEN_INFO *info ) +{ + UINT32 pointers = 1; + + TRACE( "id %u, count %p, info %p\n", id, count, info ); + + return NtUserGetPointerInfoList( id, PT_PEN, 0, 0, sizeof(*info), count, &pointers, info ); +} + +BOOL WINAPI GetPointerFrameTouchInfo( UINT32 id, UINT32 *count, POINTER_TOUCH_INFO *info ) +{ + UINT32 entries = 1; + + TRACE( "id %u, count %p, info %p\n", id, count, info ); + + return NtUserGetPointerInfoList( id, PT_TOUCH, 0, 0, sizeof(*info), &entries, count, info ); +} + +BOOL WINAPI GetPointerFramePenInfo( UINT32 id, UINT32 *count, POINTER_PEN_INFO *info ) +{ + UINT32 entries = 1; + + TRACE( "id %u, count %p, info %p\n", id, count, info ); + + return NtUserGetPointerInfoList( id, PT_PEN, 0, 0, sizeof(*info), &entries, count, info ); +} + +BOOL WINAPI GetPointerFrameTouchInfoHistory( UINT32 id, UINT32 *entries, UINT32 *pointers, POINTER_TOUCH_INFO *info ) +{ + TRACE( "id %u, entries %p, pointers %p, info %p\n", id, entries, pointers, info ); + return NtUserGetPointerInfoList( id, PT_TOUCH, 0, 0, sizeof(*info), entries, pointers, info ); +} + +BOOL WINAPI GetPointerFramePenInfoHistory( UINT32 id, UINT32 *entries, UINT32 *pointers, POINTER_PEN_INFO *info ) +{ + TRACE( "id %u, entries %p, pointers %p, info %p\n", id, entries, pointers, info ); + return NtUserGetPointerInfoList( id, PT_PEN, 0, 0, sizeof(*info), entries, pointers, info ); } diff --git a/dlls/user32/misc.c b/dlls/user32/misc.c index 16f02958135..764e559df19 100644 --- a/dlls/user32/misc.c +++ b/dlls/user32/misc.c @@ -519,10 +519,36 @@ BOOL WINAPI GetPointerType(UINT32 id, POINTER_INPUT_TYPE *type) BOOL WINAPI GetPointerInfo(UINT32 id, POINTER_INFO *info) { - FIXME("(%d %p): stub\n", id, info); + UINT32 count = 1; - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; + TRACE( "id %d, info %p\n", id, info ); + + return NtUserGetPointerInfoList( id, PT_POINTER, 0, 0, sizeof(*info), &count, &count, info ); +} + +BOOL WINAPI GetPointerInfoHistory( UINT32 id, UINT32 *count, POINTER_INFO *info ) +{ + UINT32 pointers = 1; + + TRACE( "id %u, count %p, info %p\n", id, count, info ); + + return NtUserGetPointerInfoList( id, PT_POINTER, 0, 0, sizeof(*info), count, &pointers, info ); +} + +BOOL WINAPI GetPointerFrameInfo( UINT32 id, UINT32 *count, POINTER_INFO *info ) +{ + UINT32 entries = 1; + + TRACE( "id %u, count %p, info %p\n", id, count, info ); + + return NtUserGetPointerInfoList( id, PT_POINTER, 0, 0, sizeof(*info), &entries, count, info ); +} + +BOOL WINAPI GetPointerFrameInfoHistory( UINT32 id, UINT32 *entries, UINT32 *pointers, POINTER_INFO *info ) +{ + TRACE( "id %u, entries %p, pointers %p, info %p\n", id, entries, pointers, info ); + + return NtUserGetPointerInfoList( id, PT_POINTER, 0, 0, sizeof(*info), entries, pointers, info ); } LRESULT WINAPI ImeWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index d6fb9830d76..51bad80e252 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -5416,7 +5416,9 @@ static DWORD CALLBACK test_GetPointerInfo_thread( void *arg ) memset( &pointer_info, 0xcd, sizeof(pointer_info) ); ret = pGetPointerInfo( 1, &pointer_info ); + todo_wine ok( !ret, "GetPointerInfo succeeded\n" ); + todo_wine ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); DestroyWindow( hwnd ); @@ -5545,13 +5547,13 @@ static void test_GetPointerInfo( BOOL mouse_in_pointer_enabled ) ret = pGetPointerInfo( 1, invalid_ptr ); ok( !ret, "GetPointerInfo succeeded\n" ); - todo_wine ok( GetLastError() == ERROR_NOACCESS || broken(GetLastError() == ERROR_INVALID_PARAMETER) /* w10 32bit */, "got error %lu\n", GetLastError() ); memset( pointer_info, 0xcd, sizeof(pointer_info) ); ret = pGetPointerInfo( 1, pointer_info ); ok( !ret, "GetPointerInfo succeeded\n" ); + todo_wine ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); SetCursorPos( 500, 500 ); /* avoid generating mouse message on window creation */ @@ -5563,6 +5565,7 @@ static void test_GetPointerInfo( BOOL mouse_in_pointer_enabled ) memset( pointer_info, 0xcd, sizeof(pointer_info) ); ret = pGetPointerInfo( 1, pointer_info ); ok( !ret, "GetPointerInfo succeeded\n" ); + todo_wine ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); SetCursorPos( 200, 200 ); @@ -5648,30 +5651,26 @@ static void test_GetPointerInfo( BOOL mouse_in_pointer_enabled ) memset( pointer_info, 0xcd, sizeof(pointer_info) ); ret = pGetPointerInfo( 0xdead, pointer_info ); ok( !ret, "GetPointerInfo succeeded\n" ); + todo_wine ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); memset( pointer_info, 0xcd, sizeof(pointer_info) ); ret = pGetPointerInfo( 1, pointer_info ); - todo_wine_if(mouse_in_pointer_enabled) ok( ret == mouse_in_pointer_enabled, "GetPointerInfo failed, error %lu\n", GetLastError() ); if (!mouse_in_pointer_enabled) { + todo_wine ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); return; } - todo_wine ok( pointer_info[0].pointerType == PT_MOUSE, "got pointerType %lu\n", pointer_info[0].pointerType ); - todo_wine ok( pointer_info[0].pointerId == 1, "got pointerId %u\n", pointer_info[0].pointerId ); ok( !!pointer_info[0].frameId, "got frameId %u\n", pointer_info[0].frameId ); - todo_wine ok( pointer_info[0].pointerFlags == (0x40000 | POINTER_MESSAGE_FLAG_INRANGE), "got pointerFlags %#x\n", pointer_info[0].pointerFlags ); - todo_wine ok( pointer_info[0].sourceDevice == INVALID_HANDLE_VALUE || broken(!!pointer_info[0].sourceDevice) /* < w10 & 32bit */, "got sourceDevice %p\n", pointer_info[0].sourceDevice ); - todo_wine ok( pointer_info[0].hwndTarget == hwnd, "got hwndTarget %p\n", pointer_info[0].hwndTarget ); ok( !!pointer_info[0].ptPixelLocation.x, "got ptPixelLocation %s\n", wine_dbgstr_point( &pointer_info[0].ptPixelLocation ) ); ok( !!pointer_info[0].ptPixelLocation.y, "got ptPixelLocation %s\n", wine_dbgstr_point( &pointer_info[0].ptPixelLocation ) ); @@ -5682,14 +5681,10 @@ static void test_GetPointerInfo( BOOL mouse_in_pointer_enabled ) ok( !!pointer_info[0].ptHimetricLocationRaw.x, "got ptHimetricLocationRaw %s\n", wine_dbgstr_point( &pointer_info[0].ptHimetricLocationRaw ) ); ok( !!pointer_info[0].ptHimetricLocationRaw.y, "got ptHimetricLocationRaw %s\n", wine_dbgstr_point( &pointer_info[0].ptHimetricLocationRaw ) ); ok( !!pointer_info[0].dwTime, "got dwTime %lu\n", pointer_info[0].dwTime ); - todo_wine ok( pointer_info[0].historyCount == 1, "got historyCount %u\n", pointer_info[0].historyCount ); - todo_wine ok( pointer_info[0].InputData == 0, "got InputData %u\n", pointer_info[0].InputData ); - todo_wine ok( pointer_info[0].dwKeyStates == 0, "got dwKeyStates %lu\n", pointer_info[0].dwKeyStates ); ok( !!pointer_info[0].PerformanceCount, "got PerformanceCount %I64u\n", pointer_info[0].PerformanceCount ); - todo_wine ok( pointer_info[0].ButtonChangeType == POINTER_CHANGE_FIRSTBUTTON_UP, "got ButtonChangeType %u\n", pointer_info[0].ButtonChangeType ); thread = CreateThread( NULL, 0, test_GetPointerInfo_thread, NULL, 0, NULL ); diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index b8939646668..698292c2fbf 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -632,18 +632,18 @@ @ stdcall GetPointerDeviceProperties(ptr ptr ptr) @ stdcall GetPointerDeviceRects(ptr ptr ptr) @ stdcall GetPointerDevices(ptr ptr) -# @ stub GetPointerFrameInfo -# @ stub GetPointerFrameInfoHistory -# @ stub GetPointerFramePenInfo -# @ stub GetPointerFramePenInfoHistory +@ stdcall GetPointerFrameInfo(long ptr ptr) +@ stdcall GetPointerFrameInfoHistory(long ptr ptr ptr) +@ stdcall GetPointerFramePenInfo(long ptr ptr) +@ stdcall GetPointerFramePenInfoHistory(long ptr ptr ptr) # @ stub GetPointerFrameTimes -# @ stub GetPointerFrameTouchInfo -# @ stub GetPointerFrameTouchInfoHistory +@ stdcall GetPointerFrameTouchInfo(long ptr ptr) +@ stdcall GetPointerFrameTouchInfoHistory(long ptr ptr ptr) @ stdcall GetPointerInfo(long ptr) -# @ stub GetPointerInfoHistory +@ stdcall GetPointerInfoHistory(long ptr ptr) # @ stub GetPointerInputTransform @ stdcall GetPointerPenInfo(long ptr) -# @ stub GetPointerPenInfoHistory +@ stdcall GetPointerPenInfoHistory(long ptr ptr) @ stdcall GetPointerTouchInfo(long ptr) @ stdcall GetPointerTouchInfoHistory(long ptr ptr) @ stdcall GetPointerType(long ptr) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 453ba810783..c1805fb8f5a 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2735,18 +2735,6 @@ BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) return ret; } -/********************************************************************** - * NtUserGetPointerInfoList (win32u.@) - */ -BOOL WINAPI NtUserGetPointerInfoList( UINT32 id, POINTER_INPUT_TYPE type, UINT_PTR unk0, UINT_PTR unk1, SIZE_T size, - UINT32 *entry_count, UINT32 *pointer_count, void *pointer_info ) -{ - FIXME( "id %#x, type %#x, unk0 %#lx, unk1 %#lx, size %#lx, entry_count %p, pointer_count %p, pointer_info %p stub!\n", - id, type, (long)unk0, (long)unk1, size, entry_count, pointer_count, pointer_info ); - RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; -} - static BOOL get_clip_cursor( RECT *rect, UINT dpi, MONITOR_DPI_TYPE type ) { struct object_lock lock = OBJECT_LOCK_INIT; @@ -3034,6 +3022,56 @@ BOOL WINAPI NtUserGetPointerType(UINT32 id, POINTER_INPUT_TYPE *type) return TRUE; } +/********************************************************************** + * NtUserGetPointerInfoList (win32u.@) + */ +BOOL WINAPI NtUserGetPointerInfoList( UINT32 id, POINTER_INPUT_TYPE type, UINT_PTR unk0, UINT_PTR unk1, SIZE_T size, + UINT32 *entry_count, UINT32 *pointer_count, void *pointer_info ) +{ + struct pointer *pointer; + size_t target_size = 0; + + TRACE( "id %d, type %#x, unk0 %#lx, unk1 %#lx, size %#lx, entry_count %p, pointer_count %p, pointer_info %p\n", + id, type, (long)unk0, (long)unk1, size, entry_count, pointer_count, pointer_info ); + + switch (type) + { + case PT_MOUSE: + case PT_PEN: target_size = sizeof(POINTER_PEN_INFO); break; + case PT_POINTER: target_size = sizeof(POINTER_INFO); break; + case PT_TOUCHPAD: + case PT_TOUCH: target_size = sizeof(POINTER_TOUCH_INFO); break; + } + + if (type == PT_MOUSE || size != target_size) + { + RtlSetLastWin32Error( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + if (!(pointer = find_pointerid( id ))) + { + TRACE( "pointer id %d not found.\n", id ); + RtlSetLastWin32Error( ERROR_NOACCESS ); + return FALSE; + } + + if (!pointer->info.pointerId) + { + TRACE( "no info on pointer id %d.\n", id ); + RtlSetLastWin32Error( ERROR_NOACCESS ); + return FALSE; + } + + if (type != PT_POINTER && type != PT_MOUSE) + FIXME( "Pointer type %#x not implemented!", type ); + + *entry_count = 1; + *pointer_count = 1; + *(POINTER_INFO *)pointer_info = pointer->info; + return TRUE; +} + /********************************************************************** * NtUserGetPointerDeviceRects (win32u.@) */ diff --git a/dlls/win32u/tests/win32u.c b/dlls/win32u/tests/win32u.c index 19c05a97835..3c099454a7f 100644 --- a/dlls/win32u/tests/win32u.c +++ b/dlls/win32u/tests/win32u.c @@ -1807,9 +1807,13 @@ static DWORD CALLBACK test_NtUserGetPointerInfoList_thread( void *arg ) memset( &pointer_info, 0xcd, sizeof(pointer_info) ); entry_count = pointer_count = 2; ret = NtUserGetPointerInfoList( 1, PT_POINTER, 0, 0, sizeof(POINTER_INFO), &entry_count, &pointer_count, pointer_info ); + todo_wine ok( !ret, "NtUserGetPointerInfoList succeeded\n" ); + todo_wine ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + todo_wine ok( pointer_count == 2, "got pointer_count %u\n", pointer_count ); + todo_wine ok( entry_count == 2, "got entry_count %u\n", entry_count ); DestroyWindow( hwnd ); @@ -1869,17 +1873,14 @@ static void test_NtUserGetPointerInfoList( BOOL mouse_in_pointer_enabled ) entry_count = pointer_count = 2; ret = NtUserGetPointerInfoList( 1, PT_POINTER, 0, 0, sizeof(POINTER_INFO), invalid_ptr, &pointer_count, pointer_info ); ok( !ret, "NtUserGetPointerInfoList succeeded\n" ); - todo_wine ok( GetLastError() == ERROR_NOACCESS, "got error %lu\n", GetLastError() ); entry_count = pointer_count = 2; ret = NtUserGetPointerInfoList( 1, PT_POINTER, 0, 0, sizeof(POINTER_INFO), &entry_count, invalid_ptr, pointer_info ); ok( !ret, "NtUserGetPointerInfoList succeeded\n" ); - todo_wine ok( GetLastError() == ERROR_NOACCESS, "got error %lu\n", GetLastError() ); entry_count = pointer_count = 2; ret = NtUserGetPointerInfoList( 1, PT_POINTER, 0, 0, sizeof(POINTER_INFO), &entry_count, &pointer_count, invalid_ptr ); ok( !ret, "NtUserGetPointerInfoList succeeded\n" ); - todo_wine ok( GetLastError() == ERROR_NOACCESS || broken(GetLastError() == ERROR_INVALID_PARAMETER) /* w10 32bit */, "got error %lu\n", GetLastError() ); memset( pointer_info, 0xcd, sizeof(pointer_info) ); @@ -1918,7 +1919,6 @@ static void test_NtUserGetPointerInfoList( BOOL mouse_in_pointer_enabled ) memset( pointer_info, 0xcd, sizeof(pointer_info) ); entry_count = pointer_count = 2; ret = NtUserGetPointerInfoList( 1, PT_POINTER, 0, 0, sizeof(POINTER_INFO), &entry_count, &pointer_count, pointer_info ); - todo_wine_if(mouse_in_pointer_enabled) ok( ret == mouse_in_pointer_enabled, "NtUserGetPointerInfoList failed, error %lu\n", GetLastError() ); if (!ret) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10649
On Tue Apr 14 17:20:11 2026 +0000, navi wrote:
compound literals were introduced in c99 at the same time as designated initializers (`POINT var = { .x = foo, .y = nya };`), no compiler should have one without the other, and we seem to use the initializer i can change this to a explicit variable + initializer + return, if preferred, but w.r.t. to portability it shouldn't matter unless we support c89-only compilers (to which case designated initializers are also an issue) That's not how it works, cf. the explanation under https://gitlab.winehq.org/wine/wine/-/wikis/Wine-Developer's-Guide/Coding-Practice#writing-portable-code. Whether feature X was standardized at the same time as feature Y is irrelevant, it doesn't tell us anything about what features are available in what version of what compiler.
The only thing that matters is whether it works with all the compilers that people are using to build Wine. Designated initializers work everywhere (more or less, cf. 26cac37309dbd31a39fc84c9996da205024f71ad for a recent example). Compound literals used to be more problematic, but they may be OK nowadays. We can put them in and see what happens, but note that if someone reports that it broke their build, they will have to be taken out, no matter what C99 says. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10649#note_136151
On Tue Apr 14 19:17:06 2026 +0000, Alexandre Julliard wrote:
That's not how it works, cf. the explanation under https://gitlab.winehq.org/wine/wine/-/wikis/Wine-Developer's-Guide/Coding-Practice#writing-portable-code. Whether feature X was standardized at the same time as feature Y is irrelevant, it doesn't tell us anything about what features are available in what version of what compiler. The only thing that matters is whether it works with all the compilers that people are using to build Wine. Designated initializers work everywhere (more or less, cf. 26cac37309dbd31a39fc84c9996da205024f71ad for a recent example). Compound literals used to be more problematic, but they may be OK nowadays. We can put them in and see what happens, but note that if someone reports that it broke their build, they will have to be taken out, no matter what C99 says. FWIW, according to a regex grep, there are two uses in vkd3d that have been imported into Wine. I don't see any other uses in the codebase.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10649#note_136153
On Tue Apr 14 19:25:10 2026 +0000, Elizabeth Figura wrote:
FWIW, according to a regex grep, there are two uses in vkd3d that have been imported into Wine. I don't see any other uses in the codebase. it does tell that a compiler announcing c99 must have both, however, fair enough for compilers that don't, and used to have features as an extension, or that have the feature broken
the use of literals here and in input.c:3095 have no nesting nor fancy features, so i expect them to work on all compilers that have designated initializers -- i personally would prefer to keep them if no one has build issues, but it's not a strong preference by any means -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10649#note_136155
I don't see any other uses in the codebase.
i also get a hit on: dlls/riched20/tests/txtsrv.c:1416: host_impl->client_rect = (RECT) { 0, 0, 150, 150 }; but that's a test, so idk how many people in the wild actually end up building that -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10649#note_136158
On Tue Apr 14 19:54:38 2026 +0000, navi wrote:
I don't see any other uses in the codebase. i also get a 7 hits on vkd3d, and one hit on: dlls/riched20/tests/txtsrv.c:1416: host_impl->client_rect = (RECT) { 0, 0, 150, 150 }; but that's a test, so idk how many people in the wild actually end up building that Oh indeed, I wrote mine to only catch the designated initializers...
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10649#note_136159
On Tue Apr 14 20:03:43 2026 +0000, Elizabeth Figura wrote:
Oh indeed, I wrote mine to only catch the designated initializers... Well portability considerations aside, it's also a matter of whether adding new style patterns to the code really helps making things more readable or convenient, given that style discrepancies have a fixed toll on the reader.
In this particular case, I'm not fully convinced that it does. For instance: ``` static POINT pixel_to_himetric( POINT px ) { UINT dpi = HIMETRIC / get_system_dpi(); return (POINT) { .x = px.x * dpi, .y = px.y * dpi, }; } ``` vs: ``` static POINT pixel_to_himetric( POINT px ) { UINT dpi = HIMETRIC / get_system_dpi(); px.x *= dpi; px.y *= dpi; return px; } ``` The latter is even shorter. In addition (and it is not the case here, but we've discussed the case before), the `(<type>) { <init> }` syntax has a very unfortunate "cast-like" looking that can be confusing to any unaware reader. Also, when used to pass parameters, the lifetime of the literal is well defined but potentially full of pitfalls, like this: ``` int *foo( int *a ); /* { return a; } */ /* this is fine: */ int bar(void) { return *foo( (int []) { 1 } ); } /* this is bad, there's a warning only if compiler can figure what foo does: */ int *baz(void) { return foo( (int []) { 1 } ); } int bad(void) { return *baz(); } ``` -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10649#note_136256
Rémi Bernon (@rbernon) commented about dlls/win32u/input.c:
WINE_DEFAULT_DEBUG_CHANNEL(win); WINE_DECLARE_DEBUG_CHANNEL(keyboard);
+#define HIMETRIC 2540 Where does that value come from?
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10649#note_136260
Rémi Bernon (@rbernon) commented about dlls/win32u/input.c:
+ return FALSE; + } + + monitor = get_virtual_screen_rect( dpi, MDT_DEFAULT ); + + dpi = HIMETRIC / dpi; + *pointerDeviceRect = (RECT) { + .left = monitor.left * dpi, + .top = monitor.top * dpi, + .right = monitor.right * dpi, + .bottom = monitor.bottom * dpi, + }; + *displayRect = monitor; + + return TRUE; +} We'll need some tests for that.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10649#note_136261
Rémi Bernon (@rbernon) commented about dlls/user32/input.c:
BOOL WINAPI GetPointerDeviceRects( HANDLE device, RECT *device_rect, RECT *display_rect ) { - FIXME( "device %p, device_rect %p, display_rect %p stub!\n", - device, device_rect, display_rect ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + TRACE( "device %p, device_rect %p, display_rect %p\n", device, device_rect, display_rect ); + return NtUserGetPointerDeviceRects( device, device_rect, display_rect ); }
If this is a direct 1-1 call to the syscall we don't need a user32 function and it should just be forwarded in user32.spec. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10649#note_136262
Rémi Bernon (@rbernon) commented about dlls/win32u/input.c:
+{ + UINT dpi = get_system_dpi(); + RECT monitor; + + TRACE( "%p, %p, %p\n", handle, pointerDeviceRect, displayRect ); + + if (handle != INVALID_HANDLE_VALUE) + { + FIXME( "Pointer devices are not implemented!\n" ); + RtlSetLastWin32Error( ERROR_NO_DATA ); + return FALSE; + } + + monitor = get_virtual_screen_rect( dpi, MDT_DEFAULT ); + + dpi = HIMETRIC / dpi; That'll probably cause rounding errors, you can / should use map_dpi_rect instead. Also it might be better to use `get_thread_dpi()`, or pass the desired target DPI to `get_virtual_screen_rect`, and/or use `MDR_RAW_DPI`, instead of `get_system_dpi()`, to avoid unnecessary conversion. But tests could say otherwise.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10649#note_136263
Rémi Bernon (@rbernon) commented about dlls/win32u/input.c:
+}; + +static struct pointer *find_pointerid(UINT32 id) +{ + struct pointer_thread_data *thread_data = get_pointer_thread_data(); + struct pointer *pointer; + + TRACE( "looking for pointer id %d\n", id ); + + LIST_FOR_EACH_ENTRY(pointer, &thread_data->known_pointers, struct pointer, entry) + if (pointer->id == id) + return pointer; + + TRACE( "allocating pointer id %d\n", id ); + + if (!thread_data || !(pointer = calloc( 1, sizeof(*pointer) ))) You have used thread_data before this check already, it's pointless to check it here. I'm also not sure we need to care about thread data allocation failure, it's extremely unlikely.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10649#note_136264
Rémi Bernon (@rbernon) commented about dlls/win32u/input.c:
+ + pointer->id = id; + list_add_tail( &thread_data->known_pointers, &pointer->entry ); + + return pointer; +} + +static POINT pixel_to_himetric( POINT px ) +{ + UINT dpi = HIMETRIC / get_system_dpi(); + + return (POINT) { + .x = px.x * dpi, + .y = px.y * dpi, + }; +} Same here, you will have rounding errors. Might be better to use map_dpi_point. Also I think the message location is in thread DPI when calling this, not system DPI. Note that this might even be incorrect, and maybe it would be better to convert from raw physical to HIMETRIC, which tests can tell, but there's also then physical to virtual monitor rect mapping to consider.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10649#note_136265
On Wed Apr 15 09:57:37 2026 +0000, Rémi Bernon wrote:
Where does that value come from? "himetric" is defined as "1/100th of a milimeter", since dpis are per inch, 1 inch makes 25.4mm, mm * 100 / dpi to get himetric-units-per-dot
note that we have the same definition in two other places already: ``` dlls/gdiplus/gdiplus_private.h:#define INCH_HIMETRIC (2540) dlls/ole32/ole32_main.c:#define HIMETRIC_INCHES 2540 dlls/win32u/input.c:#define HIMETRIC 2540 ``` so it might be good to just merge them all in a header (unsure which) -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10649#note_136332
On Wed Apr 15 09:57:37 2026 +0000, Rémi Bernon wrote:
You have used thread_data before this check already, it's pointless to check it here. I'm also not sure we need to care about thread data allocation failure, it's extremely unlikely. the check was meant go above, rebase mistake as it was added after the fact
i wasn't super sure if malloc fail checks were needed but saw them elsewhere in win32u and decided better safe than sorry -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10649#note_136333
participants (5)
-
Alexandre Julliard (@julliard) -
Anna (navi) Figueiredo Gomes -
Elizabeth Figura (@zfigura) -
navi (@navi) -
Rémi Bernon (@rbernon)