[PATCH v3 0/5] MR11171: win32u: Implement GetPointerType
2/3 split from !10649 -- v3: win32u: Implement NtUserGetPointerType. win32u: Keep track of pointer types. win32u: Preallocate pointerId 1 for the mouse pointer. win32u: Keep per-thread list of known pointers. https://gitlab.winehq.org/wine/wine/-/merge_requests/11171
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 048950345b3..b7ba0d94fbc 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2870,6 +2870,17 @@ INT WINAPI NtUserScheduleDispatchNotification( HWND hwnd ) return 0; } +/*********************************************************************** + * process_pointer_message + * + * 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; +} + /********************************************************************** * NtUserInitializeTouchInjection (win32u.@) */ diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index b6cdd3efa0e..2880895f77a 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2474,17 +2474,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 620d848488d..f438e0cfff8 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -111,6 +111,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/11171
From: "Anna (navi) Figueiredo Gomes" <navi@vlhl.dev> --- dlls/win32u/input.c | 121 +++++++++++++++++++++++++++++++++++ dlls/win32u/ntuser_private.h | 1 + 2 files changed, 122 insertions(+) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index b7ba0d94fbc..6dcc5c6e40d 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; @@ -2870,6 +2883,105 @@ 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 ); + + if (!thread_data) + return NULL; + + LIST_FOR_EACH_ENTRY(pointer, &thread_data->known_pointers, struct pointer, entry) + if (pointer->id == id) + return pointer; + + return NULL; +} + +static struct pointer *allocate_pointerid( UINT32 id ) +{ + struct pointer_thread_data *thread_data = get_pointer_thread_data(); + struct pointer *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 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, + }; + UINT ctx; + + 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; + + ctx = set_thread_dpi_awareness_context( NTUSER_DPI_PER_MONITOR_AWARE ); + info.ptHimetricLocation.x = location.x * HIMETRIC_PER_INCH / get_system_dpi(); + info.ptHimetricLocation.y = location.y * HIMETRIC_PER_INCH / get_system_dpi(); + info.ptHimetricLocationRaw = info.ptHimetricLocation; + set_thread_dpi_awareness_context(ctx); + + 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 * @@ -2877,7 +2989,16 @@ INT WINAPI NtUserScheduleDispatchNotification( HWND hwnd ) */ BOOL process_pointer_message( MSG *msg, UINT hw_id, const struct hardware_msg_data *msg_data ) { + UINT 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( id )) && !(pointer = allocate_pointerid( id ))) + 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 978700a37aa..fba089c21c9 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -127,6 +127,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 */ }; extern struct user_thread_info *get_user_thread_info(void); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11171
From: "Anna (navi) Figueiredo Gomes" <navi@vlhl.dev> Seems like pointerId 1 is always the mouse, regardless of EnableMouseInPointer. --- dlls/win32u/input.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 6dcc5c6e40d..7c7678766c3 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2883,11 +2883,16 @@ 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; }; @@ -2908,6 +2913,7 @@ static struct pointer *find_pointerid( UINT32 id ) return NULL; } + static struct pointer *allocate_pointerid( UINT32 id ) { struct pointer_thread_data *thread_data = get_pointer_thread_data(); @@ -2917,13 +2923,11 @@ static struct pointer *allocate_pointerid( UINT32 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 POINTER_INFO pointer_info_from_msg( const MSG *msg ) { POINT location = { LOWORD( msg->lParam ), HIWORD( msg->lParam ) }; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11171
From: "Anna (navi) Figueiredo Gomes" <navi@vlhl.dev> --- dlls/win32u/input.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 7c7678766c3..a56b4f15721 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; }; @@ -2883,7 +2884,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) { @@ -2891,7 +2892,7 @@ 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; }; @@ -2914,20 +2915,22 @@ static struct pointer *find_pointerid( UINT32 id ) } -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 POINTER_INFO pointer_info_from_msg( const MSG *msg ) { POINT location = { LOWORD( msg->lParam ), HIWORD( msg->lParam ) }; @@ -2986,6 +2989,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: return PT_TOUCH; + case IMDT_TOUCHPAD: return PT_TOUCHPAD; + default: return PT_POINTER; + } +} + /*********************************************************************** * process_pointer_message * @@ -2993,16 +3008,18 @@ static POINTER_BUTTON_CHANGE_TYPE compare_button( const POINTER_INFO *old, const */ BOOL process_pointer_message( MSG *msg, UINT hw_id, const struct hardware_msg_data *msg_data ) { + POINTER_INPUT_TYPE type = pointer_type_from_hw( &msg_data->source ); UINT 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( id )) && !(pointer = allocate_pointerid( id ))) + if (!(pointer = find_pointerid( id )) && !(pointer = allocate_pointerid( id, type ))) 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/11171
From: "Anna (navi) Figueiredo Gomes" <navi@vlhl.dev> --- dlls/dinput/tests/device8.c | 22 ++++++++++++++++++++++ dlls/user32/misc.c | 17 ----------------- dlls/user32/tests/input.c | 2 -- dlls/user32/user32.spec | 2 +- dlls/win32u/input.c | 15 ++++++++++++--- 5 files changed, 35 insertions(+), 23 deletions(-) diff --git a/dlls/dinput/tests/device8.c b/dlls/dinput/tests/device8.c index 37ed9428561..c2fefe37abe 100644 --- a/dlls/dinput/tests/device8.c +++ b/dlls/dinput/tests/device8.c @@ -1937,6 +1937,7 @@ static void test_hid_touch_screen(void) RAWINPUTDEVICE rawdevice = {.usUsagePage = HID_USAGE_PAGE_DIGITIZER, .usUsage = HID_USAGE_DIGITIZER_TOUCH_SCREEN}; UINT rawbuffer_count, rawbuffer_size, expect_flags, id, width, height; WCHAR device_path[MAX_PATH]; + POINTER_INPUT_TYPE type; char rawbuffer[1024]; RAWINPUT *rawinput; HANDLE file; @@ -2022,6 +2023,9 @@ static void test_hid_touch_screen(void) todo_wine /* missing POINTER_MESSAGE_FLAG_FIRSTBUTTON */ ok( HIWORD( pointer_wparam[0] ) == expect_flags, "got wparam %#Ix\n", pointer_wparam[0] ); ok( LOWORD( pointer_wparam[0] ) > 0, "got wparam %#Ix\n", pointer_wparam[0] ); + ret = GetPointerType( LOWORD( pointer_wparam[0] ), &type ); + ok( ret, "GetPointerType failed, error %lu\n", GetLastError() ); + ok( type == PT_TOUCH, "got pointer type %#lx\n", type ); ok( LOWORD( pointer_lparam[0] ) * 128 / width == 0x08, "got lparam %#Ix\n", pointer_lparam[0] ); ok( HIWORD( pointer_lparam[0] ) * 128 / height == 0x10, "got lparam %#Ix\n", pointer_lparam[0] ); id = LOWORD( pointer_wparam[0] ); @@ -2165,6 +2169,9 @@ static void test_hid_touch_screen(void) todo_wine /* missing POINTER_MESSAGE_FLAG_FIRSTBUTTON */ ok( HIWORD( pointer_wparam[0] ) == expect_flags, "got wparam %#Ix\n", pointer_wparam[0] ); ok( LOWORD( pointer_wparam[0] ) > 0, "got wparam %#Ix\n", pointer_wparam[0] ); + ret = GetPointerType( LOWORD( pointer_wparam[0] ), &type ); + ok( ret, "GetPointerType failed, error %lu\n", GetLastError() ); + ok( type == PT_TOUCH, "got pointer type %#lx\n", type ); ok( LOWORD( pointer_lparam[0] ) * 128 / width == 0x08, "got lparam %#Ix\n", pointer_lparam[0] ); ok( HIWORD( pointer_lparam[0] ) * 128 / height == 0x10, "got lparam %#Ix\n", pointer_lparam[0] ); ok( pointer_wparam[1] == 0, "got wparam %#Ix\n", pointer_wparam[1] ); @@ -2189,6 +2196,9 @@ static void test_hid_touch_screen(void) broken(HIWORD( pointer_wparam[0] ) == (expect_flags & ~POINTER_MESSAGE_FLAG_CONFIDENCE)), /* Win8 32bit */ "got wparam %#Ix\n", pointer_wparam[0] ); ok( LOWORD( pointer_wparam[0] ) == id, "got wparam %#Ix\n", pointer_wparam[0] ); + ret = GetPointerType( LOWORD( pointer_wparam[0] ), &type ); + ok( ret, "GetPointerType failed, error %lu\n", GetLastError() ); + ok( type == PT_TOUCH, "got pointer type %#lx\n", type ); ok( LOWORD( pointer_lparam[0] ) * 128 / width == 0x08, "got lparam %#Ix\n", pointer_lparam[0] ); ok( HIWORD( pointer_lparam[0] ) * 128 / height == 0x10, "got lparam %#Ix\n", pointer_lparam[0] ); ok( pointer_wparam[1] == 0, "got wparam %#Ix\n", pointer_wparam[1] ); @@ -2215,6 +2225,9 @@ static void test_hid_touch_screen(void) todo_wine /* missing POINTER_MESSAGE_FLAG_FIRSTBUTTON */ ok( HIWORD( pointer_wparam[0] ) == expect_flags, "got wparam %#Ix\n", pointer_wparam[0] ); ok( LOWORD( pointer_wparam[0] ) > 0, "got wparam %#Ix\n", pointer_wparam[0] ); + ret = GetPointerType( LOWORD( pointer_wparam[0] ), &type ); + ok( ret, "GetPointerType failed, error %lu\n", GetLastError() ); + ok( type == PT_TOUCH, "got pointer type %#lx\n", type ); ok( LOWORD( pointer_lparam[0] ) * 128 / width == 0x08, "got lparam %#Ix\n", pointer_lparam[0] ); ok( HIWORD( pointer_lparam[0] ) * 128 / height == 0x10, "got lparam %#Ix\n", pointer_lparam[0] ); id = LOWORD( pointer_wparam[0] ); @@ -2226,6 +2239,9 @@ static void test_hid_touch_screen(void) broken(HIWORD( pointer_wparam[1] ) == (expect_flags & ~POINTER_MESSAGE_FLAG_CONFIDENCE)), /* Win8 32bit */ "got wparam %#Ix\n", pointer_wparam[1] ); ok( LOWORD( pointer_wparam[1] ) == id + 1, "got wparam %#Ix\n", pointer_wparam[1] ); + ret = GetPointerType( LOWORD( pointer_wparam[1] ), &type ); + ok( ret, "GetPointerType failed, error %lu\n", GetLastError() ); + ok( type == PT_TOUCH, "got pointer type %#lx\n", type ); ok( LOWORD( pointer_lparam[1] ) * 128 / width == 0x18, "got lparam %#Ix\n", pointer_lparam[1] ); ok( HIWORD( pointer_lparam[1] ) * 128 / height == 0x20, "got lparam %#Ix\n", pointer_lparam[1] ); @@ -2249,6 +2265,9 @@ static void test_hid_touch_screen(void) broken(HIWORD( pointer_wparam[0] ) == (expect_flags & ~POINTER_MESSAGE_FLAG_CONFIDENCE)), /* Win8 32bit */ "got wparam %#Ix\n", pointer_wparam[0] ); ok( LOWORD( pointer_wparam[0] ) == id, "got wparam %#Ix\n", pointer_wparam[0] ); + ret = GetPointerType( LOWORD( pointer_wparam[0] ), &type ); + ok( ret, "GetPointerType failed, error %lu\n", GetLastError() ); + ok( type == PT_TOUCH, "got pointer type %#lx\n", type ); ok( LOWORD( pointer_lparam[0] ) * 128 / width == 0x08, "got lparam %#Ix\n", pointer_lparam[0] ); ok( HIWORD( pointer_lparam[0] ) * 128 / height == 0x10, "got lparam %#Ix\n", pointer_lparam[0] ); @@ -2257,6 +2276,9 @@ static void test_hid_touch_screen(void) broken(HIWORD( pointer_wparam[1] ) == (expect_flags & ~POINTER_MESSAGE_FLAG_CONFIDENCE)), /* Win8 32bit */ "got wparam %#Ix\n", pointer_wparam[1] ); ok( LOWORD( pointer_wparam[1] ) == id + 1, "got wparam %#Ix\n", pointer_wparam[1] ); + ret = GetPointerType( LOWORD( pointer_wparam[1] ), &type ); + ok( ret, "GetPointerType failed, error %lu\n", GetLastError() ); + ok( type == PT_TOUCH, "got pointer type %#lx\n", type ); ok( LOWORD( pointer_lparam[1] ) * 128 / width == 0x18, "got lparam %#Ix\n", pointer_lparam[1] ); ok( HIWORD( pointer_lparam[1] ) * 128 / height == 0x20, "got lparam %#Ix\n", pointer_lparam[1] ); diff --git a/dlls/user32/misc.c b/dlls/user32/misc.c index 6333fcb48b4..622325f7ad0 100644 --- a/dlls/user32/misc.c +++ b/dlls/user32/misc.c @@ -507,23 +507,6 @@ LRESULT WINAPI PackTouchHitTestingProximityEvaluation(const TOUCH_HIT_TESTING_IN return 0; } -/********************************************************************** - * GetPointerType [USER32.@] - */ -BOOL WINAPI GetPointerType(UINT32 id, POINTER_INPUT_TYPE *type) -{ - FIXME("(%d %p): stub\n", id, type); - - if(!id || !type) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - *type = PT_MOUSE; - return TRUE; -} - BOOL WINAPI GetPointerInfo(UINT32 id, POINTER_INFO *info) { FIXME("(%d %p): stub\n", id, info); diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 6ad01e82978..f3afb09c21b 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -5627,9 +5627,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/user32/user32.spec b/dlls/user32/user32.spec index 93ced8d8f3d..afe4a06b2f8 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -646,7 +646,7 @@ # @ stub GetPointerPenInfoHistory @ stdcall GetPointerTouchInfo(long ptr) @ stdcall GetPointerTouchInfoHistory(long ptr ptr) -@ stdcall GetPointerType(long ptr) +@ stdcall GetPointerType(long ptr) NtUserGetPointerType @ stdcall GetPriorityClipboardFormat(ptr long) NtUserGetPriorityClipboardFormat @ stdcall GetProcessDefaultLayout(ptr) @ stdcall GetProcessDpiAwarenessInternal(long ptr) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index a56b4f15721..414ec0bd752 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -3037,9 +3037,18 @@ BOOL WINAPI NtUserInitializeTouchInjection( UINT max_count, UINT mode ) */ BOOL WINAPI NtUserGetPointerType( UINT32 id, POINTER_INPUT_TYPE *type ) { - FIXME( "id %u, type %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/11171
Rémi Bernon (@rbernon) commented about dlls/win32u/ntuser_private.h:
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 */
I'd keep a `struct list` here directly. I think it'd make things simpler and save various NULL checks. It can be initialized in `get_user_thread_info`. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11171#note_143578
Rémi Bernon (@rbernon) commented about dlls/win32u/ntuser_private.h:
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 */
The pointer list is also leaked on thread detach. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11171#note_143579
Rémi Bernon (@rbernon) commented about dlls/win32u/input.c:
+ 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; How about:
```suggestion:-7+0 }; POINTER_FLAGS down = ~old->pointerFlags & new->pointerFlags, up = old->pointerFlags & ~new->pointerFlags; for (size_t i = 0; i < ARRAY_SIZE(map); i++) { if (down & map[i].flag) change |= map[i].down; if (up & map[i].flag) change |= map[i].up; } return change; ``` -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11171#note_143580
Rémi Bernon (@rbernon) commented about dlls/win32u/input.c:
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 );
As mouse messages don't go through process_pointer_message, is it really useful to have a pointer struct for it to look it up? Could it just be hardcoded in GetPointerType instead? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11171#note_143585
On Fri Jun 19 07:55:24 2026 +0000, Rémi Bernon wrote:
As mouse messages don't go through process_pointer_message, is it really useful to have a pointer struct for it to look it up? Could it just be hardcoded in GetPointerType instead? I mean, it's probably fine either way, my comment is actually more related to the other comment where I suggested to use a list directly in user thread info, which would make this mouse pointer allocation a bit out of place. But I suppose it also be done lazily, or with a static struct pointer returned from find_pointerid if id is 1.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/11171#note_143586
On Fri Jun 19 07:57:40 2026 +0000, Rémi Bernon wrote:
I mean, it's probably fine either way, my comment is actually more related to the other comment where I suggested to use a list directly in user thread info, which would make this mouse pointer allocation a bit out of place. But I suppose it also be done lazily, or with a static struct pointer returned from find_pointerid if id is 1. next set of patches will fill in the pointer struct as we get mouse messages (for GetPointerInfo w/ MouseInPointer)
a static pointerid would need to be per-thread i think, since pointer info is per-thread, though i suppose it can go directly into user_thread_info? alongside the `struct list` -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11171#note_143631
On Fri Jun 19 13:37:54 2026 +0000, navi wrote:
next set of patches will fill in the pointer struct as we get mouse messages (for GetPointerInfo w/ MouseInPointer) a static pointerid would need to be per-thread i think, since pointer info is per-thread, though i suppose it can go directly into user_thread_info? alongside the `struct list` Well in that case it's probably better to have a `struct pointer` for it too, it could just be allocated as needed when ID 1 is requested.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/11171#note_143632
participants (3)
-
Anna (navi) Figueiredo Gomes -
navi (@navi) -
Rémi Bernon (@rbernon)