From: Paul Gofman pgofman@codeweavers.com
--- dlls/win32u/defwnd.c | 6 ++ dlls/win32u/input.c | 12 ++++ dlls/win32u/win32u_private.h | 1 + server/protocol.def | 8 +++ server/queue.c | 124 ++++++++++++++++++++++++++++++----- 5 files changed, 133 insertions(+), 18 deletions(-)
diff --git a/dlls/win32u/defwnd.c b/dlls/win32u/defwnd.c index 0cbb41d8604..83ad8fb983b 100644 --- a/dlls/win32u/defwnd.c +++ b/dlls/win32u/defwnd.c @@ -2732,6 +2732,12 @@ LRESULT default_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, f10_key = menu_sys_key = 0; break;
+ case WM_POINTERDOWN: + case WM_POINTERUP: + case WM_POINTERUPDATE: + update_mouse_state_from_pointer( hwnd, msg, GET_POINTERID_WPARAM( wparam ) ); + break; + case WM_KEYDOWN: if (wparam == VK_F10) f10_key = VK_F10; break; diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index ad4ba4d77c5..f464892cdc0 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2596,6 +2596,18 @@ BOOL WINAPI NtUserIsMouseInPointerEnabled(void) return FALSE; }
+void update_mouse_state_from_pointer( HWND hwnd, UINT msg, unsigned int pointer_id ) +{ + SERVER_START_REQ( track_mouse_from_pointer ) + { + req->win = wine_server_user_handle( hwnd ); + req->msg = msg; + req->pointer_id = pointer_id; + wine_server_call( req ); + } + SERVER_END_REQ; +} + static BOOL is_captured_by_system(void) { GUITHREADINFO info; diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index b4738ed6b16..7aec52ec964 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -104,6 +104,7 @@ extern void update_mouse_tracking_info( HWND hwnd ); extern BOOL process_wine_clipcursor( HWND hwnd, UINT flags, BOOL reset ); extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ); extern USHORT map_scan_to_kbd_vkey( USHORT scan, HKL layout ); +void update_mouse_state_from_pointer( HWND hwnd, UINT msg, unsigned int pointer_id );
/* menu.c */ extern UINT draw_nc_menu_bar( HDC hdc, RECT *rect, HWND hwnd ); diff --git a/server/protocol.def b/server/protocol.def index 4f712b4e4e6..48f812b2e04 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2311,6 +2311,14 @@ enum message_type #define SEND_HWMSG_INJECTED 0x01
+/* Control generating of mouse events from pointer events. */ +@REQ(track_mouse_from_pointer) + user_handle_t win; /* window handle */ + unsigned int msg; /* message code */ + unsigned int pointer_id; /* pointer 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 4ac6a670cd7..d6643072014 100644 --- a/server/queue.c +++ b/server/queue.c @@ -100,6 +100,15 @@ struct timer lparam_t lparam; /* lparam for message */ };
+struct pointer_state +{ + unsigned int pointer_id; /* id of pointer currently tracked, ~0u if none */ + user_handle_t pointer_win; /* pointer window */ + int button_msg_sent; /* mouse button message was already sent */ + int x; /* last seen pointer x coordinate */ + int y; /* last seen pointer y coordinate */ +}; + struct thread_input { struct object obj; /* object header */ @@ -108,6 +117,7 @@ struct thread_input int caret_state; /* caret on/off state */ struct list msg_list; /* list of hardware messages */ unsigned char desktop_keystate[256]; /* desktop keystate when keystate was synced */ + struct pointer_state pointer_state; const input_shm_t *shared; /* thread input in session shared memory */ };
@@ -250,6 +260,7 @@ static struct thread_input *create_thread_input( struct thread *thread ) { list_init( &input->msg_list ); input->shared = NULL; + input->pointer_state.pointer_id = ~0u;
if (!(input->desktop = get_thread_desktop( thread, 0 /* FIXME: access rights */ ))) { @@ -2567,19 +2578,25 @@ struct pointer user_handle_t win; int primary; union hw_input input; + int x; + int y; };
-static struct pointer *find_pointer_from_id( struct desktop *desktop, unsigned int id ) +static struct pointer *find_pointer_from_id( struct desktop *desktop, unsigned int id, int create ) { struct pointer *pointer;
LIST_FOR_EACH_ENTRY( pointer, &desktop->pointers, struct pointer, entry ) if (LOWORD(pointer->input.hw.wparam) == id) return pointer;
+ if (!create) return NULL; + pointer = mem_alloc( sizeof(struct pointer) ); pointer->timeout = NULL; pointer->desktop = desktop; pointer->primary = list_empty( &desktop->pointers ); + pointer->x = 0; + pointer->y = 0; list_add_tail( &desktop->pointers, &pointer->entry );
return pointer; @@ -2604,6 +2621,76 @@ static void queue_mouse_message_from_pointer( struct desktop *desktop, unsigned queue_hardware_message( desktop, msg, 1 ); }
+static void track_mouse_message_from_pointer( struct thread_input *input, unsigned int pointer_id, + unsigned int input_message ) +{ + struct pointer_state *state = &input->pointer_state; + struct desktop *desktop = input->desktop; + unsigned int time = get_tick_count(); + const desktop_shm_t *desktop_shm = desktop->shared; + struct pointer *pointer; + int pointer_moved; + + if (!input) return; + if (input_message == WM_POINTERUP) + { + /* hardware pointer might be destroyed at this moment so don't rely on its presence */ + if (pointer_id != state->pointer_id) return; + if (!state->button_msg_sent) + { + queue_mouse_message_from_pointer( desktop, WM_MOUSEMOVE, state->x, state->y, state->pointer_win, time ); + queue_mouse_message_from_pointer( desktop, WM_LBUTTONDOWN, state->x, state->y, state->pointer_win, time ); + } + else if (state->x != desktop_shm->cursor.x || state->y != desktop_shm->cursor.y) + { + queue_mouse_message_from_pointer( desktop, WM_MOUSEMOVE, state->x, state->y, state->pointer_win, time ); + } + queue_mouse_message_from_pointer( desktop, WM_LBUTTONUP, state->x, state->y, state->pointer_win, time ); + state->pointer_id = ~0u; + return; + } + + if (input_message != WM_POINTERDOWN && state->pointer_id != pointer_id) return; + + if (!(pointer = find_pointer_from_id( desktop, pointer_id, 0 ))) return; + if (input_message == WM_POINTERDOWN) + { + if (state->pointer_id != pointer_id && list_count( &desktop->pointers ) > 1) + { + if (!state->button_msg_sent) state->pointer_id = ~0u; + return; + } + state->pointer_id = pointer_id; + state->pointer_win = pointer->win; + state->x = pointer->x; + state->y = pointer->y; + state->button_msg_sent = 0; + return; + } + + if (input_message != WM_POINTERUPDATE) return; + state->pointer_win = pointer->win; + + pointer_moved = state->x != pointer->x || state->y != pointer->y; + + if (pointer_moved) + { + if (!state->button_msg_sent) + { + queue_mouse_message_from_pointer( desktop, WM_MOUSEMOVE, state->x, state->y, state->pointer_win, time ); + /* TODO: emulate right button and double clicks. */ + queue_mouse_message_from_pointer( desktop, WM_LBUTTONDOWN, state->x, state->y, state->pointer_win, time ); + state->button_msg_sent = 1; + } + state->x = pointer->x; + state->y = pointer->y; + } + if (pointer_moved || (state->button_msg_sent + && (state->x != desktop_shm->cursor.x || state->y != desktop_shm->cursor.y))) + queue_mouse_message_from_pointer( desktop, WM_MOUSEMOVE, state->x, state->y, state->pointer_win, time ); + return; +} + static void queue_pointer_message( struct pointer *pointer, int repeated );
static void pointer_message_timeout( void *private ) @@ -2625,40 +2712,33 @@ static void queue_pointer_message( struct pointer *pointer, int repeated ) const desktop_shm_t *desktop_shm = desktop->shared; const union hw_input *input = &pointer->input; unsigned int i, wparam = input->hw.wparam; - timeout_t time = get_tick_count(); - user_handle_t win = pointer->win; struct rectangle top_rect; 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; + pointer->x = LOWORD(input->hw.lparam) * (top_rect.right - top_rect.left) / 65535; + pointer->y = HIWORD(input->hw.lparam) * (top_rect.bottom - top_rect.top) / 65535;
if (pointer->primary) wparam |= POINTER_MESSAGE_FLAG_PRIMARY << 16;
for (i = 0; i < 2 && messages[input->hw.msg - WM_POINTERUPDATE][i]; i++) { - if (!(msg = alloc_hardware_message( 0, source, time, 0 ))) return; + if (!(msg = alloc_hardware_message( 0, source, get_tick_count(), 0 ))) return;
- msg->win = get_user_full_handle( win ); + msg->win = get_user_full_handle( pointer->win ); msg->msg = messages[input->hw.msg - WM_POINTERUPDATE][i]; msg->wparam = wparam; - msg->lparam = MAKELONG(x, y); + msg->lparam = MAKELONG(pointer->x, pointer->y); msg->x = desktop_shm->cursor.x; msg->y = desktop_shm->cursor.y;
queue_hardware_message( desktop, msg, 1 ); }
- if (!repeated && pointer->primary) - { - unsigned int message = WM_MOUSEMOVE; - if (input->hw.msg == WM_POINTERDOWN) message = WM_LBUTTONDOWN; - else if (input->hw.msg == WM_POINTERUP) message = WM_LBUTTONUP; - - queue_mouse_message_from_pointer( desktop, message, x, y, win, time ); - } + if (desktop->foreground_input + && desktop->foreground_input->pointer_state.pointer_id == LOWORD(pointer->input.hw.wparam) + && desktop->foreground_input->pointer_state.button_msg_sent) + track_mouse_message_from_pointer( desktop->foreground_input, LOWORD(pointer->input.hw.wparam), input->hw.msg );
if (input->hw.msg != WM_POINTERUP) { @@ -2707,7 +2787,7 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_
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) ); + pointer = find_pointer_from_id( desktop, LOWORD(input->hw.wparam), 1 ); if (pointer->timeout) remove_timeout_user( pointer->timeout ); pointer->input = *input; pointer->win = win; @@ -4270,3 +4350,11 @@ DECL_HANDLER(set_keyboard_repeat)
release_object( desktop ); } + +DECL_HANDLER(track_mouse_from_pointer) +{ + struct msg_queue *queue = get_current_queue(); + + if (queue && check_queue_input_window( queue, req->win )) + track_mouse_message_from_pointer( queue->input, req->pointer_id, req->msg ); +}