From c7efa293f0b35bdb86f2b472f5b7cef2a6ebcea9 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Wed, 2 Mar 2011 19:53:03 +0100 Subject: [PATCH] server: Invoke low-level hardware hooks directly from the server side. --- dlls/user32/message.c | 48 +++++++++++++ dlls/winex11.drv/keyboard.c | 9 --- dlls/winex11.drv/mouse.c | 105 ++++++----------------------- include/wine/server_protocol.h | 11 +-- server/hook.c | 11 +++ server/protocol.def | 8 ++- server/queue.c | 150 ++++++++++++++++++++++++++++++----------- server/request.h | 3 +- server/trace.c | 8 ++- server/user.h | 1 + 10 files changed, 211 insertions(+), 143 deletions(-) diff --git a/dlls/user32/message.c b/dlls/user32/message.c index 0095af39bb4..59f2e49799c 100644 --- a/dlls/user32/message.c +++ b/dlls/user32/message.c @@ -2709,6 +2709,38 @@ static BOOL peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags info.msg.lParam, msg_data->winevent.tid, info.msg.time); } continue; + case MSG_HOOK_LL: + info.flags = ISMEX_SEND; + result = 0; + if (info.msg.message == WH_KEYBOARD_LL && size >= sizeof(msg_data->hardware)) + { + KBDLLHOOKSTRUCT hook; + + hook.vkCode = LOWORD( info.msg.lParam ); + hook.scanCode = HIWORD( info.msg.lParam ); + hook.flags = msg_data->hardware.flags; + hook.time = info.msg.time; + hook.dwExtraInfo = msg_data->hardware.info; + TRACE( "calling keyboard LL hook vk %x scan %x flags %x time %u info %lx\n", + hook.vkCode, hook.scanCode, hook.flags, hook.time, hook.dwExtraInfo ); + result = HOOK_CallHooks( WH_KEYBOARD_LL, HC_ACTION, info.msg.wParam, (LPARAM)&hook, TRUE ); + } + else if (info.msg.message == WH_MOUSE_LL && size >= sizeof(msg_data->hardware)) + { + MSLLHOOKSTRUCT hook; + + hook.pt.x = msg_data->hardware.x; + hook.pt.y = msg_data->hardware.y; + hook.mouseData = info.msg.lParam; + hook.flags = msg_data->hardware.flags; + hook.time = info.msg.time; + hook.dwExtraInfo = msg_data->hardware.info; + TRACE( "calling mouse LL hook pos %d,%d data %x flags %x time %u info %lx\n", + hook.pt.x, hook.pt.y, hook.mouseData, hook.flags, hook.time, hook.dwExtraInfo ); + result = HOOK_CallHooks( WH_MOUSE_LL, HC_ACTION, info.msg.wParam, (LPARAM)&hook, TRUE ); + } + reply_message( &info, result, TRUE ); + continue; case MSG_OTHER_PROCESS: info.flags = ISMEX_SEND; if (!unpack_message( info.msg.hwnd, info.msg.message, &info.msg.wParam, @@ -3072,7 +3104,15 @@ static BOOL send_message( struct send_message_info *info, DWORD_PTR *res_ptr, BO */ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags ) { + struct send_message_info info; NTSTATUS ret; + BOOL wait; + + info.type = MSG_HARDWARE; + info.dest_tid = 0; + info.hwnd = hwnd; + info.flags = 0; + info.timeout = 0; SERVER_START_REQ( send_hardware_message ) { @@ -3102,8 +3142,16 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags ) break; } ret = wine_server_call( req ); + wait = reply->wait; } SERVER_END_REQ; + + if (wait) + { + LRESULT ignored; + wait_message_reply( 0 ); + retrieve_reply( &info, 0, &ignored ); + } return ret; } diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 6fc7bb06519..0d6230be371 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1155,7 +1155,6 @@ void X11DRV_send_keyboard_input( HWND hwnd, WORD wVk, WORD wScan, DWORD event_fl { UINT message; INPUT input; - KBDLLHOOKSTRUCT hook; WORD flags, wVkStripped, wVkL, wVkR, vk_hook = wVk; if (!time) time = GetTickCount(); @@ -1227,14 +1226,6 @@ void X11DRV_send_keyboard_input( HWND hwnd, WORD wVk, WORD wScan, DWORD event_fl if (event_flags & KEYEVENTF_UNICODE) vk_hook = wVk = VK_PACKET; - /* Hook gets whatever key was sent. */ - hook.vkCode = vk_hook; - hook.scanCode = wScan; - hook.flags = (flags >> 8) | injected_flags; - hook.time = time; - hook.dwExtraInfo = dwExtraInfo; - if (HOOK_CallHooks( WH_KEYBOARD_LL, HC_ACTION, message, (LPARAM)&hook, TRUE )) return; - input.type = INPUT_KEYBOARD; input.u.ki.wVk = vk_hook; input.u.ki.wScan = wScan; diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 2d71be51fae..23e9001feaf 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -293,7 +293,6 @@ void X11DRV_send_mouse_input( HWND hwnd, DWORD flags, DWORD x, DWORD y, { POINT pt; INPUT input; - MSLLHOOKSTRUCT hook; if (!time) time = GetTickCount(); @@ -308,34 +307,29 @@ void X11DRV_send_mouse_input( HWND hwnd, DWORD flags, DWORD x, DWORD y, { pt.x = x; pt.y = y; - wine_tsx11_lock(); - if (cursor_pos.x == x && cursor_pos.y == y && - (flags & ~(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE))) - flags &= ~MOUSEEVENTF_MOVE; - wine_tsx11_unlock(); } } else if (flags & MOUSEEVENTF_MOVE) { - int accel[3], xMult = 1, yMult = 1; + int accel[3]; /* dx and dy can be negative numbers for relative movements */ SystemParametersInfoW(SPI_GETMOUSE, 0, accel, 0); if (abs(x) > accel[0] && accel[2] != 0) { - xMult = 2; - if ((abs(x) > accel[1]) && (accel[2] == 2)) xMult = 4; + x = (int)x * 2; + if ((abs(x) > accel[1]) && (accel[2] == 2)) x = (int)x * 2; } if (abs(y) > accel[0] && accel[2] != 0) { - yMult = 2; - if ((abs(y) > accel[1]) && (accel[2] == 2)) yMult = 4; + y = (int)y * 2; + if ((abs(y) > accel[1]) && (accel[2] == 2)) y = (int)y * 2; } wine_tsx11_lock(); - pt.x = cursor_pos.x + (long)x * xMult; - pt.y = cursor_pos.y + (long)y * yMult; + pt.x = cursor_pos.x + x; + pt.y = cursor_pos.y + y; wine_tsx11_unlock(); } else @@ -345,85 +339,28 @@ void X11DRV_send_mouse_input( HWND hwnd, DWORD flags, DWORD x, DWORD y, wine_tsx11_unlock(); } - hook.pt.x = pt.x; - hook.pt.y = pt.y; - hook.mouseData = MAKELONG( 0, data ); - hook.flags = injected_flags; - hook.time = time; - hook.dwExtraInfo = extra_info; last_time_modified = GetTickCount(); - if (flags & MOUSEEVENTF_MOVE) - { - if (HOOK_CallHooks( WH_MOUSE_LL, HC_ACTION, WM_MOUSEMOVE, (LPARAM)&hook, TRUE )) return; - if ((injected_flags & LLMHF_INJECTED) && - ((flags & MOUSEEVENTF_ABSOLUTE) || x || y)) /* we have to actually move the cursor */ - { - clip_point_to_rect( &cursor_clip, &pt ); - X11DRV_SetCursorPos( pt.x, pt.y ); - } - else - { - wine_tsx11_lock(); - clip_point_to_rect( &cursor_clip, &pt); - cursor_pos = pt; - wine_tsx11_unlock(); - } - } - if (flags & MOUSEEVENTF_LEFTDOWN) - { - if (HOOK_CallHooks( WH_MOUSE_LL, HC_ACTION, - GetSystemMetrics(SM_SWAPBUTTON) ? WM_RBUTTONDOWN : WM_LBUTTONDOWN, - (LPARAM)&hook, TRUE )) return; - } - if (flags & MOUSEEVENTF_LEFTUP) - { - if (HOOK_CallHooks( WH_MOUSE_LL, HC_ACTION, - GetSystemMetrics(SM_SWAPBUTTON) ? WM_RBUTTONUP : WM_LBUTTONUP, - (LPARAM)&hook, TRUE )) return; - } - if (flags & MOUSEEVENTF_RIGHTDOWN) - { - if (HOOK_CallHooks( WH_MOUSE_LL, HC_ACTION, - GetSystemMetrics(SM_SWAPBUTTON) ? WM_LBUTTONDOWN : WM_RBUTTONDOWN, - (LPARAM)&hook, TRUE )) return; - } - if (flags & MOUSEEVENTF_RIGHTUP) - { - if (HOOK_CallHooks( WH_MOUSE_LL, HC_ACTION, - GetSystemMetrics(SM_SWAPBUTTON) ? WM_LBUTTONUP : WM_RBUTTONUP, - (LPARAM)&hook, TRUE )) return; - } - if (flags & MOUSEEVENTF_MIDDLEDOWN) - { - if (HOOK_CallHooks( WH_MOUSE_LL, HC_ACTION, WM_MBUTTONDOWN, (LPARAM)&hook, TRUE )) return; - } - if (flags & MOUSEEVENTF_MIDDLEUP) - { - if (HOOK_CallHooks( WH_MOUSE_LL, HC_ACTION, WM_MBUTTONUP, (LPARAM)&hook, TRUE )) return; - } - if (flags & MOUSEEVENTF_WHEEL) - { - if (HOOK_CallHooks( WH_MOUSE_LL, HC_ACTION, WM_MOUSEWHEEL, (LPARAM)&hook, TRUE )) return; - } - if (flags & MOUSEEVENTF_XDOWN) - { - if (HOOK_CallHooks( WH_MOUSE_LL, HC_ACTION, WM_XBUTTONDOWN, (LPARAM)&hook, TRUE )) return; - } - if (flags & MOUSEEVENTF_XUP) - { - if (HOOK_CallHooks( WH_MOUSE_LL, HC_ACTION, WM_XBUTTONUP, (LPARAM)&hook, TRUE )) return; - } - input.type = INPUT_MOUSE; - input.u.mi.dx = pt.x; - input.u.mi.dy = pt.y; + input.u.mi.dx = x; + input.u.mi.dy = y; input.u.mi.mouseData = data; - input.u.mi.dwFlags = flags | MOUSEEVENTF_ABSOLUTE; + input.u.mi.dwFlags = flags; input.u.mi.time = time; input.u.mi.dwExtraInfo = extra_info; __wine_send_input( hwnd, &input, (injected_flags & LLMHF_INJECTED) != 0 ); + + if (injected_flags & LLMHF_INJECTED) + { + if ((flags & MOUSEEVENTF_MOVE) && + ((flags & MOUSEEVENTF_ABSOLUTE) || x || y)) /* we have to actually move the cursor */ + { + GetCursorPos( &pt ); + if (!(flags & MOUSEEVENTF_ABSOLUTE) || pt.x != x || pt.y != y) + X11DRV_SetCursorPos( pt.x, pt.y ); + } + } } #ifdef SONAME_LIBXCURSOR diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 327acc487cb..82e95be41f9 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -283,7 +283,7 @@ struct hardware_msg_data int x; int y; unsigned int hw_id; - int __pad; + unsigned int flags; }; struct callback_msg_data @@ -2782,7 +2782,8 @@ enum message_type MSG_OTHER_PROCESS, MSG_POSTED, MSG_HARDWARE, - MSG_WINEVENT + MSG_WINEVENT, + MSG_HOOK_LL }; #define SEND_MSG_ABORT_IF_HUNG 0x01 @@ -2794,11 +2795,13 @@ struct send_hardware_message_request user_handle_t win; hw_input_t input; unsigned int flags; - unsigned int msg; + char __pad_52[4]; }; struct send_hardware_message_reply { struct reply_header __header; + int wait; + char __pad_12[4]; }; #define SEND_HWMSG_INJECTED 0x01 @@ -5556,6 +5559,6 @@ union generic_reply struct set_cursor_reply set_cursor_reply; }; -#define SERVER_PROTOCOL_VERSION 416 +#define SERVER_PROTOCOL_VERSION 417 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/hook.c b/server/hook.c index 7c0ae0f2d9f..c9df5d37d39 100644 --- a/server/hook.c +++ b/server/hook.c @@ -369,6 +369,17 @@ unsigned int get_active_hooks(void) return ret; } +/* return the thread that owns the first global hook */ +struct thread *get_first_global_hook( int id ) +{ + struct hook *hook; + struct hook_table *global_hooks = get_global_hooks( current ); + + if (!global_hooks) return NULL; + if (!(hook = get_first_valid_hook( global_hooks, id - WH_MINHOOK, EVENT_MIN, 0, 0, 0 ))) return NULL; + return hook->owner; +} + /* set a window hook */ DECL_HANDLER(set_hook) { diff --git a/server/protocol.def b/server/protocol.def index 593ce4ec119..aaaebc0080a 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -299,7 +299,7 @@ struct hardware_msg_data int x; /* x position */ int y; /* y position */ unsigned int hw_id; /* unique id */ - int __pad; + unsigned int flags; /* hook flags */ }; struct callback_msg_data @@ -2024,7 +2024,8 @@ enum message_type MSG_OTHER_PROCESS, /* sent from other process, may include vararg data, always Unicode */ MSG_POSTED, /* posted message (from PostMessageW), always Unicode */ MSG_HARDWARE, /* hardware message */ - MSG_WINEVENT /* winevent message */ + MSG_WINEVENT, /* winevent message */ + MSG_HOOK_LL /* low-level hardware hook */ }; #define SEND_MSG_ABORT_IF_HUNG 0x01 @@ -2034,7 +2035,8 @@ enum message_type user_handle_t win; /* window handle */ hw_input_t input; /* input data */ unsigned int flags; /* flags (see below) */ - unsigned int msg; /* message code */ +@REPLY + int wait; /* do we need to wait for a reply? */ @END #define SEND_HWMSG_INJECTED 0x01 diff --git a/server/queue.c b/server/queue.c index 13e3f47e180..d1aa7153402 100644 --- a/server/queue.c +++ b/server/queue.c @@ -58,6 +58,8 @@ struct message_result int replied; /* has it been replied to? */ unsigned int error; /* error code to pass back to sender */ lparam_t result; /* reply result */ + struct message *hardware_msg; /* hardware message if low-level hook result */ + struct desktop *desktop; /* desktop for hardware message */ struct message *callback_msg; /* message to queue for callback */ void *data; /* message reply data */ unsigned int data_size; /* size of message reply data */ @@ -201,6 +203,7 @@ static const struct object_ops thread_input_ops = /* pointer to input structure of foreground thread */ static unsigned int last_input_time; +static void queue_hardware_message( struct desktop *desktop, struct message *msg ); static void free_message( struct message *msg ); /* set the caret window in a given thread input */ @@ -436,6 +439,8 @@ static void free_result( struct message_result *result ) if (result->timeout) remove_timeout_user( result->timeout ); free( result->data ); if (result->callback_msg) free_message( result->callback_msg ); + if (result->hardware_msg) free_message( result->hardware_msg ); + if (result->desktop) release_object( result->desktop ); free( result ); } @@ -460,6 +465,17 @@ static void store_message_result( struct message_result *res, lparam_t result, u remove_timeout_user( res->timeout ); res->timeout = NULL; } + + if (res->hardware_msg) + { + if (!error && result) /* rejected by the hook */ + free_message( res->hardware_msg ); + else + queue_hardware_message( res->desktop, res->hardware_msg ); + + res->hardware_msg = NULL; + } + if (res->sender) { if (res->callback_msg) @@ -479,7 +495,7 @@ static void store_message_result( struct message_result *res, lparam_t result, u set_queue_bits( res->sender, QS_SMRESULT ); } } - + else if (!res->receiver) free_result( res ); } /* free a message when deleting a queue or window */ @@ -489,12 +505,8 @@ static void free_message( struct message *msg ) if (result) { result->msg = NULL; - if (result->sender) - { - result->receiver = NULL; - store_message_result( result, 0, STATUS_ACCESS_DENIED /*FIXME*/ ); - } - else free_result( result ); + result->receiver = NULL; + store_message_result( result, 0, STATUS_ACCESS_DENIED /*FIXME*/ ); } free( msg->data ); free( msg ); @@ -535,13 +547,7 @@ static void result_timeout( void *private ) msg->result = NULL; remove_queue_message( result->receiver, msg, SEND_MESSAGE ); result->receiver = NULL; - if (!result->sender) - { - free_result( result ); - return; - } } - store_message_result( result, 0, STATUS_TIMEOUT ); } @@ -553,13 +559,16 @@ static struct message_result *alloc_message_result( struct msg_queue *send_queue struct message_result *result = mem_alloc( sizeof(*result) ); if (result) { - result->msg = msg; - result->sender = send_queue; - result->receiver = recv_queue; - result->replied = 0; - result->data = NULL; - result->data_size = 0; - result->timeout = NULL; + result->msg = msg; + result->sender = send_queue; + result->receiver = recv_queue; + result->replied = 0; + result->data = NULL; + result->data_size = 0; + result->timeout = NULL; + result->hardware_msg = NULL; + result->desktop = NULL; + result->callback_msg = NULL; if (msg->type == MSG_CALLBACK) { @@ -586,11 +595,7 @@ static struct message_result *alloc_message_result( struct msg_queue *send_queue result->callback_msg = callback_msg; list_add_head( &send_queue->callback_result, &result->sender_entry ); } - else - { - result->callback_msg = NULL; - list_add_head( &send_queue->send_result, &result->sender_entry ); - } + else if (send_queue) list_add_head( &send_queue->send_result, &result->sender_entry ); if (timeout != TIMEOUT_INFINITE) result->timeout = add_timeout_user( timeout, result_timeout, result ); @@ -641,7 +646,7 @@ static void reply_message( struct msg_queue *queue, lparam_t result, { queue->recv_result = res->recv_next; res->receiver = NULL; - if (!res->sender) /* no one waiting for it */ + if (!res->sender && !res->hardware_msg) /* no one waiting for it */ { free_result( res ); return; @@ -1328,13 +1333,58 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg release_object( thread ); } +/* send the low-level hook message for a given hardware message */ +static int send_hook_ll_message( struct desktop *desktop, struct message *hardware_msg, + const hw_input_t *input, struct msg_queue *sender ) +{ + struct thread *hook_thread; + struct msg_queue *queue; + struct message *msg; + timeout_t timeout = 2000 * -10000; /* FIXME: load from registry */ + int id = (input->type == INPUT_MOUSE) ? WH_MOUSE_LL : WH_KEYBOARD_LL; + + if (!(hook_thread = get_first_global_hook( id ))) return 0; + if (!(queue = hook_thread->queue)) return 0; + + if (!(msg = mem_alloc( sizeof(*msg) ))) return 0; + + msg->type = MSG_HOOK_LL; + msg->win = 0; + msg->msg = id; + msg->wparam = hardware_msg->msg; + msg->time = hardware_msg->time; + msg->data_size = hardware_msg->data_size; + msg->result = NULL; + + if (input->type == INPUT_KEYBOARD) + { + unsigned short vkey = input->kbd.vkey; + if (input->kbd.flags & KEYEVENTF_UNICODE) vkey = VK_PACKET; + msg->lparam = (input->kbd.scan << 16) | vkey; + } + else msg->lparam = input->mouse.data; + + if (!(msg->data = memdup( hardware_msg->data, hardware_msg->data_size )) || + !(msg->result = alloc_message_result( sender, queue, msg, timeout ))) + { + free_message( msg ); + return 0; + } + msg->result->hardware_msg = hardware_msg; + msg->result->desktop = (struct desktop *)grab_object( desktop ); + list_add_tail( &queue->msg_list[SEND_MESSAGE], &msg->entry ); + set_queue_bits( queue, QS_SENDMESSAGE ); + return 1; +} + /* queue a hardware message for a mouse event */ -static void queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input ) +static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, + unsigned int hook_flags, struct msg_queue *sender ) { struct hardware_msg_data *msg_data; struct message *msg; unsigned int i, time, flags; - int x, y; + int wait = 0, x, y; static const unsigned int messages[] = { @@ -1383,12 +1433,13 @@ static void queue_mouse_message( struct desktop *desktop, user_handle_t win, con { if (!messages[i]) continue; if (!(flags & (1 << i))) continue; + flags &= ~(1 << i); - if (!(msg = mem_alloc( sizeof(*msg) ))) return; + if (!(msg = mem_alloc( sizeof(*msg) ))) return 0; if (!(msg_data = mem_alloc( sizeof(*msg_data) ))) { free( msg ); - return; + return 0; } memset( msg_data, 0, sizeof(*msg_data) ); @@ -1404,23 +1455,34 @@ static void queue_mouse_message( struct desktop *desktop, user_handle_t win, con msg_data->x = x; msg_data->y = y; msg_data->info = input->mouse.info; + if (hook_flags & SEND_HWMSG_INJECTED) msg_data->flags = LLMHF_INJECTED; - queue_hardware_message( desktop, msg ); + /* specify a sender only when sending the last message */ + if (!(flags & ((1 << sizeof(messages)/sizeof(messages[0])) - 1))) + { + if (!(wait = send_hook_ll_message( desktop, msg, input, sender ))) + queue_hardware_message( desktop, msg ); + } + else if (!send_hook_ll_message( desktop, msg, input, NULL )) + queue_hardware_message( desktop, msg ); } + return wait; } /* queue a hardware message for a keyboard event */ -static void queue_keyboard_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input ) +static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, + unsigned int hook_flags, struct msg_queue *sender ) { struct hardware_msg_data *msg_data; struct message *msg; unsigned char vkey = input->kbd.vkey; + int wait; - if (!(msg = mem_alloc( sizeof(*msg) ))) return; + if (!(msg = mem_alloc( sizeof(*msg) ))) return 0; if (!(msg_data = mem_alloc( sizeof(*msg_data) ))) { free( msg ); - return; + return 0; } memset( msg_data, 0, sizeof(*msg_data) ); @@ -1433,6 +1495,7 @@ static void queue_keyboard_message( struct desktop *desktop, user_handle_t win, msg->data_size = sizeof(*msg_data); msg_data->info = input->kbd.info; if (!msg->time) msg->time = get_tick_count(); + if (hook_flags & SEND_HWMSG_INJECTED) msg_data->flags = LLKHF_INJECTED; if (input->kbd.flags & KEYEVENTF_UNICODE) { @@ -1440,6 +1503,7 @@ static void queue_keyboard_message( struct desktop *desktop, user_handle_t win, } else { + unsigned int flags = 0; switch (vkey) { case VK_MENU: @@ -1458,12 +1522,14 @@ static void queue_keyboard_message( struct desktop *desktop, user_handle_t win, vkey = (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) ? VK_RSHIFT : VK_LSHIFT; break; } - if (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) msg->lparam |= KF_EXTENDED << 16; + if (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) flags |= KF_EXTENDED; /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */ - if (input->kbd.flags & KEYEVENTF_KEYUP) msg->lparam |= (KF_REPEAT | KF_UP) << 16; - else if (desktop->keystate[vkey] & 0x80) msg->lparam |= KF_REPEAT << 16; + if (input->kbd.flags & KEYEVENTF_KEYUP) flags |= KF_REPEAT | KF_UP; + else if (desktop->keystate[vkey] & 0x80) flags |= KF_REPEAT; msg->wparam = vkey; + msg->lparam |= flags << 16; + msg_data->flags |= (flags & (KF_EXTENDED | KF_ALTDOWN | KF_UP)) >> 8; } msg->msg = (input->kbd.flags & KEYEVENTF_KEYUP) ? WM_KEYUP : WM_KEYDOWN; @@ -1508,8 +1574,10 @@ static void queue_keyboard_message( struct desktop *desktop, user_handle_t win, desktop->keystate[VK_MENU] &= ~0x02; break; } + if (!(wait = send_hook_ll_message( desktop, msg, input, sender ))) + queue_hardware_message( desktop, msg ); - queue_hardware_message( desktop, msg ); + return wait; } /* queue a hardware message for a custom type of event */ @@ -1941,6 +2009,7 @@ DECL_HANDLER(send_message) break; case MSG_HARDWARE: /* should use send_hardware_message instead */ case MSG_CALLBACK_RESULT: /* cannot send this one */ + case MSG_HOOK_LL: /* generated internally */ default: set_error( STATUS_INVALID_PARAMETER ); free( msg ); @@ -1955,6 +2024,7 @@ DECL_HANDLER(send_hardware_message) { struct thread *thread = NULL; struct desktop *desktop; + struct msg_queue *sender = get_current_queue(); if (req->win) { @@ -1966,10 +2036,10 @@ DECL_HANDLER(send_hardware_message) switch (req->input.type) { case INPUT_MOUSE: - queue_mouse_message( desktop, req->win, &req->input ); + reply->wait = queue_mouse_message( desktop, req->win, &req->input, req->flags, sender ); break; case INPUT_KEYBOARD: - queue_keyboard_message( desktop, req->win, &req->input ); + reply->wait = queue_keyboard_message( desktop, req->win, &req->input, req->flags, sender ); break; case INPUT_HARDWARE: queue_custom_hardware_message( desktop, req->win, &req->input ); diff --git a/server/request.h b/server/request.h index 780c2ebef3b..47733a53b47 100644 --- a/server/request.h +++ b/server/request.h @@ -1381,8 +1381,9 @@ C_ASSERT( sizeof(struct post_quit_message_request) == 16 ); C_ASSERT( FIELD_OFFSET(struct send_hardware_message_request, win) == 12 ); C_ASSERT( FIELD_OFFSET(struct send_hardware_message_request, input) == 16 ); C_ASSERT( FIELD_OFFSET(struct send_hardware_message_request, flags) == 48 ); -C_ASSERT( FIELD_OFFSET(struct send_hardware_message_request, msg) == 52 ); C_ASSERT( sizeof(struct send_hardware_message_request) == 56 ); +C_ASSERT( FIELD_OFFSET(struct send_hardware_message_reply, wait) == 8 ); +C_ASSERT( sizeof(struct send_hardware_message_reply) == 16 ); C_ASSERT( FIELD_OFFSET(struct get_message_request, flags) == 12 ); C_ASSERT( FIELD_OFFSET(struct get_message_request, get_win) == 16 ); C_ASSERT( FIELD_OFFSET(struct get_message_request, get_first) == 20 ); diff --git a/server/trace.c b/server/trace.c index e39780e8c11..0933cf17259 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2496,7 +2496,11 @@ static void dump_send_hardware_message_request( const struct send_hardware_messa fprintf( stderr, " win=%08x", req->win ); dump_hw_input( ", input=", &req->input ); fprintf( stderr, ", flags=%08x", req->flags ); - fprintf( stderr, ", msg=%08x", req->msg ); +} + +static void dump_send_hardware_message_reply( const struct send_hardware_message_reply *req ) +{ + fprintf( stderr, " wait=%d", req->wait ); } static void dump_get_message_request( const struct get_message_request *req ) @@ -4275,7 +4279,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_get_process_idle_event_reply, NULL, NULL, - NULL, + (dump_func)dump_send_hardware_message_reply, (dump_func)dump_get_message_reply, NULL, NULL, diff --git a/server/user.h b/server/user.h index 5d7bec8b911..b8da053fbaa 100644 --- a/server/user.h +++ b/server/user.h @@ -87,6 +87,7 @@ extern void cleanup_clipboard_thread( struct thread *thread ); extern void remove_thread_hooks( struct thread *thread ); extern unsigned int get_active_hooks(void); +extern struct thread *get_first_global_hook( int id ); /* queue functions */ -- 2.11.4.GIT