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