[PATCH 0/9] MR11693: Draft: plumbing, fixups, and tests for pen input
From: navi <navi@vlhl.dev> --- include/winuser.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/winuser.h b/include/winuser.h index 32b07b387a1..fe3d4dee5d4 100644 --- a/include/winuser.h +++ b/include/winuser.h @@ -3799,6 +3799,7 @@ typedef struct tagPOINTER_TYPE_INFO POINTER_INPUT_TYPE type; union { + POINTER_INFO pointerInfo; POINTER_TOUCH_INFO touchInfo; POINTER_PEN_INFO penInfo; } DUMMYUNIONNAME; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11693
From: navi <navi@vlhl.dev> Pointer input will require sending more info than it's possible to infer from wparam and lparam, additionally those two can be taken from the full pointer structure. Since this would lead the pointer messages to ignore most of hw_input.hw, split it into a new request. --- dlls/mouhid.sys/main.c | 28 ++++++------ dlls/win32u/input.c | 57 +++++++++++++++++++------ dlls/win32u/message.c | 3 ++ dlls/win32u/win32u_private.h | 1 + dlls/winex11.drv/mouse.c | 27 ++++++------ dlls/wow64win/user.c | 1 + include/ntuser.h | 1 + server/protocol.def | 5 +++ server/queue.c | 82 ++++++++++++++++++++++++------------ 9 files changed, 140 insertions(+), 65 deletions(-) diff --git a/dlls/mouhid.sys/main.c b/dlls/mouhid.sys/main.c index 0e325cd29c4..23642c53554 100644 --- a/dlls/mouhid.sys/main.c +++ b/dlls/mouhid.sys/main.c @@ -112,8 +112,9 @@ static NTSTATUS start_device_read( DEVICE_OBJECT *device ) static void add_contact( struct device *impl, struct list *old_contacts, ULONG id, LONG x, LONG y ) { - UINT flags = POINTER_MESSAGE_FLAG_INRANGE | POINTER_MESSAGE_FLAG_INCONTACT | POINTER_MESSAGE_FLAG_CONFIDENCE; - INPUT input = {.type = INPUT_HARDWARE}; + UINT msg, flags = POINTER_MESSAGE_FLAG_INRANGE | POINTER_MESSAGE_FLAG_INCONTACT | POINTER_MESSAGE_FLAG_CONFIDENCE; + POINTER_TYPE_INFO pointer = { .type = PT_TOUCH }; + POINTER_INFO *info = &pointer.pointerInfo; struct contact *contact; LIST_FOR_EACH_ENTRY( contact, old_contacts, struct contact, entry ) @@ -121,7 +122,7 @@ static void add_contact( struct device *impl, struct list *old_contacts, ULONG i if (&contact->entry != old_contacts) { - input.hi.uMsg = WM_POINTERUPDATE; + msg = WM_POINTERUPDATE; list_remove( &contact->entry ); contact->pos.x = x; @@ -130,7 +131,7 @@ static void add_contact( struct device *impl, struct list *old_contacts, ULONG i } else if ((contact = calloc( 1, sizeof(*contact) ))) { - input.hi.uMsg = WM_POINTERDOWN; + msg = WM_POINTERDOWN; flags |= POINTER_MESSAGE_FLAG_NEW; contact->id = id; @@ -144,9 +145,10 @@ static void add_contact( struct device *impl, struct list *old_contacts, ULONG i return; } - input.hi.wParamL = contact->id; - input.hi.wParamH = flags; - NtUserSendHardwareInput( 0, 0, &input, MAKELPARAM(contact->pos.x, contact->pos.y) ); + info->pointerId = contact->id; + info->pointerFlags = flags; + info->ptPixelLocation = contact->pos; + NtUserMessageCall(0, msg, 0, 0, &pointer, NtUserInjectPointer, FALSE); list_add_tail( &impl->contacts, &contact->entry ); } @@ -157,15 +159,17 @@ static void release_contacts( struct list *contacts ) LIST_FOR_EACH_ENTRY_SAFE( contact, next, contacts, struct contact, entry ) { - INPUT input = {.type = INPUT_HARDWARE}; + POINTER_TYPE_INFO pointer = { .type = PT_TOUCH }; ULONG flags = POINTER_MESSAGE_FLAG_CONFIDENCE; + POINTER_INFO *info = &pointer.pointerInfo; TRACE( "releasing contact %#lx, pos %s\n", contact->id, wine_dbgstr_point( &contact->pos ) ); - input.hi.uMsg = WM_POINTERUP; - input.hi.wParamL = contact->id; - input.hi.wParamH = flags; - NtUserSendHardwareInput( 0, 0, &input, MAKELPARAM(contact->pos.x, contact->pos.y) ); + info->pointerId = contact->id; + info->pointerFlags = flags; + info->ptPixelLocation = contact->pos; + + NtUserMessageCall(0, WM_POINTERUP, 0, 0, &pointer, NtUserInjectPointer, FALSE); list_remove( &contact->entry ); free( contact ); diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index a3f345b6d7c..3b9d5e05db7 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -415,8 +415,7 @@ struct pointer { UINT32 id; struct list entry; - POINTER_INPUT_TYPE type; - POINTER_INFO info; + POINTER_TYPE_INFO info; }; BOOL grab_pointer = TRUE; @@ -2964,7 +2963,7 @@ static struct pointer *pointer_create( UINT32 id, POINTER_INPUT_TYPE type ) if (!(pointer = calloc( 1, sizeof(*pointer) ))) return NULL; pointer->id = id; - pointer->type = type; + pointer->info.type = type; list_add_tail( &thread_info->known_pointers, &pointer->entry ); return pointer; @@ -3042,20 +3041,49 @@ static POINTER_BUTTON_CHANGE_TYPE compare_button( const POINTER_INFO *old, const return change; } -void update_pointer_from_msg( POINTER_INPUT_TYPE type, const MSG *msg ) +static void update_pointer( const POINTER_TYPE_INFO *pointer_info ) { - POINTER_INFO info = pointer_info_from_msg( msg ); - POINTER_BUTTON_CHANGE_TYPE buttons; + POINTER_INFO info = pointer_info->pointerInfo; + POINTER_INPUT_TYPE type = pointer_info->type; struct pointer *pointer; TRACE( "updating pointer id %d.\n", info.pointerId ); if (!(pointer = find_pointer( info.pointerId )) && !(pointer = pointer_create( info.pointerId, type ))) return; - buttons = compare_button( &pointer->info, &info ); - pointer->info = info; - pointer->info.pointerType = pointer->type; - pointer->info.ButtonChangeType = buttons; + info.ButtonChangeType = compare_button( &pointer->info.pointerInfo, &info ); + pointer->info = *pointer_info; + pointer->info.pointerInfo = info; +} + +void update_pointer_from_msg( POINTER_INPUT_TYPE type, const MSG *msg ) +{ + POINTER_TYPE_INFO info = { .type = type, .pointerInfo = pointer_info_from_msg( msg ) }; + + update_pointer( &info ); +} + +NTSTATUS send_pointer_message( UINT msg, const POINTER_TYPE_INFO *info ) +{ + POINTER_TYPE_INFO pointer = *info; + LARGE_INTEGER counter; + NTSTATUS ret; + + TRACE( "Injecting pointer msg %#x.\n", msg ); + NtQueryPerformanceCounter( &counter, NULL ); + pointer.pointerInfo.PerformanceCount = counter.QuadPart; + pointer.pointerInfo.dwTime = NtGetTickCount(); + + SERVER_START_REQ( send_pointer_message ) + { + req->win = wine_server_user_handle( pointer.pointerInfo.hwndTarget ); + req->msg = msg; + wine_server_add_data( req, &pointer, sizeof(pointer) ); + ret = wine_server_call( req ); + } + SERVER_END_REQ; + + return ret; } static POINTER_INPUT_TYPE pointer_type_from_hw( const struct hw_msg_source *source ) @@ -3077,7 +3105,10 @@ 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 ) { - update_pointer_from_msg( pointer_type_from_hw( &msg_data->source ), msg ); + if (msg_data->size == sizeof(*msg_data) + sizeof(POINTER_TYPE_INFO)) + update_pointer((POINTER_TYPE_INFO *)(msg_data + 1)); + else + update_pointer_from_msg( pointer_type_from_hw( &msg_data->source ), msg ); msg->pt = point_phys_to_win_dpi( msg->hwnd, msg->pt ); return TRUE; } @@ -3113,7 +3144,7 @@ BOOL WINAPI NtUserGetPointerType( UINT32 id, POINTER_INPUT_TYPE *type ) return FALSE; } - *type = pointer->type; + *type = pointer->info.type; return TRUE; } @@ -3158,7 +3189,7 @@ BOOL WINAPI NtUserGetPointerInfoList( UINT32 id, POINTER_INPUT_TYPE type, UINT_P *pointer_count = 1; memset( pointer_info, 0, size ); - *(POINTER_INFO *)pointer_info = pointer->info; + *(POINTER_INFO *)pointer_info = pointer->info.pointerInfo; return TRUE; } diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 8c9a2aaef7c..e56fcf28ac7 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -4818,6 +4818,9 @@ LRESULT WINAPI NtUserMessageCall( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpa case NtUserWintabDriverCall: return user_driver->pWintabProc( hwnd, msg, wparam, lparam, result_info ); + case NtUserInjectPointer: + return send_pointer_message( msg, result_info ); + default: FIXME( "%p %x %lx %lx %p %x %x\n", hwnd, msg, (long)wparam, lparam, result_info, type, ansi ); } diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 060a446a76d..69693f98f0a 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -113,6 +113,7 @@ extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ); extern USHORT map_scan_to_kbd_vkey( USHORT scan, HKL layout, UINT *mapped ); extern void destroy_thread_pointers(void); extern BOOL process_pointer_message( MSG *msg, UINT hw_id, const struct hardware_msg_data *msg_data ); +extern NTSTATUS send_pointer_message( UINT msg, const POINTER_TYPE_INFO *info ); extern void update_pointer_from_msg( POINTER_INPUT_TYPE type, const MSG *msg ); extern NTSTATUS send_hardware_input( HWND hwnd, UINT flags, const INPUT *input, LPARAM lparam ); diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 7e4d6f9b031..346a851fead 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -1675,36 +1675,39 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) static BOOL X11DRV_TouchEvent( HWND hwnd, XGenericEventCookie *xev ) { RECT virtual = NtUserGetVirtualScreenRect( MDT_RAW_DPI ); - INPUT input = {.type = INPUT_HARDWARE}; + POINTER_TYPE_INFO pointer_info = { .type = PT_TOUCH }; + POINTER_INFO *info = &pointer_info.pointerInfo; XIDeviceEvent *event = xev->data; POINT pt = { event->event_x, event->event_y }, root = { event->root_x, event->root_y }; - int flags = 0; POINT pos; + UINT msg; pt = map_event_coords( hwnd, event->event, event->root, root, pt ); pos.x = pt.x * 65535 / (virtual.right - virtual.left); pos.y = pt.y * 65535 / (virtual.bottom - virtual.top); + info->ptPixelLocation = pos; + info->pointerId = event->detail; + info->pointerFlags = POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT; + switch (event->evtype) { case XI_TouchBegin: - input.hi.uMsg = WM_POINTERDOWN; - flags |= POINTER_MESSAGE_FLAG_NEW; - TRACE("XI_TouchBegin detail %u pos %dx%d, flags %#x\n", event->detail, pos.x, pos.y, flags); + msg = WM_POINTERDOWN; + info->pointerFlags |= POINTER_FLAG_NEW; + TRACE("XI_TouchBegin detail %u pos %dx%d, flags %#x\n", event->detail, pos.x, pos.y, info->pointerFlags); break; case XI_TouchEnd: - input.hi.uMsg = WM_POINTERUP; - TRACE("XI_TouchEnd detail %u pos %dx%d, flags %#x\n", event->detail, pos.x, pos.y, flags); + msg = WM_POINTERUP; + TRACE("XI_TouchEnd detail %u pos %dx%d, flags %#x\n", event->detail, pos.x, pos.y, info->pointerFlags); break; case XI_TouchUpdate: - input.hi.uMsg = WM_POINTERUPDATE; - TRACE("XI_TouchUpdate detail %u pos %dx%d, flags %#x\n", event->detail, pos.x, pos.y, flags); + msg = WM_POINTERUPDATE; + TRACE("XI_TouchUpdate detail %u pos %dx%d, flags %#x\n", event->detail, pos.x, pos.y, info->pointerFlags); break; } - input.hi.wParamL = event->detail; - input.hi.wParamH = POINTER_MESSAGE_FLAG_INRANGE | POINTER_MESSAGE_FLAG_INCONTACT | flags; - NtUserSendHardwareInput( hwnd, 0, &input, MAKELPARAM( pos.x, pos.y ) ); + NtUserMessageCall( hwnd, msg, 0, 0, &pointer_info, NtUserInjectPointer, FALSE ); return TRUE; } diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index 92c1877566b..4cf6b3d6dc8 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -3945,6 +3945,7 @@ NTSTATUS WINAPI wow64_NtUserMessageCall( UINT *args ) } case NtUserWintabDriverCall: + case NtUserInjectPointer: return NtUserMessageCall( hwnd, msg, wparam, lparam, result_info, type, ansi ); } diff --git a/include/ntuser.h b/include/ntuser.h index be41b33adfd..45153724d27 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -417,6 +417,7 @@ enum NtUserDragDropCall = 0x0307, NtUserPostDdeCall = 0x0308, NtUserWintabDriverCall = 0x0309, + NtUserInjectPointer = 0x030a, }; /* NtUserWintabDriverCall codes */ diff --git a/server/protocol.def b/server/protocol.def index a9be0a16eb6..63c2a9f65c8 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2435,6 +2435,11 @@ enum message_type #define SEND_HWMSG_INJECTED 0x01 /* message is injected from application */ #define SEND_HWMSG_RAWINPUT 0x02 /* don't generate WM_INPUT x / y updates */ +@REQ(send_pointer_message) + user_handle_t win; + unsigned int msg; + VARARG(data,bytes); +@END /* Get a message from the current queue */ @REQ(get_message) diff --git a/server/queue.c b/server/queue.c index 3d8ae3f96dd..26e8f301f79 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2463,18 +2463,19 @@ struct pointer struct desktop *desktop; user_handle_t win; int primary; - union hw_input input; + POINTER_TYPE_INFO info; }; -static void queue_pointer_message( struct pointer *pointer, int repeated ); +static unsigned int pointer_frame = 1; +static void queue_pointer_message( UINT message, struct pointer *pointer, int repeated ); static void pointer_message_timeout( void *private ) { struct pointer *pointer = private; - queue_pointer_message( pointer, 1 ); + queue_pointer_message( WM_POINTERUPDATE, pointer, 1 ); } -static void queue_pointer_message( struct pointer *pointer, int repeated ) +static void queue_pointer_message( UINT message, struct pointer *pointer, int repeated ) { static const unsigned int messages[][2] = { @@ -2485,30 +2486,37 @@ static void queue_pointer_message( struct pointer *pointer, int repeated ) struct hw_msg_source source = { IMDT_UNAVAILABLE, IMDT_TOUCH }; struct desktop *desktop = pointer->desktop; desktop_shm_t *desktop_shm = desktop->shared; - const union hw_input *input = &pointer->input; - unsigned int i, wparam = input->hw.wparam; + POINTER_INFO *info = &pointer->info.pointerInfo; timeout_t time = get_tick_count(); user_handle_t win = pointer->win; struct rectangle top_rect; + unsigned int i, wparam; struct message *msg; int x, y; get_virtual_screen_rect( desktop, &top_rect, 0 ); - x = LOWORD(input->hw.lparam) * (top_rect.right - top_rect.left) / 65535; - y = HIWORD(input->hw.lparam) * (top_rect.bottom - top_rect.top) / 65535; + x = info->ptPixelLocation.x * (top_rect.right - top_rect.left) / 65535; + y = info->ptPixelLocation.y * (top_rect.bottom - top_rect.top) / 65535; - if (pointer->primary) wparam |= POINTER_MESSAGE_FLAG_PRIMARY << 16; + if (pointer->primary) info->pointerFlags |= POINTER_FLAG_PRIMARY; + info->pointerType = pointer->info.type; + info->frameId = pointer_frame++; - for (i = 0; i < 2 && messages[input->hw.msg - WM_POINTERUPDATE][i]; i++) + wparam = MAKELONG(info->pointerId, info->pointerFlags); + for (i = 0; i < 2 && messages[message - WM_POINTERUPDATE][i]; i++) { - if (!(msg = alloc_hardware_message( 0, source, time, 0 ))) return; + struct hardware_msg_data *msg_data; + + if (!(msg = alloc_hardware_message( 0, source, time, sizeof(*info) ))) return; msg->win = get_user_full_handle( win ); - msg->msg = messages[input->hw.msg - WM_POINTERUPDATE][i]; + msg->msg = messages[message - WM_POINTERUPDATE][i]; msg->wparam = wparam; msg->lparam = MAKELONG(x, y); msg->x = desktop_shm->cursor.x; msg->y = desktop_shm->cursor.y; + msg_data = msg->data; + mem_append( msg_data + 1, info, sizeof(*info) ); queue_hardware_message( desktop, msg, 1 ); } @@ -2516,8 +2524,8 @@ static void queue_pointer_message( struct pointer *pointer, int repeated ) if (!repeated && pointer->primary && (msg = alloc_hardware_message( 0xff515700, source, time, 0 ))) { unsigned int message = WM_MOUSEMOVE; - if (input->hw.msg == WM_POINTERDOWN) message = WM_LBUTTONDOWN; - else if (input->hw.msg == WM_POINTERUP) message = WM_LBUTTONUP; + if (message == WM_POINTERDOWN) message = WM_LBUTTONDOWN; + else if (message == WM_POINTERUP) message = WM_LBUTTONUP; msg->win = get_user_full_handle( win ); msg->msg = message; @@ -2530,11 +2538,10 @@ static void queue_pointer_message( struct pointer *pointer, int repeated ) queue_hardware_message( desktop, msg, 0 ); } - if (input->hw.msg != WM_POINTERUP) + if (message != WM_POINTERUP) { - pointer->input.hw.msg = WM_POINTERUPDATE; - pointer->input.hw.wparam &= ~(POINTER_MESSAGE_FLAG_NEW << 16); pointer->timeout = add_timeout_user( -160000, pointer_message_timeout, pointer ); + info->pointerFlags &= ~POINTER_FLAG_NEW; } else { @@ -2548,7 +2555,7 @@ static struct pointer *find_pointer_from_id( struct desktop *desktop, unsigned i struct pointer *pointer; LIST_FOR_EACH_ENTRY( pointer, &desktop->pointers, struct pointer, entry ) - if (LOWORD(pointer->input.hw.wparam) == id) return pointer; + if (pointer->info.pointerInfo.pointerId == id) return pointer; pointer = mem_alloc( sizeof(struct pointer) ); pointer->timeout = NULL; @@ -2566,7 +2573,6 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_ desktop_shm_t *desktop_shm = desktop->shared; struct hw_msg_source source = { IMDT_UNAVAILABLE, origin }; struct thread *foreground; - struct pointer *pointer; struct message *msg; switch (input->hw.msg) @@ -2589,16 +2595,14 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_ release_object( foreground ); } return; - } - - if (input->hw.msg == WM_POINTERDOWN || input->hw.msg == WM_POINTERUP || input->hw.msg == WM_POINTERUPDATE) - { - pointer = find_pointer_from_id( desktop, LOWORD(input->hw.wparam) ); - if (pointer->timeout) remove_timeout_user( pointer->timeout ); - pointer->input = *input; - pointer->win = win; - queue_pointer_message( pointer, 0 ); + case WM_POINTERUPDATE: + case WM_POINTERDOWN: + case WM_POINTERUP: + case WM_POINTERENTER: + case WM_POINTERLEAVE: + /* should use send_pointer_message */ + set_error( STATUS_INVALID_PARAMETER ); return; } @@ -3232,6 +3236,28 @@ DECL_HANDLER(send_hardware_message) release_object( desktop ); } +DECL_HANDLER(send_pointer_message) +{ + const POINTER_TYPE_INFO *info = get_req_data(); + struct pointer *pointer; + struct desktop *desktop; + + if (!(desktop = get_hardware_input_desktop( req->win ))) return; + if (get_req_data_size() != sizeof(*info)) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + + pointer = find_pointer_from_id( desktop, LOWORD(info->pointerInfo.pointerId) ); + if (pointer->timeout) remove_timeout_user( pointer->timeout ); + pointer->info = *info; + pointer->win = req->win; + + queue_pointer_message( req->msg, pointer, 0 ); + return; +} + /* post a quit message to the current queue */ DECL_HANDLER(post_quit_message) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11693
From: navi <navi@vlhl.dev> --- dlls/mouhid.sys/main.c | 3 +++ dlls/winex11.drv/mouse.c | 14 ++++++++------ server/queue.c | 36 +++++++++++++----------------------- 3 files changed, 24 insertions(+), 29 deletions(-) diff --git a/dlls/mouhid.sys/main.c b/dlls/mouhid.sys/main.c index 23642c53554..0ed4d5c0344 100644 --- a/dlls/mouhid.sys/main.c +++ b/dlls/mouhid.sys/main.c @@ -148,6 +148,8 @@ static void add_contact( struct device *impl, struct list *old_contacts, ULONG i info->pointerId = contact->id; info->pointerFlags = flags; info->ptPixelLocation = contact->pos; + if (msg == WM_POINTERDOWN) + NtUserMessageCall(0, WM_POINTERENTER, 0, 0, &pointer, NtUserInjectPointer, FALSE); NtUserMessageCall(0, msg, 0, 0, &pointer, NtUserInjectPointer, FALSE); list_add_tail( &impl->contacts, &contact->entry ); @@ -170,6 +172,7 @@ static void release_contacts( struct list *contacts ) info->ptPixelLocation = contact->pos; NtUserMessageCall(0, WM_POINTERUP, 0, 0, &pointer, NtUserInjectPointer, FALSE); + NtUserMessageCall(0, WM_POINTERLEAVE, 0, 0, &pointer, NtUserInjectPointer, FALSE); list_remove( &contact->entry ); free( contact ); diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 346a851fead..62cbc983931 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -1680,7 +1680,6 @@ static BOOL X11DRV_TouchEvent( HWND hwnd, XGenericEventCookie *xev ) XIDeviceEvent *event = xev->data; POINT pt = { event->event_x, event->event_y }, root = { event->root_x, event->root_y }; POINT pos; - UINT msg; pt = map_event_coords( hwnd, event->event, event->root, root, pt ); pos.x = pt.x * 65535 / (virtual.right - virtual.left); @@ -1693,22 +1692,25 @@ static BOOL X11DRV_TouchEvent( HWND hwnd, XGenericEventCookie *xev ) switch (event->evtype) { case XI_TouchBegin: - msg = WM_POINTERDOWN; info->pointerFlags |= POINTER_FLAG_NEW; TRACE("XI_TouchBegin detail %u pos %dx%d, flags %#x\n", event->detail, pos.x, pos.y, info->pointerFlags); + + NtUserMessageCall( hwnd, WM_POINTERENTER, 0, 0, &pointer_info, NtUserInjectPointer, FALSE ); + NtUserMessageCall( hwnd, WM_POINTERDOWN, 0, 0, &pointer_info, NtUserInjectPointer, FALSE ); break; case XI_TouchEnd: - msg = WM_POINTERUP; TRACE("XI_TouchEnd detail %u pos %dx%d, flags %#x\n", event->detail, pos.x, pos.y, info->pointerFlags); + + NtUserMessageCall( hwnd, WM_POINTERUP, 0, 0, &pointer_info, NtUserInjectPointer, FALSE ); + NtUserMessageCall( hwnd, WM_POINTERLEAVE, 0, 0, &pointer_info, NtUserInjectPointer, FALSE ); break; case XI_TouchUpdate: - msg = WM_POINTERUPDATE; TRACE("XI_TouchUpdate detail %u pos %dx%d, flags %#x\n", event->detail, pos.x, pos.y, info->pointerFlags); + + NtUserMessageCall( hwnd, WM_POINTERUPDATE, 0, 0, &pointer_info, NtUserInjectPointer, FALSE ); break; } - NtUserMessageCall( hwnd, msg, 0, 0, &pointer_info, NtUserInjectPointer, FALSE ); - return TRUE; } diff --git a/server/queue.c b/server/queue.c index 26e8f301f79..928f78ba5c1 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2477,20 +2477,15 @@ static void pointer_message_timeout( void *private ) static void queue_pointer_message( UINT message, struct pointer *pointer, int repeated ) { - static const unsigned int messages[][2] = - { - {WM_POINTERUPDATE, 0}, - {WM_POINTERENTER, WM_POINTERDOWN}, - {WM_POINTERUP, WM_POINTERLEAVE}, - }; struct hw_msg_source source = { IMDT_UNAVAILABLE, IMDT_TOUCH }; struct desktop *desktop = pointer->desktop; desktop_shm_t *desktop_shm = desktop->shared; POINTER_INFO *info = &pointer->info.pointerInfo; + struct hardware_msg_data *msg_data; timeout_t time = get_tick_count(); user_handle_t win = pointer->win; struct rectangle top_rect; - unsigned int i, wparam; + unsigned int wparam; struct message *msg; int x, y; @@ -2503,23 +2498,18 @@ static void queue_pointer_message( UINT message, struct pointer *pointer, int re info->frameId = pointer_frame++; wparam = MAKELONG(info->pointerId, info->pointerFlags); - for (i = 0; i < 2 && messages[message - WM_POINTERUPDATE][i]; i++) - { - struct hardware_msg_data *msg_data; + if (!(msg = alloc_hardware_message( 0, source, time, sizeof(pointer->info) ))) return; - if (!(msg = alloc_hardware_message( 0, source, time, sizeof(*info) ))) return; - - msg->win = get_user_full_handle( win ); - msg->msg = messages[message - WM_POINTERUPDATE][i]; - msg->wparam = wparam; - msg->lparam = MAKELONG(x, y); - msg->x = desktop_shm->cursor.x; - msg->y = desktop_shm->cursor.y; - msg_data = msg->data; - mem_append( msg_data + 1, info, sizeof(*info) ); + msg->win = get_user_full_handle( win ); + msg->msg = message; + msg->wparam = wparam; + msg->lparam = MAKELONG(x, y); + msg->x = desktop_shm->cursor.x; + msg->y = desktop_shm->cursor.y; + msg_data = msg->data; + mem_append( msg_data + 1, &pointer->info, sizeof(pointer->info) ); - queue_hardware_message( desktop, msg, 1 ); - } + queue_hardware_message( desktop, msg, 1 ); if (!repeated && pointer->primary && (msg = alloc_hardware_message( 0xff515700, source, time, 0 ))) { @@ -2538,7 +2528,7 @@ static void queue_pointer_message( UINT message, struct pointer *pointer, int re queue_hardware_message( desktop, msg, 0 ); } - if (message != WM_POINTERUP) + if (message != WM_POINTERLEAVE) { pointer->timeout = add_timeout_user( -160000, pointer_message_timeout, pointer ); info->pointerFlags &= ~POINTER_FLAG_NEW; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11693
From: navi <navi@vlhl.dev> --- dlls/mouhid.sys/main.c | 14 ++++++++------ dlls/win32u/input.c | 14 ++++++++++++++ dlls/win32u/message.c | 4 ++++ dlls/win32u/win32u_private.h | 1 + dlls/winex11.drv/mouse.c | 36 +++++++++++++++++++++++++++++++++++- include/ntuser.h | 1 + server/protocol.def | 5 +++++ server/queue.c | 8 ++++++++ 8 files changed, 76 insertions(+), 7 deletions(-) diff --git a/dlls/mouhid.sys/main.c b/dlls/mouhid.sys/main.c index 0ed4d5c0344..23e731ae674 100644 --- a/dlls/mouhid.sys/main.c +++ b/dlls/mouhid.sys/main.c @@ -40,7 +40,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(hid); struct contact { struct list entry; - ULONG id; + UINT id; + ULONG hid_id; POINT pos; }; @@ -118,7 +119,7 @@ static void add_contact( struct device *impl, struct list *old_contacts, ULONG i struct contact *contact; LIST_FOR_EACH_ENTRY( contact, old_contacts, struct contact, entry ) - if (contact->id == id) break; + if (contact->hid_id == id) break; if (&contact->entry != old_contacts) { @@ -127,17 +128,18 @@ static void add_contact( struct device *impl, struct list *old_contacts, ULONG i contact->pos.x = x; contact->pos.y = y; - TRACE( "updating contact %#lx, pos %s\n", contact->id, wine_dbgstr_point( &contact->pos ) ); + TRACE( "updating contact %#lx, pos %s\n", contact->hid_id, wine_dbgstr_point( &contact->pos ) ); } else if ((contact = calloc( 1, sizeof(*contact) ))) { msg = WM_POINTERDOWN; flags |= POINTER_MESSAGE_FLAG_NEW; - contact->id = id; + NtUserMessageCall(0, 0, 0, 0, &contact->id, NtUserAllocatePointer, FALSE); + contact->hid_id = id; contact->pos.x = x; contact->pos.y = y; - TRACE( "new contact %#lx, pos %s\n", contact->id, wine_dbgstr_point( &contact->pos ) ); + TRACE( "new contact %#lx, pos %s\n", contact->hid_id, wine_dbgstr_point( &contact->pos ) ); } else { @@ -165,7 +167,7 @@ static void release_contacts( struct list *contacts ) ULONG flags = POINTER_MESSAGE_FLAG_CONFIDENCE; POINTER_INFO *info = &pointer.pointerInfo; - TRACE( "releasing contact %#lx, pos %s\n", contact->id, wine_dbgstr_point( &contact->pos ) ); + TRACE( "releasing contact %#lx, pos %s\n", contact->hid_id, wine_dbgstr_point( &contact->pos ) ); info->pointerId = contact->id; info->pointerFlags = flags; diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 3b9d5e05db7..2640fce0bf7 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2969,6 +2969,20 @@ static struct pointer *pointer_create( UINT32 id, POINTER_INPUT_TYPE type ) return pointer; } +W32KAPI UINT allocate_pointer_id( void ) +{ + UINT pointerid; + + SERVER_START_REQ( allocate_pointer_id ) + { + wine_server_call( req ); + pointerid = reply->id; + } + SERVER_END_REQ; + + return pointerid; +} + static struct pointer *find_pointer( UINT32 id ) { struct user_thread_info *thread_info = get_user_thread_info(); diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index e56fcf28ac7..21e15637ede 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -4821,6 +4821,10 @@ LRESULT WINAPI NtUserMessageCall( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpa case NtUserInjectPointer: return send_pointer_message( msg, result_info ); + case NtUserAllocatePointer: + *(UINT *)result_info = allocate_pointer_id(); + return 0; + default: FIXME( "%p %x %lx %lx %p %x %x\n", hwnd, msg, (long)wparam, lparam, result_info, type, ansi ); } diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 69693f98f0a..c6288a3c2f9 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -114,6 +114,7 @@ extern USHORT map_scan_to_kbd_vkey( USHORT scan, HKL layout, UINT *mapped ); extern void destroy_thread_pointers(void); extern BOOL process_pointer_message( MSG *msg, UINT hw_id, const struct hardware_msg_data *msg_data ); extern NTSTATUS send_pointer_message( UINT msg, const POINTER_TYPE_INFO *info ); +extern UINT allocate_pointer_id( void ); extern void update_pointer_from_msg( POINTER_INPUT_TYPE type, const MSG *msg ); extern NTSTATUS send_hardware_input( HWND hwnd, UINT flags, const INPUT *input, LPARAM lparam ); diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 62cbc983931..742f60eb315 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -121,6 +121,14 @@ static const UINT button_up_data[NB_BUTTONS] = XContext cursor_context = 0; +struct pointer +{ + UINT detail, id; + struct list entry; +}; + +static struct list pointers = LIST_INIT( pointers ); + static RECT clip_rect; static Cursor create_cursor( HANDLE handle ); @@ -1672,6 +1680,24 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) return TRUE; } +static struct pointer *pointer_get(UINT detail) +{ + struct pointer *pointer; + + LIST_FOR_EACH_ENTRY( pointer, &pointers, struct pointer, entry ) + if (pointer->detail == detail) + return pointer; + + if (!(pointer = calloc( 1, sizeof( *pointer )))) + return NULL; + + pointer->detail = detail; + NtUserMessageCall(0, 0, 0, 0, &pointer->id, NtUserAllocatePointer, FALSE); + list_add_tail( &pointers, &pointer->entry ); + + return pointer; +} + static BOOL X11DRV_TouchEvent( HWND hwnd, XGenericEventCookie *xev ) { RECT virtual = NtUserGetVirtualScreenRect( MDT_RAW_DPI ); @@ -1679,14 +1705,20 @@ static BOOL X11DRV_TouchEvent( HWND hwnd, XGenericEventCookie *xev ) POINTER_INFO *info = &pointer_info.pointerInfo; XIDeviceEvent *event = xev->data; POINT pt = { event->event_x, event->event_y }, root = { event->root_x, event->root_y }; + struct pointer *pointer; POINT pos; + UINT id; + + if (!(pointer = pointer_get(event->detail))) + return FALSE; pt = map_event_coords( hwnd, event->event, event->root, root, pt ); pos.x = pt.x * 65535 / (virtual.right - virtual.left); pos.y = pt.y * 65535 / (virtual.bottom - virtual.top); + id = pointer->id; info->ptPixelLocation = pos; - info->pointerId = event->detail; + info->pointerId = id; info->pointerFlags = POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT; switch (event->evtype) @@ -1703,6 +1735,8 @@ static BOOL X11DRV_TouchEvent( HWND hwnd, XGenericEventCookie *xev ) NtUserMessageCall( hwnd, WM_POINTERUP, 0, 0, &pointer_info, NtUserInjectPointer, FALSE ); NtUserMessageCall( hwnd, WM_POINTERLEAVE, 0, 0, &pointer_info, NtUserInjectPointer, FALSE ); + list_remove( &pointer->entry ); + free( pointer ); break; case XI_TouchUpdate: TRACE("XI_TouchUpdate detail %u pos %dx%d, flags %#x\n", event->detail, pos.x, pos.y, info->pointerFlags); diff --git a/include/ntuser.h b/include/ntuser.h index 45153724d27..f3c16befbbb 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -418,6 +418,7 @@ enum NtUserPostDdeCall = 0x0308, NtUserWintabDriverCall = 0x0309, NtUserInjectPointer = 0x030a, + NtUserAllocatePointer = 0x030b, }; /* NtUserWintabDriverCall codes */ diff --git a/server/protocol.def b/server/protocol.def index 63c2a9f65c8..a20b7058e67 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2441,6 +2441,11 @@ enum message_type VARARG(data,bytes); @END +@REQ(allocate_pointer_id) +@REPLY + unsigned int id; +@END + /* Get a message from the current queue */ @REQ(get_message) unsigned int flags; /* PM_* flags */ diff --git a/server/queue.c b/server/queue.c index 928f78ba5c1..d150a9cdb04 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2467,6 +2467,9 @@ struct pointer }; static unsigned int pointer_frame = 1; +/* pointer id 1 is always hardcoded to PT_MOUSE */ +static unsigned int last_pointer_id = 2; + static void queue_pointer_message( UINT message, struct pointer *pointer, int repeated ); static void pointer_message_timeout( void *private ) @@ -3248,6 +3251,11 @@ DECL_HANDLER(send_pointer_message) return; } +DECL_HANDLER(allocate_pointer_id) +{ + reply->id = last_pointer_id++; +} + /* post a quit message to the current queue */ DECL_HANDLER(post_quit_message) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11693
From: navi <navi@vlhl.dev> --- dlls/win32u/input.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 2640fce0bf7..a4bd8327894 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -3202,8 +3202,23 @@ BOOL WINAPI NtUserGetPointerInfoList( UINT32 id, POINTER_INPUT_TYPE type, UINT_P *entry_count = 1; *pointer_count = 1; + if (!pointer_info) + return TRUE; + memset( pointer_info, 0, size ); - *(POINTER_INFO *)pointer_info = pointer->info.pointerInfo; + switch (type) + { + case PT_PEN: + *(POINTER_PEN_INFO *)pointer_info = pointer->info.penInfo; + break; + case PT_TOUCH: + *(POINTER_TOUCH_INFO *)pointer_info = pointer->info.touchInfo; + break; + default: + *(POINTER_INFO *)pointer_info = pointer->info.pointerInfo; + break; + } + return TRUE; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11693
From: navi <navi@vlhl.dev> --- dlls/mouhid.sys/main.c | 10 +-- dlls/user32/input.c | 8 ++- dlls/user32/user32.spec | 10 +-- dlls/win32u/input.c | 118 ++++++++++++++++++++++++++++++++++- dlls/win32u/main.c | 26 ++++++++ dlls/win32u/message.c | 2 +- dlls/win32u/win32syscalls.h | 15 ++--- dlls/win32u/win32u.spec | 6 +- dlls/win32u/win32u_private.h | 2 +- dlls/wow64win/user.c | 27 ++++++++ include/ntuser.h | 11 ++++ server/protocol.def | 1 + server/queue.c | 22 +++++-- 13 files changed, 225 insertions(+), 33 deletions(-) diff --git a/dlls/mouhid.sys/main.c b/dlls/mouhid.sys/main.c index 23e731ae674..0d0413deea2 100644 --- a/dlls/mouhid.sys/main.c +++ b/dlls/mouhid.sys/main.c @@ -114,6 +114,7 @@ static NTSTATUS start_device_read( DEVICE_OBJECT *device ) static void add_contact( struct device *impl, struct list *old_contacts, ULONG id, LONG x, LONG y ) { UINT msg, flags = POINTER_MESSAGE_FLAG_INRANGE | POINTER_MESSAGE_FLAG_INCONTACT | POINTER_MESSAGE_FLAG_CONFIDENCE; + enum wine_pointer_flags inject_flags = WINE_POINTER_MAP_COORDS | WINE_POINTER_TIMEOUT; POINTER_TYPE_INFO pointer = { .type = PT_TOUCH }; POINTER_INFO *info = &pointer.pointerInfo; struct contact *contact; @@ -151,14 +152,15 @@ static void add_contact( struct device *impl, struct list *old_contacts, ULONG i info->pointerFlags = flags; info->ptPixelLocation = contact->pos; if (msg == WM_POINTERDOWN) - NtUserMessageCall(0, WM_POINTERENTER, 0, 0, &pointer, NtUserInjectPointer, FALSE); - NtUserMessageCall(0, msg, 0, 0, &pointer, NtUserInjectPointer, FALSE); + NtUserMessageCall(0, WM_POINTERENTER, 0, inject_flags, &pointer, NtUserInjectPointer, FALSE); + NtUserMessageCall(0, msg, 0, inject_flags, &pointer, NtUserInjectPointer, FALSE); list_add_tail( &impl->contacts, &contact->entry ); } static void release_contacts( struct list *contacts ) { + enum wine_pointer_flags inject_flags = WINE_POINTER_MAP_COORDS | WINE_POINTER_TIMEOUT; struct contact *contact, *next; LIST_FOR_EACH_ENTRY_SAFE( contact, next, contacts, struct contact, entry ) @@ -173,8 +175,8 @@ static void release_contacts( struct list *contacts ) info->pointerFlags = flags; info->ptPixelLocation = contact->pos; - NtUserMessageCall(0, WM_POINTERUP, 0, 0, &pointer, NtUserInjectPointer, FALSE); - NtUserMessageCall(0, WM_POINTERLEAVE, 0, 0, &pointer, NtUserInjectPointer, FALSE); + NtUserMessageCall(0, WM_POINTERUP, 0, inject_flags, &pointer, NtUserInjectPointer, FALSE); + NtUserMessageCall(0, WM_POINTERLEAVE, 0, inject_flags, &pointer, NtUserInjectPointer, FALSE); list_remove( &contact->entry ); free( contact ); diff --git a/dlls/user32/input.c b/dlls/user32/input.c index 051f4e48ec9..6b64a0d32ad 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -881,9 +881,11 @@ HWND WINAPI GetTaskmanWindow(void) HSYNTHETICPOINTERDEVICE WINAPI CreateSyntheticPointerDevice(POINTER_INPUT_TYPE type, ULONG max_count, POINTER_FEEDBACK_MODE mode) { - FIXME( "type %ld, max_count %ld, mode %d stub!\n", type, max_count, mode); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return NULL; + HANDLE handle; + + if (!NtUserInitializePointerDeviceInjection( type, max_count, NULL, mode, &handle )) + return NULL; + return (HSYNTHETICPOINTERDEVICE) handle; } /*********************************************************************** diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 241b40054b8..f6f350333e7 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -399,7 +399,7 @@ @ stdcall DestroyIcon(long) @ stdcall DestroyMenu(long) NtUserDestroyMenu # @ stub DestroyReasons -# @ stub DestroySyntheticPointerDevice +@ stdcall DestroySyntheticPointerDevice(long) NtUserRemoveInjectionDevice @ stdcall DestroyWindow(long) NtUserDestroyWindow @ stdcall DialogBoxIndirectParamA(long ptr long ptr long) @ stdcall DialogBoxIndirectParamAorW(long ptr long ptr long long) @@ -747,15 +747,15 @@ # @ stub InitializeGenericHidInjection # @ stub InitializeInputDeviceInjection # @ stub InitializeLpkHooks -# @ stub InitializePointerDeviceInjection +@ stdcall InitializePointerDeviceInjection(long long long long ptr) NtUserInitializePointerDeviceInjection # @ stub InitializePointerDeviceInjectionEx @ stdcall InitializeTouchInjection(long long) NtUserInitializeTouchInjection # @ stub InjectDeviceInput # @ stub InjectGenericHidInput # @ stub InjectKeyboardInput # @ stub InjectMouseInput -# @ stub InjectPointerInput -# @ stub InjectSyntheticPointerInput +@ stdcall InjectPointerInput(long ptr long) NtUserInjectPointerInput +@ stdcall InjectSyntheticPointerInput(long ptr long) NtUserInjectPointerInput # @ stub InjectTouchInput # @ stub InputSpaceRegionFromPoint @ stdcall InsertMenuA(long long long long ptr) @@ -986,7 +986,7 @@ @ stdcall ReleaseDC(long long) NtUserReleaseDC # @ stub ReleaseDwmHitTestWaiters @ stdcall RemoveClipboardFormatListener(long) NtUserRemoveClipboardFormatListener -# @ stub RemoveInjectionDevice +@ stdcall RemoveInjectionDevice(long) NtUserRemoveInjectionDevice @ stdcall RemoveMenu(long long long) NtUserRemoveMenu @ stdcall RemovePropA(long str) @ stdcall RemovePropW(long wstr) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index a4bd8327894..729420165cb 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -3077,7 +3077,7 @@ void update_pointer_from_msg( POINTER_INPUT_TYPE type, const MSG *msg ) update_pointer( &info ); } -NTSTATUS send_pointer_message( UINT msg, const POINTER_TYPE_INFO *info ) +NTSTATUS send_pointer_message( UINT msg, enum wine_pointer_flags flags, const POINTER_TYPE_INFO *info ) { POINTER_TYPE_INFO pointer = *info; LARGE_INTEGER counter; @@ -3092,6 +3092,7 @@ NTSTATUS send_pointer_message( UINT msg, const POINTER_TYPE_INFO *info ) { req->win = wine_server_user_handle( pointer.pointerInfo.hwndTarget ); req->msg = msg; + req->flags = flags; wine_server_add_data( req, &pointer, sizeof(pointer) ); ret = wine_server_call( req ); } @@ -3244,3 +3245,118 @@ BOOL WINAPI NtUserGetPointerDeviceRects( HANDLE handle, RECT *device_rect, RECT TRACE( "returning device %s, display %s\n", wine_dbgstr_rect(device_rect), wine_dbgstr_rect(display_rect) ); return TRUE; } + +struct syn_pointer +{ + HWND focus; + UINT32 id; + POINTER_TYPE_INFO last; +}; + +BOOL WINAPI NtUserInjectPointerInput( HSYNTHETICPOINTERDEVICE device, const POINTER_TYPE_INFO *pointerInfo, UINT32 count ) +{ + UINT msg = WM_POINTERUPDATE; + struct syn_pointer *pointer; + POINTER_TYPE_INFO type_info; + POINTER_INFO *info; + INT hittest; + HWND hwnd; + + type_info = *pointerInfo; + info = &type_info.pointerInfo; + info->pointerType = type_info.type; + info->pointerFlags &= (POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT); + info->pointerFlags |= POINTER_FLAG_UPDATE | POINTER_FLAG_CONFIDENCE; + + switch (type_info.type) + { + case PT_PEN: + type_info.penInfo.penMask = PEN_MASK_PRESSURE | PEN_MASK_ROTATION | PEN_MASK_TILT_X | PEN_MASK_TILT_Y; + break; + default: break; + } + + hwnd = window_from_point( NULL, info->ptPixelLocation, &hittest, TRUE ); + + pointer = get_user_handle_ptr( device, NTUSER_OBJ_POINTER_DEVICE ); + + TRACE( "Injecting pointer input for pointer %d.\n", pointer->id ); + + if (info->pointerFlags & POINTER_FLAG_INCONTACT) + info->pointerFlags |= POINTER_FLAG_FIRSTBUTTON; + + info->pointerId = pointer->id; + info->pointerType = PT_PEN; + info->ptHimetricLocation.x = info->ptPixelLocation.x * HIMETRIC_PER_INCH / system_dpi; + info->ptHimetricLocation.y = info->ptPixelLocation.y * HIMETRIC_PER_INCH / system_dpi; + + info->ptPixelLocationRaw = info->ptPixelLocation; + info->ptHimetricLocationRaw = info->ptHimetricLocation; + info->sourceDevice = device; + info->hwndTarget = hwnd; + + if (!(info->pointerFlags & POINTER_FLAG_INRANGE)) + { + if (pointer->focus) + { + info->hwndTarget = pointer->focus; + send_pointer_message( WM_POINTERUPDATE, 0, &type_info ); + send_pointer_message( WM_POINTERLEAVE, 0, &type_info ); + } + pointer->focus = NULL; + goto out; + } + + if (!pointer->focus) + { + info->pointerId = pointer->id = allocate_pointer_id(); + info->pointerFlags |= POINTER_FLAG_NEW; + } + + if (hwnd != pointer->focus) + { + if (pointer->focus) + send_pointer_message( WM_POINTERLEAVE, 0, &pointer->last ); + send_pointer_message( WM_POINTERENTER, 0, &type_info ); + pointer->focus = hwnd; + } + + if ((info->pointerFlags & POINTER_FLAG_INCONTACT) != (pointer->last.pointerInfo.pointerFlags & POINTER_FLAG_INCONTACT)) + { + info->pointerFlags &= ~POINTER_FLAG_UPDATE; + if (info->pointerFlags & POINTER_FLAG_INCONTACT) + { + info->pointerFlags |= POINTER_FLAG_DOWN; + msg = WM_POINTERDOWN; + } + else + { + info->pointerFlags |= POINTER_FLAG_UP; + msg = WM_POINTERUP; + } + } + + send_pointer_message( msg, 0, &type_info ); + pointer->last = type_info; + +out: + release_user_handle_ptr( pointer ); + return TRUE; +} + +W32KAPI BOOL WINAPI NtUserInitializePointerDeviceInjection( POINTER_INPUT_TYPE type, ULONG contactCount, + HMONITOR monitor, DWORD visualMode, HANDLE* device ) +{ + struct syn_pointer *pointer = calloc( 1, sizeof(*pointer) ); + + TRACE( "%#x, %u, %p, %d, %p\n", type, contactCount, monitor, visualMode, device ); + + *device = alloc_user_handle( pointer, NTUSER_OBJ_POINTER_DEVICE ); + return TRUE; +} + +W32KAPI BOOL WINAPI NtUserRemoveInjectionDevice( HANDLE device ) +{ + free( free_user_handle( device, NTUSER_OBJ_POINTER_DEVICE ) ); + return true; +} diff --git a/dlls/win32u/main.c b/dlls/win32u/main.c index 22e5368b132..d6c60edd900 100644 --- a/dlls/win32u/main.c +++ b/dlls/win32u/main.c @@ -1753,11 +1753,37 @@ BOOL SYSCALL_API NtUserGetPointerType( UINT32 id, POINTER_INPUT_TYPE *type ) SYSCALL_FUNC( NtUserGetPointerType ); } +BOOL SYSCALL_API NtUserGetPointerCursorId( UINT32 id, UINT32 *type ) +{ + SYSCALL_FUNC( NtUserGetPointerCursorId ); +} + +BOOL SYSCALL_API NtUserGetPointerDevices( UINT32 *deviceCount, POINTER_DEVICE_INFO *pointerDevices ) +{ + SYSCALL_FUNC( NtUserGetPointerDevices ); +} + BOOL SYSCALL_API NtUserGetPointerDeviceRects( HANDLE handle, RECT *device_rect, RECT *display_rect ) { SYSCALL_FUNC( NtUserGetPointerDeviceRects ); } +BOOL SYSCALL_API NtUserInitializePointerDeviceInjection( POINTER_INPUT_TYPE type, ULONG contactCount, + HMONITOR monitor, DWORD visualMode, HANDLE* device ) +{ + SYSCALL_FUNC( NtUserInitializePointerDeviceInjection ); +} + +BOOL SYSCALL_API NtUserRemoveInjectionDevice( HANDLE device ) +{ + SYSCALL_FUNC( NtUserRemoveInjectionDevice ); +} + +BOOL SYSCALL_API NtUserInjectPointerInput( HSYNTHETICPOINTERDEVICE device, const POINTER_TYPE_INFO *pointerInfo, UINT32 count ) +{ + SYSCALL_FUNC( NtUserInjectPointerInput ); +} + INT SYSCALL_API NtUserGetPriorityClipboardFormat( UINT *list, INT count ) { SYSCALL_FUNC( NtUserGetPriorityClipboardFormat ); diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 21e15637ede..2b875171956 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -4819,7 +4819,7 @@ LRESULT WINAPI NtUserMessageCall( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpa return user_driver->pWintabProc( hwnd, msg, wparam, lparam, result_info ); case NtUserInjectPointer: - return send_pointer_message( msg, result_info ); + return send_pointer_message( msg, lparam, result_info ); case NtUserAllocatePointer: *(UINT *)result_info = allocate_pointer_id(); diff --git a/dlls/win32u/win32syscalls.h b/dlls/win32u/win32syscalls.h index 132ac47836b..86f39844c0b 100644 --- a/dlls/win32u/win32syscalls.h +++ b/dlls/win32u/win32syscalls.h @@ -1150,7 +1150,7 @@ SYSCALL_ENTRY( 0x147a, NtUserInitializeClientPfnArrays, 16 ) \ SYSCALL_ENTRY( 0x147b, NtUserInitializeGenericHidInjection, 0 ) \ SYSCALL_ENTRY( 0x147c, NtUserInitializeInputDeviceInjection, 0 ) \ - SYSCALL_ENTRY( 0x147d, NtUserInitializePointerDeviceInjection, 0 ) \ + SYSCALL_ENTRY( 0x147d, NtUserInitializePointerDeviceInjection, 20 ) \ SYSCALL_ENTRY( 0x147e, NtUserInitializePointerDeviceInjectionEx, 0 ) \ SYSCALL_ENTRY( 0x147f, NtUserInitializeTouchInjection, 8 ) \ SYSCALL_ENTRY( 0x1480, NtUserInjectDeviceInput, 0 ) \ @@ -1158,7 +1158,7 @@ SYSCALL_ENTRY( 0x1482, NtUserInjectGesture, 0 ) \ SYSCALL_ENTRY( 0x1483, NtUserInjectKeyboardInput, 0 ) \ SYSCALL_ENTRY( 0x1484, NtUserInjectMouseInput, 0 ) \ - SYSCALL_ENTRY( 0x1485, NtUserInjectPointerInput, 0 ) \ + SYSCALL_ENTRY( 0x1485, NtUserInjectPointerInput, 12 ) \ SYSCALL_ENTRY( 0x1486, NtUserInjectTouchInput, 0 ) \ SYSCALL_ENTRY( 0x1487, NtUserInteractiveControlQueryUsage, 0 ) \ SYSCALL_ENTRY( 0x1488, NtUserInternalGetWindowIcon, 8 ) \ @@ -1309,7 +1309,7 @@ SYSCALL_ENTRY( 0x1519, NtUserRemoteStopScreenUpdates, 0 ) \ SYSCALL_ENTRY( 0x151a, NtUserRemoteThinwireStats, 0 ) \ SYSCALL_ENTRY( 0x151b, NtUserRemoveClipboardFormatListener, 4 ) \ - SYSCALL_ENTRY( 0x151c, NtUserRemoveInjectionDevice, 0 ) \ + SYSCALL_ENTRY( 0x151c, NtUserRemoveInjectionDevice, 4 ) \ SYSCALL_ENTRY( 0x151d, NtUserRemoveMenu, 12 ) \ SYSCALL_ENTRY( 0x151e, NtUserRemoveProp, 8 ) \ SYSCALL_ENTRY( 0x151f, NtUserRemoveQueueCompletion, 0 ) \ @@ -2692,7 +2692,7 @@ SYSCALL_ENTRY( 0x147a, NtUserInitializeClientPfnArrays, 32 ) \ SYSCALL_ENTRY( 0x147b, NtUserInitializeGenericHidInjection, 0 ) \ SYSCALL_ENTRY( 0x147c, NtUserInitializeInputDeviceInjection, 0 ) \ - SYSCALL_ENTRY( 0x147d, NtUserInitializePointerDeviceInjection, 0 ) \ + SYSCALL_ENTRY( 0x147d, NtUserInitializePointerDeviceInjection, 40 ) \ SYSCALL_ENTRY( 0x147e, NtUserInitializePointerDeviceInjectionEx, 0 ) \ SYSCALL_ENTRY( 0x147f, NtUserInitializeTouchInjection, 16 ) \ SYSCALL_ENTRY( 0x1480, NtUserInjectDeviceInput, 0 ) \ @@ -2700,7 +2700,7 @@ SYSCALL_ENTRY( 0x1482, NtUserInjectGesture, 0 ) \ SYSCALL_ENTRY( 0x1483, NtUserInjectKeyboardInput, 0 ) \ SYSCALL_ENTRY( 0x1484, NtUserInjectMouseInput, 0 ) \ - SYSCALL_ENTRY( 0x1485, NtUserInjectPointerInput, 0 ) \ + SYSCALL_ENTRY( 0x1485, NtUserInjectPointerInput, 24 ) \ SYSCALL_ENTRY( 0x1486, NtUserInjectTouchInput, 0 ) \ SYSCALL_ENTRY( 0x1487, NtUserInteractiveControlQueryUsage, 0 ) \ SYSCALL_ENTRY( 0x1488, NtUserInternalGetWindowIcon, 16 ) \ @@ -2851,7 +2851,7 @@ SYSCALL_ENTRY( 0x1519, NtUserRemoteStopScreenUpdates, 0 ) \ SYSCALL_ENTRY( 0x151a, NtUserRemoteThinwireStats, 0 ) \ SYSCALL_ENTRY( 0x151b, NtUserRemoveClipboardFormatListener, 8 ) \ - SYSCALL_ENTRY( 0x151c, NtUserRemoveInjectionDevice, 0 ) \ + SYSCALL_ENTRY( 0x151c, NtUserRemoveInjectionDevice, 8 ) \ SYSCALL_ENTRY( 0x151d, NtUserRemoveMenu, 24 ) \ SYSCALL_ENTRY( 0x151e, NtUserRemoveProp, 16 ) \ SYSCALL_ENTRY( 0x151f, NtUserRemoveQueueCompletion, 0 ) \ @@ -3882,14 +3882,12 @@ SYSCALL_STUB( NtUserInitialize ) \ SYSCALL_STUB( NtUserInitializeGenericHidInjection ) \ SYSCALL_STUB( NtUserInitializeInputDeviceInjection ) \ - SYSCALL_STUB( NtUserInitializePointerDeviceInjection ) \ SYSCALL_STUB( NtUserInitializePointerDeviceInjectionEx ) \ SYSCALL_STUB( NtUserInjectDeviceInput ) \ SYSCALL_STUB( NtUserInjectGenericHidInput ) \ SYSCALL_STUB( NtUserInjectGesture ) \ SYSCALL_STUB( NtUserInjectKeyboardInput ) \ SYSCALL_STUB( NtUserInjectMouseInput ) \ - SYSCALL_STUB( NtUserInjectPointerInput ) \ SYSCALL_STUB( NtUserInjectTouchInput ) \ SYSCALL_STUB( NtUserInteractiveControlQueryUsage ) \ SYSCALL_STUB( NtUserInternalStartMoveSize ) \ @@ -3996,7 +3994,6 @@ SYSCALL_STUB( NtUserRemoteShadowStop ) \ SYSCALL_STUB( NtUserRemoteStopScreenUpdates ) \ SYSCALL_STUB( NtUserRemoteThinwireStats ) \ - SYSCALL_STUB( NtUserRemoveInjectionDevice ) \ SYSCALL_STUB( NtUserRemoveQueueCompletion ) \ SYSCALL_STUB( NtUserRemoveVisualIdentifier ) \ SYSCALL_STUB( NtUserReportInertia ) \ diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 2c409010cd2..e89f55d2d80 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -1148,7 +1148,7 @@ @ stdcall -syscall NtUserInitializeClientPfnArrays(ptr ptr ptr ptr) @ stub -syscall NtUserInitializeGenericHidInjection @ stub -syscall NtUserInitializeInputDeviceInjection -@ stub -syscall NtUserInitializePointerDeviceInjection +@ stdcall -syscall NtUserInitializePointerDeviceInjection(long long long long ptr) @ stub -syscall NtUserInitializePointerDeviceInjectionEx @ stdcall -syscall NtUserInitializeTouchInjection(long long) @ stub -syscall NtUserInjectDeviceInput @@ -1156,7 +1156,7 @@ @ stub -syscall NtUserInjectGesture @ stub -syscall NtUserInjectKeyboardInput @ stub -syscall NtUserInjectMouseInput -@ stub -syscall NtUserInjectPointerInput +@ stdcall -syscall NtUserInjectPointerInput(long ptr long) @ stub -syscall NtUserInjectTouchInput @ stub -syscall NtUserInteractiveControlQueryUsage @ stdcall -syscall NtUserInternalGetWindowIcon(ptr long) @@ -1307,7 +1307,7 @@ @ stub -syscall NtUserRemoteStopScreenUpdates @ stub -syscall NtUserRemoteThinwireStats @ stdcall -syscall NtUserRemoveClipboardFormatListener(long) -@ stub -syscall NtUserRemoveInjectionDevice +@ stdcall -syscall NtUserRemoveInjectionDevice(long) @ stdcall -syscall NtUserRemoveMenu(long long long) @ stdcall -syscall NtUserRemoveProp(long wstr) @ stub -syscall NtUserRemoveQueueCompletion diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index c6288a3c2f9..4c129fd44d9 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -113,7 +113,7 @@ extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ); extern USHORT map_scan_to_kbd_vkey( USHORT scan, HKL layout, UINT *mapped ); extern void destroy_thread_pointers(void); extern BOOL process_pointer_message( MSG *msg, UINT hw_id, const struct hardware_msg_data *msg_data ); -extern NTSTATUS send_pointer_message( UINT msg, const POINTER_TYPE_INFO *info ); +NTSTATUS send_pointer_message( UINT msg, enum wine_pointer_flags flags, const POINTER_TYPE_INFO *info ); extern UINT allocate_pointer_id( void ); extern void update_pointer_from_msg( POINTER_INPUT_TYPE type, const MSG *msg ); extern NTSTATUS send_hardware_input( HWND hwnd, UINT flags, const INPUT *input, LPARAM lparam ); diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index 4cf6b3d6dc8..719fa0783a2 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -2981,6 +2981,33 @@ NTSTATUS WINAPI wow64_NtUserGetPointerDeviceRects( UINT *args ) return NtUserGetPointerDeviceRects( device, device_rect, display_rect ); } +NTSTATUS WINAPI wow64_NtUserInitializePointerDeviceInjection( UINT *args ) +{ + POINTER_INPUT_TYPE type = get_ulong( &args ); + ULONG contactCount = get_ulong( &args ); + HMONITOR monitor = get_handle( &args ); + DWORD visualMode = get_ulong( &args ); + HANDLE* device = get_ptr( &args ); + + return NtUserInitializePointerDeviceInjection( type, contactCount, monitor, visualMode, device ); +} + +NTSTATUS WINAPI wow64_NtUserRemoveInjectionDevice( UINT *args ) +{ + HANDLE device = get_handle( &args ); + + return NtUserRemoveInjectionDevice( device ); +} + +NTSTATUS WINAPI wow64_NtUserInjectPointerInput( UINT *args ) +{ + HSYNTHETICPOINTERDEVICE handle = get_handle( &args ); + const POINTER_TYPE_INFO *pointerInfo = get_ptr( &args ); + UINT32 count = get_ulong( &args ); + + return NtUserInjectPointerInput( handle, pointerInfo, count ); +} + NTSTATUS WINAPI wow64_NtUserGetPriorityClipboardFormat( UINT *args ) { UINT *list = get_ptr( &args ); diff --git a/include/ntuser.h b/include/ntuser.h index f3c16befbbb..e7fb3a6bccf 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -476,6 +476,7 @@ struct post_dde_message_call_params #define NTUSER_OBJ_ACCEL 0x08 #define NTUSER_OBJ_HOOK 0x0f #define NTUSER_OBJ_IMC 0x11 +#define NTUSER_OBJ_POINTER_DEVICE 0x12 /* NtUserScrollWindowEx flag */ #define SW_NODCCACHE 0x8000 @@ -699,6 +700,12 @@ enum wine_drag_drop_call WINE_DRAG_DROP_POST, }; +enum wine_pointer_flags +{ + WINE_POINTER_MAP_COORDS = 0x1, + WINE_POINTER_TIMEOUT = 0x2, +}; + struct ntuser_property_list { UINT64 data; @@ -885,6 +892,10 @@ W32KAPI BOOL WINAPI NtUserGetPointerInfoList( UINT32 id, POINTER_INPUT_TYPE t 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 *device_rect, RECT *display_rect ); +W32KAPI BOOL WINAPI NtUserInitializePointerDeviceInjection( POINTER_INPUT_TYPE type, ULONG contactCount, + HMONITOR monitor, DWORD visualMode, HANDLE* device ); +W32KAPI BOOL WINAPI NtUserRemoveInjectionDevice( HANDLE device ); +W32KAPI BOOL WINAPI NtUserInjectPointerInput( HSYNTHETICPOINTERDEVICE handle, const POINTER_TYPE_INFO *pointerInfo, UINT32 count ); W32KAPI INT WINAPI NtUserGetPriorityClipboardFormat( UINT *list, INT count ); W32KAPI BOOL WINAPI NtUserGetProcessDefaultLayout( ULONG *layout ); W32KAPI ULONG WINAPI NtUserGetProcessDpiAwarenessContext( HANDLE process ); diff --git a/server/protocol.def b/server/protocol.def index a20b7058e67..d647183b62e 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2438,6 +2438,7 @@ enum message_type @REQ(send_pointer_message) user_handle_t win; unsigned int msg; + unsigned int flags; VARARG(data,bytes); @END diff --git a/server/queue.c b/server/queue.c index d150a9cdb04..04157b6e605 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2462,7 +2462,7 @@ struct pointer struct timeout_user *timeout; struct desktop *desktop; user_handle_t win; - int primary; + int primary, do_timeout; POINTER_TYPE_INFO info; }; @@ -2487,14 +2487,12 @@ static void queue_pointer_message( UINT message, struct pointer *pointer, int re struct hardware_msg_data *msg_data; timeout_t time = get_tick_count(); user_handle_t win = pointer->win; - struct rectangle top_rect; unsigned int wparam; struct message *msg; int x, y; - get_virtual_screen_rect( desktop, &top_rect, 0 ); - x = info->ptPixelLocation.x * (top_rect.right - top_rect.left) / 65535; - y = info->ptPixelLocation.y * (top_rect.bottom - top_rect.top) / 65535; + x = info->ptPixelLocation.x; + y = info->ptPixelLocation.y; if (pointer->primary) info->pointerFlags |= POINTER_FLAG_PRIMARY; info->pointerType = pointer->info.type; @@ -2533,7 +2531,8 @@ static void queue_pointer_message( UINT message, struct pointer *pointer, int re if (message != WM_POINTERLEAVE) { - pointer->timeout = add_timeout_user( -160000, pointer_message_timeout, pointer ); + if (pointer->do_timeout) + pointer->timeout = add_timeout_user( -160000, pointer_message_timeout, pointer ); info->pointerFlags &= ~POINTER_FLAG_NEW; } else @@ -3246,6 +3245,17 @@ DECL_HANDLER(send_pointer_message) if (pointer->timeout) remove_timeout_user( pointer->timeout ); pointer->info = *info; pointer->win = req->win; + pointer->do_timeout = !!(req->flags & WINE_POINTER_TIMEOUT); + + if (req->flags & WINE_POINTER_MAP_COORDS) + { + POINT *pt = &pointer->info.pointerInfo.ptPixelLocation; + struct rectangle top_rect; + + get_virtual_screen_rect( desktop, &top_rect, 0 ); + pt->x = pt->x * (top_rect.right - top_rect.left) / 65535; + pt->y = pt->y * (top_rect.bottom - top_rect.top) / 65535; + } queue_pointer_message( req->msg, pointer, 0 ); return; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11693
From: navi <navi@vlhl.dev> --- server/queue.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/server/queue.c b/server/queue.c index 04157b6e605..eda9704d43f 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2512,21 +2512,25 @@ static void queue_pointer_message( UINT message, struct pointer *pointer, int re queue_hardware_message( desktop, msg, 1 ); - if (!repeated && pointer->primary && (msg = alloc_hardware_message( 0xff515700, source, time, 0 ))) + if (!repeated && pointer->primary) { - unsigned int message = WM_MOUSEMOVE; - if (message == WM_POINTERDOWN) message = WM_LBUTTONDOWN; - else if (message == WM_POINTERUP) message = WM_LBUTTONUP; + int click_msgs[2] = { WM_LBUTTONDOWN, WM_LBUTTONUP }, move_msg[2] = { WM_MOUSEMOVE }, *msgs; + msgs = message == WM_POINTERUP ? click_msgs : move_msg; - msg->win = get_user_full_handle( win ); - msg->msg = message; - msg->wparam = 0; - msg->lparam = 0; - msg->x = x; - msg->y = y; - - if (!send_hook_ll_message( desktop, msg, WH_MOUSE_LL, 0, NULL )) - queue_hardware_message( desktop, msg, 0 ); + for (size_t i = 0; i < 2 && msgs[i]; i++) + { + if (!(msg = alloc_hardware_message( 0xff515700, source, time, 0 ))) + break; + msg->win = get_user_full_handle( win ); + msg->msg = msgs[i]; + msg->wparam = 0; + msg->lparam = 0; + msg->x = x; + msg->y = y; + + if (!send_hook_ll_message( desktop, msg, WH_MOUSE_LL, 0, NULL )) + queue_hardware_message( desktop, msg, 0 ); + } } if (message != WM_POINTERLEAVE) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11693
From: navi <navi@vlhl.dev> --- server/queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/queue.c b/server/queue.c index eda9704d43f..e7793f1897e 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2512,7 +2512,7 @@ static void queue_pointer_message( UINT message, struct pointer *pointer, int re queue_hardware_message( desktop, msg, 1 ); - if (!repeated && pointer->primary) + if (!repeated && message != WM_POINTERENTER && pointer->primary) { int click_msgs[2] = { WM_LBUTTONDOWN, WM_LBUTTONUP }, move_msg[2] = { WM_MOUSEMOVE }, *msgs; msgs = message == WM_POINTERUP ? click_msgs : move_msg; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11693
From: navi <navi@vlhl.dev> --- dlls/user32/tests/input.c | 298 +++++++++++++++++++++++++++++++++++++- 1 file changed, 297 insertions(+), 1 deletion(-) diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index a5d82885b91..cdb6695f922 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -184,6 +184,11 @@ static const char *debugstr_wm( UINT msg ) case WM_LBUTTONUP: return "WM_LBUTTONUP"; case WM_LBUTTONDBLCLK: return "WM_LBUTTONDBLCLK"; case WM_NCHITTEST: return "WM_NCHITTEST"; + case WM_POINTERUPDATE: return "WM_POINTERUPDATE"; + case WM_POINTERDOWN: return "WM_POINTERDOWN"; + case WM_POINTERUP: return "WM_POINTERUP"; + case WM_POINTERENTER: return "WM_POINTERENTER"; + case WM_POINTERLEAVE: return "WM_POINTERLEAVE"; } return wine_dbg_sprintf( "%#x", msg ); } @@ -428,6 +433,7 @@ static BOOL (WINAPI *pIsMouseInPointerEnabled)(void); static BOOL (WINAPI *pGetCurrentInputMessageSource)( INPUT_MESSAGE_SOURCE *source ); static BOOL (WINAPI *pGetPointerType)(UINT32, POINTER_INPUT_TYPE*); static BOOL (WINAPI *pGetPointerInfo)(UINT32, POINTER_INFO*); +static BOOL (WINAPI *pGetPointerPenInfo)(UINT32, POINTER_PEN_INFO*); static BOOL (WINAPI *pGetPointerInfoHistory)(UINT32, UINT32*, POINTER_INFO*); static BOOL (WINAPI *pGetPointerFrameInfo)(UINT32, UINT32*, POINTER_INFO*); static BOOL (WINAPI *pGetPointerFrameInfoHistory)(UINT32, UINT32*, UINT32*, POINTER_INFO*); @@ -461,6 +467,7 @@ static void init_function_pointers(void) GET_PROC(GetCurrentInputMessageSource); GET_PROC(GetMouseMovePointsEx); GET_PROC(GetPointerInfo); + GET_PROC(GetPointerPenInfo); GET_PROC(GetPointerInfoHistory); GET_PROC(GetPointerFrameInfo); GET_PROC(GetPointerFrameInfoHistory); @@ -5836,6 +5843,290 @@ static BOOL accept_pointer_messages( UINT msg ) return msg >= WM_TOUCH && msg <= WM_POINTERROUTEDRELEASED; } +#define ok_pointer_seq( hwnd, id, msgs ) ok_pointer_seq_( __FILE__, __LINE__, hwnd, id, msgs, #msgs ) +static void ok_pointer_seq_( const char *file, int line, HWND hwnd, UINT32 pointerid, struct user_call *msgs, const char *context ) +{ + + for (struct user_call *msg = msgs; msg->func; msg++) { + if (msg->message.msg == WM_MOUSEMOVE || msg->message.msg == WM_LBUTTONDOWN || msg->message.msg == WM_LBUTTONUP) + { + POINT pt = { LOWORD( msg->message.lparam ), HIWORD( msg->message.lparam ) }; + ScreenToClient( hwnd, &pt ); + msg->message.lparam = MAKELONG( pt.x, pt.y ); + } + else + { + msg->message.wparam = MAKELONG( pointerid, HIWORD(msg->message.wparam) ); + } + } + ok_seq_( file, line, msgs, context ); +} + +#define compare_pen( got, expected ) compare_pen_( __FILE__, __LINE__, got, expected ) +static void compare_pen_( const char *file, int line, POINTER_PEN_INFO *got, POINTER_PEN_INFO *expected ) +{ + check_member_( file, line, *got, *expected, "%d", pointerInfo.pointerId ); + check_member_( file, line, *got, *expected, "%#lx", pointerInfo.pointerType ); + ok_(file, line)( !!got->pointerInfo.frameId, "got frameId %u\n", got->pointerInfo.frameId ); + check_member_( file, line, *got, *expected, "%#x", pointerInfo.pointerFlags ); + ok_(file, line)( got->pointerInfo.sourceDevice != INVALID_HANDLE_VALUE, "got sourceDevice %p\n", got->pointerInfo.sourceDevice ); + check_member_( file, line, *got, *expected, "%p", pointerInfo.hwndTarget ); + + check_member_( file, line, *got, *expected, "%lu", pointerInfo.ptPixelLocation.x ); + check_member_( file, line, *got, *expected, "%lu", pointerInfo.ptPixelLocation.y ); + check_member_( file, line, *got, *expected, "%lu", pointerInfo.ptPixelLocationRaw.x ); + check_member_( file, line, *got, *expected, "%lu", pointerInfo.ptPixelLocationRaw.y ); + check_member_( file, line, *got, *expected, "%lu", pointerInfo.ptHimetricLocation.x ); + check_member_( file, line, *got, *expected, "%lu", pointerInfo.ptHimetricLocation.y ); + check_member_( file, line, *got, *expected, "%lu", pointerInfo.ptHimetricLocationRaw.x ); + check_member_( file, line, *got, *expected, "%lu", pointerInfo.ptHimetricLocationRaw.y ); + + ok_(file, line)( !!got->pointerInfo.dwTime, "got dwTime %lu\n", got->pointerInfo.dwTime ); + check_member_( file, line, *got, *expected, "%d", pointerInfo.InputData ); + check_member_( file, line, *got, *expected, "%#lx", pointerInfo.dwKeyStates ); + ok_(file, line)( !!got->pointerInfo.dwTime, "got dwTime %lu\n", got->pointerInfo.dwTime ); + ok_(file, line)( !!got->pointerInfo.PerformanceCount, "got PerformanceCount %llu\n", got->pointerInfo.PerformanceCount ); + check_member_( file, line, *got, *expected, "%#x", pointerInfo.ButtonChangeType ); + + check_member_( file, line, *got, *expected, "%#x", penMask ); + check_member_( file, line, *got, *expected, "%#x", pressure ); + check_member_( file, line, *got, *expected, "%#x", rotation ); + check_member_( file, line, *got, *expected, "%#x", tiltX ); + check_member_( file, line, *got, *expected, "%#x", tiltY ); +} + +static void test_GetPointerPenInfo( void ) +{ +#define WIN_MSG(m, h, w, l, ...) {.func = MSG_TEST_WIN, .message = {.msg = m, .hwnd = h, .wparam = w, .lparam = l}, ## __VA_ARGS__} + UINT flags = POINTER_FLAG_PRIMARY | POINTER_FLAG_CONFIDENCE | POINTER_FLAG_UPDATE; + UINT flags_inrange = POINTER_FLAG_INRANGE | flags; + struct user_call new_enter[] = { + WIN_MSG(WM_POINTERENTER, NULL, MAKELONG(0, POINTER_FLAG_NEW | flags_inrange), MAKELONG(150, 150)), + WIN_MSG(WM_POINTERUPDATE, NULL, MAKELONG(0, POINTER_FLAG_NEW | flags_inrange), MAKELONG(150, 150)), + WIN_MSG(WM_MOUSEMOVE, NULL, 0, MAKELONG(150, 150)), + {0} + }; + + struct user_call update[] = { + WIN_MSG(WM_POINTERUPDATE, NULL, MAKELONG(0, flags_inrange), MAKELONG(150, 150)), + {0} + }; + + struct user_call leave[] = { + WIN_MSG(WM_POINTERLEAVE, NULL, MAKELONG(0, flags_inrange), MAKELONG(150, 150)), + {0} + }; + + struct user_call reenter[] = { + WIN_MSG(WM_POINTERENTER, NULL, MAKELONG(0, flags_inrange), MAKELONG(175, 150)), + WIN_MSG(WM_POINTERUPDATE, NULL, MAKELONG(0, flags_inrange), MAKELONG(175, 150)), + WIN_MSG(WM_MOUSEMOVE, NULL, 0, MAKELONG(175, 150)), + {0} + }; + + struct user_call out_range[] = { + WIN_MSG(WM_POINTERUPDATE, NULL, MAKELONG(0, flags), MAKELONG(175, 150)), + WIN_MSG(WM_POINTERLEAVE, NULL, MAKELONG(0, flags), MAKELONG(175, 150)), + {0} + }; + + struct user_call in_range[] = { + WIN_MSG(WM_POINTERENTER, NULL, MAKELONG(0, POINTER_FLAG_NEW | flags_inrange), MAKELONG(175, 150)), + WIN_MSG(WM_POINTERUPDATE, NULL, MAKELONG(0, POINTER_FLAG_NEW | flags_inrange), MAKELONG(175, 150)), + {0} + }; + + struct user_call down[] = { + WIN_MSG(WM_POINTERDOWN, NULL, MAKELONG(0, POINTER_FLAG_INCONTACT | POINTER_FLAG_FIRSTBUTTON | flags_inrange), MAKELONG(175, 150)), + {0} + }; + + struct user_call up[] = { + WIN_MSG(WM_POINTERUP, NULL, MAKELONG(0, flags_inrange), MAKELONG(175, 150)), + WIN_MSG(WM_LBUTTONDOWN, NULL, 1, MAKELONG(175, 150)), + WIN_MSG(WM_LBUTTONUP, NULL, 0, MAKELONG(175, 150)), + {0} + }; +#undef WIN_MSG + + HSYNTHETICPOINTERDEVICE dev = CreateSyntheticPointerDevice( PT_PEN, 1, POINTER_FEEDBACK_DEFAULT ); + POINTER_TYPE_INFO syn_pointer = + { + .type = PT_PEN, + .penInfo = { + .pointerInfo = + { + .pointerFlags = POINTER_FLAG_INRANGE, + .ptPixelLocation = { .x = 150, .y = 150 }, + }, + .penMask = PEN_MASK_PRESSURE | PEN_MASK_TILT_X, + .pressure = 512, + } + }; + POINTER_PEN_INFO info, exp = { + .pointerInfo = + { + .pointerType = PT_PEN, + .pointerFlags = flags_inrange | POINTER_FLAG_UPDATE | POINTER_FLAG_NEW, + .ptPixelLocation = { .x = 150, .y = 150 }, + .ptPixelLocationRaw = { .x = 150, .y = 150 }, + .ptHimetricLocation = { .x = 150 * 2540 / 96, .y = 150 * 2540 / 96 }, + .ptHimetricLocationRaw = { .x = 150 * 2540 / 96, .y = 150 * 2540 / 96 }, + }, + .penMask = PEN_MASK_PRESSURE | PEN_MASK_ROTATION | PEN_MASK_TILT_X | PEN_MASK_TILT_Y, + .pressure = 512, + }; + UINT32 pointerid, newid; + POINTER_INFO *syn_info; + WNDCLASSW cls = + { + .lpfnWndProc = DefWindowProcW, + .hInstance = GetModuleHandleW( NULL ), + .hbrBackground = GetStockObject( WHITE_BRUSH ), + .lpszClassName = L"test", + }; + ATOM class; + HWND hwnd; + BOOL ret; + + class = RegisterClassW( &cls ); + ok( class, "RegisterClassW failed: %lu\n", GetLastError() ); + + hwnd = CreateWindowW( L"test", L"test name", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 200, 200, 0, 0, NULL, 0 ); + empty_message_queue(); + + SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)append_message_wndproc ); + p_accept_message = accept_pointer_messages; + + syn_info = &syn_pointer.pointerInfo; + exp.pointerInfo.hwndTarget = hwnd; + exp.pointerInfo.sourceDevice = dev; + + ret = InjectSyntheticPointerInput( dev, &syn_pointer, 1 ); + ok( ret, "InjectSyntheticPointerInput failed, error %lu\n", GetLastError() ); + + wait_messages( 100, FALSE ); + ok( current_sequence_len, "missing pointer messages\n" ); + if (!current_sequence_len) + return; + pointerid = GET_POINTERID_WPARAM(current_sequence[0].message.wparam); + exp.pointerInfo.pointerId = pointerid; + ok_pointer_seq( hwnd, pointerid, new_enter ); + + ret = pGetPointerPenInfo( pointerid, &info ); + ok( ret, "GetPointerInfo failed, error %lu\n", GetLastError() ); + compare_pen( &info, &exp ); + + exp.pointerInfo.pointerFlags &= ~POINTER_FLAG_NEW; + ret = InjectSyntheticPointerInput( dev, &syn_pointer, 1 ); + ok( ret, "InjectSyntheticPointerInput failed, error %lu\n", GetLastError() ); + + wait_messages( 100, FALSE ); + ok_pointer_seq(hwnd, pointerid, update); + + ret = pGetPointerPenInfo( pointerid, &info ); + ok( ret, "GetPointerInfo failed, error %lu\n", GetLastError() ); + compare_pen( &info, &exp ); + + syn_info->ptPixelLocation.x = 350; + + ret = InjectSyntheticPointerInput( dev, &syn_pointer, 1 ); + ok( ret, "InjectSyntheticPointerInput failed, error %lu\n", GetLastError() ); + + wait_messages( 100, FALSE ); + ok_pointer_seq(hwnd, pointerid, leave); + + ret = pGetPointerPenInfo( pointerid, &info ); + ok( ret, "GetPointerInfo failed, error %lu\n", GetLastError() ); + compare_pen( &info, &exp ); + + syn_info->ptPixelLocation.x = 175; + exp.pointerInfo.ptPixelLocation.x = exp.pointerInfo.ptPixelLocationRaw.x = 175; + exp.pointerInfo.ptHimetricLocation.x = exp.pointerInfo.ptHimetricLocationRaw.x = 175 * 2540 / 96; + + ret = InjectSyntheticPointerInput( dev, &syn_pointer, 1 ); + ok( ret, "InjectSyntheticPointerInput failed, error %lu\n", GetLastError() ); + + wait_messages( 100, FALSE ); + ok_pointer_seq(hwnd, pointerid, reenter); + + ret = pGetPointerPenInfo( pointerid, &info ); + ok( ret, "GetPointerInfo failed, error %lu\n", GetLastError() ); + compare_pen( &info, &exp ); + + syn_info->pointerFlags &= ~POINTER_FLAG_INRANGE; + + ret = InjectSyntheticPointerInput( dev, &syn_pointer, 1 ); + ok( ret, "InjectSyntheticPointerInput failed, error %lu\n", GetLastError() ); + + wait_messages( 100, FALSE ); + ok_pointer_seq(hwnd, pointerid, out_range); + + ret = pGetPointerPenInfo( pointerid, &info ); + ok( ret, "GetPointerInfo failed, error %lu\n", GetLastError() ); + exp.pointerInfo.pointerFlags &= ~(POINTER_FLAG_INRANGE); + compare_pen( &info, &exp ); + + syn_info->pointerFlags |= POINTER_FLAG_INRANGE; + ret = InjectSyntheticPointerInput( dev, &syn_pointer, 1 ); + ok( ret, "InjectSyntheticPointerInput failed, error %lu\n", GetLastError() ); + + wait_messages( 100, FALSE ); + ok( current_sequence_len, "missing pointer message\n" ); + newid = GET_POINTERID_WPARAM(current_sequence[0].message.wparam); + ok( pointerid != newid, "pointerId %d unchanged\n", pointerid ); + exp.pointerInfo.pointerId = pointerid = newid; + ok_pointer_seq(hwnd, pointerid, in_range); + + ret = pGetPointerPenInfo( pointerid, &info ); + ok( ret, "GetPointerInfo failed, error %lu\n", GetLastError() ); + exp.pointerInfo.pointerFlags |= POINTER_FLAG_NEW | POINTER_FLAG_INRANGE; + compare_pen( &info, &exp ); + exp.pointerInfo.pointerFlags &= ~POINTER_FLAG_NEW; + + syn_info->pointerFlags |= POINTER_FLAG_INCONTACT; + ret = InjectSyntheticPointerInput( dev, &syn_pointer, 1 ); + ok( ret, "InjectSyntheticPointerInput failed, error %lu\n", GetLastError() ); + + wait_messages( 100, FALSE ); + ok_pointer_seq(hwnd, pointerid, down); + + ret = pGetPointerPenInfo( pointerid, &info ); + ok( ret, "GetPointerInfo failed, error %lu\n", GetLastError() ); + exp.pointerInfo.pointerFlags |= POINTER_FLAG_INCONTACT | POINTER_FLAG_DOWN | POINTER_FLAG_FIRSTBUTTON; + exp.pointerInfo.pointerFlags &= ~POINTER_FLAG_UPDATE; + exp.pointerInfo.ButtonChangeType = POINTER_CHANGE_FIRSTBUTTON_DOWN; + compare_pen( &info, &exp ); + exp.pointerInfo.pointerFlags &= ~POINTER_FLAG_DOWN; + + syn_info->pointerFlags &= ~POINTER_FLAG_INCONTACT; + ret = InjectSyntheticPointerInput( dev, &syn_pointer, 1 ); + ok( ret, "InjectSyntheticPointerInput failed, error %lu\n", GetLastError() ); + + wait_messages( 100, FALSE ); + ok_pointer_seq(hwnd, pointerid, up); + + ret = pGetPointerPenInfo( pointerid, &info ); + ok( ret, "GetPointerInfo failed, error %lu\n", GetLastError() ); + exp.pointerInfo.pointerFlags &= ~(POINTER_FLAG_FIRSTBUTTON | POINTER_FLAG_INCONTACT); + exp.pointerInfo.pointerFlags |= POINTER_FLAG_UP; + exp.pointerInfo.ButtonChangeType = POINTER_CHANGE_FIRSTBUTTON_UP; + compare_pen( &info, &exp ); + + syn_info->pointerFlags &= ~POINTER_FLAG_FIRSTBUTTON; + for (unsigned i = 0; i < 5; i++) + InjectSyntheticPointerInput( dev, &syn_pointer, 1 ); + wait_messages( 100, FALSE ); + /* one message, history count == 5 */ + + syn_info->pointerFlags &= ~POINTER_FLAG_INRANGE; + InjectSyntheticPointerInput( dev, &syn_pointer, 1 ); + + DestroySyntheticPointerDevice( dev ); + p_accept_message = NULL; +} + static void test_GetPointerInfo( BOOL mouse_in_pointer_enabled ) { #define WIN_MSG(m, h, w, l, ...) {.func = MSG_TEST_WIN, .message = {.msg = m, .hwnd = h, .wparam = w, .lparam = l}, ## __VA_ARGS__} @@ -5910,7 +6201,7 @@ static void test_GetPointerInfo( BOOL mouse_in_pointer_enabled ) .lpfnWndProc = DefWindowProcW, .hInstance = GetModuleHandleW( NULL ), .hbrBackground = GetStockObject( WHITE_BRUSH ), - .lpszClassName = L"test", + .lpszClassName = L"pen-test", }; LONG_PTR old_proc; HANDLE thread; @@ -6967,6 +7258,11 @@ START_TEST(input) run_in_process( argv, "test_EnableMouseInPointer 1" ); } + if (!pGetPointerPenInfo) + win_skip( "GetPointerInfo not found, skipping tests\n" ); + else + test_GetPointerPenInfo(); + test_ClipCursor( argv ); run_in_desktop( argv, "test_system_messages_with_rawinput_nolegacy", 1 ); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11693
participants (2)
-
navi -
navi (@navi)