From: "Anna (navi) Figueiredo Gomes" <navi@vlhl.dev> --- dlls/win32u/input.c | 106 +++++++++++++++++++++++++++++++++++ dlls/win32u/ntuser_private.h | 1 + dlls/win32u/syscall.c | 1 + 3 files changed, 108 insertions(+) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index b7ba0d94fbc..a52347a1e36 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -407,6 +407,14 @@ 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; +}; BOOL grab_pointer = TRUE; BOOL grab_fullscreen = FALSE; @@ -2870,6 +2878,95 @@ INT WINAPI NtUserScheduleDispatchNotification( HWND hwnd ) return 0; } +static struct pointer *allocate_pointerid( UINT32 id ) +{ + struct user_thread_info *thread_info = get_user_thread_info(); + struct pointer *pointer; + + TRACE( "allocating pointer id %d\n", id ); + + if (!(pointer = calloc( 1, sizeof(*pointer) ))) + return NULL; + + pointer->id = id; + list_add_tail( &thread_info->known_pointers, &pointer->entry ); + + return pointer; +} + +static struct pointer *find_pointerid( UINT32 id ) +{ + struct user_thread_info *thread_info = get_user_thread_info(); + struct pointer *pointer; + + TRACE( "looking for pointer id %d\n", id ); + + LIST_FOR_EACH_ENTRY(pointer, &thread_info->known_pointers, struct pointer, entry) + if (pointer->id == id) + return pointer; + + return NULL; +} + +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 }, + }; + 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; +} + /*********************************************************************** * process_pointer_message * @@ -2877,7 +2974,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..26125e185b1 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 list known_pointers; /* list of known pointers */ }; extern struct user_thread_info *get_user_thread_info(void); diff --git a/dlls/win32u/syscall.c b/dlls/win32u/syscall.c index e9f36bdd32b..ca1be7227ca 100644 --- a/dlls/win32u/syscall.c +++ b/dlls/win32u/syscall.c @@ -197,6 +197,7 @@ struct user_thread_info *get_user_thread_info(void) info = calloc( 1, sizeof(*info) ); pthread_setspecific( user_thread_info_key, info ); + list_init( &info->known_pointers ); if (teb) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11171