This is an early draft of an implementation of key auto-repeat in wineserver to get some feedback. Some open questions:
1. queue_keyboard_message requires a `current` thread, but we don't get one in timeout callbacks. At the moment I am manually setting `current` to the foreground thread, but I am wondering if that's acceptable or we should explore other ways forward (also see TODO in code).
2. This draft introduces a new server request to configure auto-repeat (`enable/delay/period`). I am thinking that for more straightforward integration with the keyboard repeat SPI parameters, the request should only support the `enable` flag and the server should query the SPI registry values to get `delay` and `period` when needed. I am wondering if there any caveats here since I don't see other code in the server querying registry values (well, except to implement the registry requests themselves). Also, I would hope that opening and caching the `HKCU\Control Panel\Keyboard` hkey would remove most of the cost of performing this operation (if that's even a concern at all).
-- v5: win32u: Implement keyboard auto-repeat using new server request. server: Implement key auto-repeat request.
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- server/hook.c | 4 ++-- server/queue.c | 2 +- server/user.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/server/hook.c b/server/hook.c index 5abdf39ad37..c22e3748b8b 100644 --- a/server/hook.c +++ b/server/hook.c @@ -372,10 +372,10 @@ unsigned int get_active_hooks(void) }
/* return the thread that owns the first global hook */ -struct thread *get_first_global_hook( int id ) +struct thread *get_first_global_hook( struct desktop *desktop, int id ) { struct hook *hook; - struct hook_table *global_hooks = get_global_hooks( current ); + struct hook_table *global_hooks = desktop->global_hooks;
if (!global_hooks) return NULL; if (!(hook = get_first_valid_hook( global_hooks, id - WH_MINHOOK, EVENT_MIN, 0, 0, 0 ))) return NULL; diff --git a/server/queue.c b/server/queue.c index e881e40271d..2e9460e4c0a 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1745,7 +1745,7 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa struct message *msg; timeout_t timeout = 2000 * -10000; /* FIXME: load from registry */
- if (!(hook_thread = get_first_global_hook( id ))) return 0; + if (!(hook_thread = get_first_global_hook( desktop, id ))) return 0; if (!(queue = hook_thread->queue)) return 0; if (is_queue_hung( queue )) return 0;
diff --git a/server/user.h b/server/user.h index d805a179d16..e3a14466c9d 100644 --- a/server/user.h +++ b/server/user.h @@ -103,7 +103,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 ); +extern struct thread *get_first_global_hook( struct desktop *desktop, int id );
/* queue functions */
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- server/queue.c | 56 ++++++++++++++++---------------------------------- 1 file changed, 18 insertions(+), 38 deletions(-)
diff --git a/server/queue.c b/server/queue.c index 2e9460e4c0a..2c30f16b712 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1522,27 +1522,6 @@ static void update_input_key_state( struct desktop *desktop, unsigned char *keys } }
-/* update the desktop key state according to a mouse message flags */ -static void update_desktop_mouse_state( struct desktop *desktop, unsigned int flags, lparam_t wparam ) -{ - if (flags & MOUSEEVENTF_LEFTDOWN) - update_input_key_state( desktop, desktop->keystate, WM_LBUTTONDOWN, wparam ); - if (flags & MOUSEEVENTF_LEFTUP) - update_input_key_state( desktop, desktop->keystate, WM_LBUTTONUP, wparam ); - if (flags & MOUSEEVENTF_RIGHTDOWN) - update_input_key_state( desktop, desktop->keystate, WM_RBUTTONDOWN, wparam ); - if (flags & MOUSEEVENTF_RIGHTUP) - update_input_key_state( desktop, desktop->keystate, WM_RBUTTONUP, wparam ); - if (flags & MOUSEEVENTF_MIDDLEDOWN) - update_input_key_state( desktop, desktop->keystate, WM_MBUTTONDOWN, wparam ); - if (flags & MOUSEEVENTF_MIDDLEUP) - update_input_key_state( desktop, desktop->keystate, WM_MBUTTONUP, wparam ); - if (flags & MOUSEEVENTF_XDOWN) - update_input_key_state( desktop, desktop->keystate, WM_XBUTTONDOWN, wparam ); - if (flags & MOUSEEVENTF_XUP) - update_input_key_state( desktop, desktop->keystate, WM_XBUTTONUP, wparam ); -} - /* release the hardware message currently being processed by the given thread */ static void release_hardware_message( struct msg_queue *queue, unsigned int hw_id ) { @@ -1671,6 +1650,19 @@ static void prepend_cursor_history( int x, int y, unsigned int time, lparam_t in pos->info = info; }
+static unsigned int get_rawinput_device_flags( struct process *process, struct message *msg ) +{ + switch (get_hardware_msg_bit( msg->msg )) + { + case QS_KEY: + return process->rawinput_kbd ? process->rawinput_kbd->flags : 0; + case QS_MOUSEMOVE: + case QS_MOUSEBUTTON: + return process->rawinput_mouse ? process->rawinput_mouse->flags : 0; + } + return 0; +} + /* queue a hardware message into a given thread input */ static void queue_hardware_message( struct desktop *desktop, struct message *msg, int always_queue ) { @@ -1679,6 +1671,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg struct thread_input *input; struct hardware_msg_data *msg_data = msg->data; unsigned int msg_code; + int flags;
update_input_key_state( desktop, desktop->keystate, msg->msg, msg->wparam ); last_input_time = get_tick_count(); @@ -1717,12 +1710,14 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg else input = desktop->foreground_input;
win = find_hardware_message_window( desktop, input, msg, &msg_code, &thread ); - if (!win || !thread) + flags = thread ? get_rawinput_device_flags( thread->process, msg ) : 0; + if (!win || !thread || (flags & RIDEV_NOLEGACY)) { - if (input) update_input_key_state( input->desktop, input->keystate, msg->msg, msg->wparam ); + if (input && !(flags & RIDEV_NOLEGACY)) update_input_key_state( input->desktop, input->keystate, msg->msg, msg->wparam ); free_message( msg ); return; } + input = thread->queue->input;
if (win != msg->win) always_queue = 1; @@ -1981,7 +1976,6 @@ static void dispatch_rawinput_message( struct desktop *desktop, struct rawinput_ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, unsigned int origin, struct msg_queue *sender ) { - const struct rawinput_device *device; struct hardware_msg_data *msg_data; struct rawinput_message raw_msg; struct message *msg; @@ -2050,13 +2044,6 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons release_object( foreground ); }
- if ((device = current->process->rawinput_mouse) && (device->flags & RIDEV_NOLEGACY)) - { - if (flags & MOUSEEVENTF_MOVE) update_desktop_cursor_pos( desktop, win, x, y ); - update_desktop_mouse_state( desktop, flags, wparam ); - return 0; - } - for (i = 0; i < ARRAY_SIZE( messages ); i++) { if (!messages[i]) continue; @@ -2091,7 +2078,6 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c unsigned int origin, struct msg_queue *sender ) { struct hw_msg_source source = { IMDT_KEYBOARD, origin }; - const struct rawinput_device *device; struct hardware_msg_data *msg_data; struct message *msg; struct thread *foreground; @@ -2207,12 +2193,6 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c release_object( foreground ); }
- if ((device = current->process->rawinput_kbd) && (device->flags & RIDEV_NOLEGACY)) - { - update_input_key_state( desktop, desktop->keystate, message_code, vkey ); - return 0; - } - if (!(msg = alloc_hardware_message( input->kbd.info, source, time, 0 ))) return 0; msg_data = msg->data;
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- include/wine/server_protocol.h | 21 +++++++++++- server/protocol.def | 10 ++++++ server/queue.c | 63 ++++++++++++++++++++++++++++++++-- server/request.h | 8 +++++ server/trace.c | 15 ++++++++ server/user.h | 11 ++++++ server/winstation.c | 2 ++ 7 files changed, 127 insertions(+), 3 deletions(-)
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index e08f656f882..826b04afb13 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -5638,6 +5638,22 @@ struct get_next_thread_reply };
+ +struct set_keyboard_repeat_request +{ + struct request_header __header; + int enable; + int delay; + int period; +}; +struct set_keyboard_repeat_reply +{ + struct reply_header __header; + int enable; + char __pad_12[4]; +}; + + enum request { REQ_new_process, @@ -5924,6 +5940,7 @@ enum request REQ_suspend_process, REQ_resume_process, REQ_get_next_thread, + REQ_set_keyboard_repeat, REQ_NB_REQUESTS };
@@ -6215,6 +6232,7 @@ union generic_request struct suspend_process_request suspend_process_request; struct resume_process_request resume_process_request; struct get_next_thread_request get_next_thread_request; + struct set_keyboard_repeat_request set_keyboard_repeat_request; }; union generic_reply { @@ -6504,11 +6522,12 @@ union generic_reply struct suspend_process_reply suspend_process_reply; struct resume_process_reply resume_process_reply; struct get_next_thread_reply get_next_thread_reply; + struct set_keyboard_repeat_reply set_keyboard_repeat_reply; };
/* ### protocol_version begin ### */
-#define SERVER_PROTOCOL_VERSION 803 +#define SERVER_PROTOCOL_VERSION 804
/* ### protocol_version end ### */
diff --git a/server/protocol.def b/server/protocol.def index ac103156fe4..2b3279069ae 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3877,3 +3877,13 @@ struct handle_info @REPLY obj_handle_t handle; /* next thread handle */ @END + + +/* Setup keyboard auto-repeat */ +@REQ(set_keyboard_repeat) + int enable; /* whether to enable auto-repeat */ + int delay; /* auto-repeat delay in ms */ + int period; /* auto-repeat period in ms */ +@REPLY + int enable; /* previous state of auto-repeat enable */ +@END diff --git a/server/queue.c b/server/queue.c index 2c30f16b712..c536e0a6539 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2073,9 +2073,20 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons return wait; }
+static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, + unsigned int origin, struct msg_queue *sender, int repeat ); + +static void key_repeat_timeout( void *private ) +{ + struct desktop *desktop = private; + + desktop->key_repeat.timeout = NULL; + queue_keyboard_message( desktop, desktop->key_repeat.win, &desktop->key_repeat.input, IMO_HARDWARE, NULL, 1 ); +} + /* queue a hardware message for a keyboard event */ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, - unsigned int origin, struct msg_queue *sender ) + unsigned int origin, struct msg_queue *sender, int repeat ) { struct hw_msg_source source = { IMDT_KEYBOARD, origin }; struct hardware_msg_data *msg_data; @@ -2178,6 +2189,29 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c } }
+ if (origin == IMO_HARDWARE) + { + /* if the repeat key is released, stop auto-repeating */ + if (((input->kbd.flags & KEYEVENTF_KEYUP) && + (input->kbd.scan == desktop->key_repeat.input.kbd.scan))) + { + if (desktop->key_repeat.timeout) remove_timeout_user( desktop->key_repeat.timeout ); + desktop->key_repeat.timeout = NULL; + desktop->key_repeat.win = 0; + memset( &desktop->key_repeat.input, 0, sizeof(desktop->key_repeat.input) ); + } + /* if a key is down, start or continue auto-repeating */ + if (!(input->kbd.flags & KEYEVENTF_KEYUP) && desktop->key_repeat.enable) + { + timeout_t timeout = repeat ? desktop->key_repeat.period : desktop->key_repeat.delay; + desktop->key_repeat.input = *input; + desktop->key_repeat.input.kbd.time = 0; + desktop->key_repeat.win = win; + if (desktop->key_repeat.timeout) remove_timeout_user( desktop->key_repeat.timeout ); + desktop->key_repeat.timeout = add_timeout_user( timeout, key_repeat_timeout, desktop ); + } + } + if (!unicode && (foreground = get_foreground_thread( desktop, win ))) { struct rawinput_message raw_msg = {0}; @@ -2939,7 +2973,7 @@ DECL_HANDLER(send_hardware_message) wait = queue_mouse_message( desktop, req->win, &req->input, origin, sender ); break; case INPUT_KEYBOARD: - wait = queue_keyboard_message( desktop, req->win, &req->input, origin, sender ); + wait = queue_keyboard_message( desktop, req->win, &req->input, origin, sender, 0 ); break; case INPUT_HARDWARE: queue_custom_hardware_message( desktop, req->win, origin, &req->input ); @@ -3813,3 +3847,28 @@ DECL_HANDLER(update_rawinput_devices) release_object( desktop ); } } + +DECL_HANDLER(set_keyboard_repeat) +{ + struct desktop *desktop; + + if (!(desktop = get_thread_desktop( current, 0 ))) return; + + /* report previous values */ + reply->enable = desktop->key_repeat.enable; + + /* ignore negative values to allow partial updates */ + if (req->enable >= 0) desktop->key_repeat.enable = req->enable; + if (req->delay >= 0) desktop->key_repeat.delay = -req->delay * 10000; + if (req->period >= 0) desktop->key_repeat.period = -req->period * 10000; + + if (!desktop->key_repeat.enable) + { + if (desktop->key_repeat.timeout) remove_timeout_user( desktop->key_repeat.timeout ); + desktop->key_repeat.timeout = NULL; + desktop->key_repeat.win = 0; + memset( &desktop->key_repeat.input, 0, sizeof(desktop->key_repeat.input) ); + } + + release_object( desktop ); +} diff --git a/server/request.h b/server/request.h index 327c6168241..4d5a692244c 100644 --- a/server/request.h +++ b/server/request.h @@ -403,6 +403,7 @@ DECL_HANDLER(terminate_job); DECL_HANDLER(suspend_process); DECL_HANDLER(resume_process); DECL_HANDLER(get_next_thread); +DECL_HANDLER(set_keyboard_repeat);
#ifdef WANT_REQUEST_HANDLERS
@@ -693,6 +694,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_suspend_process, (req_handler)req_resume_process, (req_handler)req_get_next_thread, + (req_handler)req_set_keyboard_repeat, };
C_ASSERT( sizeof(abstime_t) == 8 ); @@ -2335,6 +2337,12 @@ C_ASSERT( FIELD_OFFSET(struct get_next_thread_request, flags) == 28 ); C_ASSERT( sizeof(struct get_next_thread_request) == 32 ); C_ASSERT( FIELD_OFFSET(struct get_next_thread_reply, handle) == 8 ); C_ASSERT( sizeof(struct get_next_thread_reply) == 16 ); +C_ASSERT( FIELD_OFFSET(struct set_keyboard_repeat_request, enable) == 12 ); +C_ASSERT( FIELD_OFFSET(struct set_keyboard_repeat_request, delay) == 16 ); +C_ASSERT( FIELD_OFFSET(struct set_keyboard_repeat_request, period) == 20 ); +C_ASSERT( sizeof(struct set_keyboard_repeat_request) == 24 ); +C_ASSERT( FIELD_OFFSET(struct set_keyboard_repeat_reply, enable) == 8 ); +C_ASSERT( sizeof(struct set_keyboard_repeat_reply) == 16 );
#endif /* WANT_REQUEST_HANDLERS */
diff --git a/server/trace.c b/server/trace.c index a68577763e7..866fb80f050 100644 --- a/server/trace.c +++ b/server/trace.c @@ -4590,6 +4590,18 @@ static void dump_get_next_thread_reply( const struct get_next_thread_reply *req fprintf( stderr, " handle=%04x", req->handle ); }
+static void dump_set_keyboard_repeat_request( const struct set_keyboard_repeat_request *req ) +{ + fprintf( stderr, " enable=%d", req->enable ); + fprintf( stderr, ", delay=%d", req->delay ); + fprintf( stderr, ", period=%d", req->period ); +} + +static void dump_set_keyboard_repeat_reply( const struct set_keyboard_repeat_reply *req ) +{ + fprintf( stderr, " enable=%d", req->enable ); +} + static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_new_process_request, (dump_func)dump_get_new_process_info_request, @@ -4875,6 +4887,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_suspend_process_request, (dump_func)dump_resume_process_request, (dump_func)dump_get_next_thread_request, + (dump_func)dump_set_keyboard_repeat_request, };
static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { @@ -5162,6 +5175,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { NULL, NULL, (dump_func)dump_get_next_thread_reply, + (dump_func)dump_set_keyboard_repeat_reply, };
static const char * const req_names[REQ_NB_REQUESTS] = { @@ -5449,6 +5463,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "suspend_process", "resume_process", "get_next_thread", + "set_keyboard_repeat", };
static const struct diff --git a/server/user.h b/server/user.h index e3a14466c9d..0a79897916d 100644 --- a/server/user.h +++ b/server/user.h @@ -64,6 +64,16 @@ struct global_cursor user_handle_t win; /* window that contains the cursor */ };
+struct key_repeat +{ + int enable; /* enable auto-repeat */ + timeout_t delay; /* auto-repeat delay */ + timeout_t period; /* auto-repeat period */ + hw_input_t input; /* the input to repeat */ + user_handle_t win; /* target window for input event */ + struct timeout_user *timeout; /* timeout for repeat */ +}; + struct desktop { struct object obj; /* object header */ @@ -82,6 +92,7 @@ struct desktop unsigned int users; /* processes and threads using this desktop */ struct global_cursor cursor; /* global cursor information */ unsigned char keystate[256]; /* asynchronous key state */ + struct key_repeat key_repeat; /* key auto-repeat */ };
/* user handles functions */ diff --git a/server/winstation.c b/server/winstation.c index 80126ad5d60..66fb6ad1e35 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -294,6 +294,7 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned list_init( &desktop->threads ); memset( &desktop->cursor, 0, sizeof(desktop->cursor) ); memset( desktop->keystate, 0, sizeof(desktop->keystate) ); + memset( &desktop->key_repeat, 0, sizeof(desktop->key_repeat) ); list_add_tail( &winstation->desktops, &desktop->entry ); list_init( &desktop->hotkeys ); list_init( &desktop->pointers ); @@ -365,6 +366,7 @@ static void desktop_destroy( struct object *obj ) if (desktop->msg_window) free_window_handle( desktop->msg_window ); if (desktop->global_hooks) release_object( desktop->global_hooks ); if (desktop->close_timeout) remove_timeout_user( desktop->close_timeout ); + if (desktop->key_repeat.timeout) remove_timeout_user( desktop->key_repeat.timeout ); release_object( desktop->winstation ); }
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/win32u/message.c | 58 ------------------------------------ dlls/win32u/ntuser_private.h | 5 ---- dlls/win32u/sysparams.c | 34 +++++++++++++++++++-- 3 files changed, 32 insertions(+), 65 deletions(-)
diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 877be545810..6b89b873f37 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -288,7 +288,6 @@ struct send_message_info };
static const INPUT_MESSAGE_SOURCE msg_source_unavailable = { IMDT_UNAVAILABLE, IMO_UNAVAILABLE }; -static BOOL keyboard_auto_repeat_enabled;
/* flag for messages that contain pointers */ /* 32 messages per entry, messages 0..31 map to bits 0..31 */ @@ -516,13 +515,6 @@ static inline BOOL check_hwnd_filter( const MSG *msg, HWND hwnd_filter ) return (msg->hwnd == hwnd_filter || is_child( hwnd_filter, msg->hwnd )); }
-BOOL set_keyboard_auto_repeat( BOOL enable ) -{ - BOOL enabled = keyboard_auto_repeat_enabled; - keyboard_auto_repeat_enabled = enable; - return enabled; -} - /*********************************************************************** * unpack_message * @@ -2309,21 +2301,6 @@ static void send_parent_notify( HWND hwnd, WORD event, WORD idChild, POINT pt ) } }
- -static void handle_keyboard_repeat_message( HWND hwnd ) -{ - struct user_thread_info *thread_info = get_user_thread_info(); - MSG *msg = &thread_info->key_repeat_msg; - UINT speed; - - msg->lParam = (msg->lParam & ~(LPARAM)0xffff) + ((msg->lParam + 1) & 0xffff); - - if (NtUserSystemParametersInfo( SPI_GETKEYBOARDSPEED, 0, &speed, 0 )) - NtUserSetSystemTimer( hwnd, SYSTEM_TIMER_KEY_REPEAT, 400 / (speed + 1) ); - - NtUserPostMessage( hwnd, msg->message, msg->wParam, msg->lParam ); -} - /*********************************************************************** * process_pointer_message * @@ -2416,37 +2393,6 @@ static BOOL process_keyboard_message( MSG *msg, UINT hw_id, HWND hwnd_filter, if (ImmProcessKey( msg->hwnd, NtUserGetKeyboardLayout(0), msg->wParam, msg->lParam, 0 )) msg->wParam = VK_PROCESSKEY;
- /* set/kill timers for key auto-repeat */ - if (remove && keyboard_auto_repeat_enabled) - { - struct user_thread_info *thread_info = get_user_thread_info(); - - switch (msg->message) - { - case WM_KEYDOWN: - case WM_SYSKEYDOWN: - { - UINT delay; - - if (msg->wParam == VK_PROCESSKEY) break; - - if (thread_info->key_repeat_msg.hwnd != msg->hwnd) - kill_system_timer( thread_info->key_repeat_msg.hwnd, SYSTEM_TIMER_KEY_REPEAT ); - thread_info->key_repeat_msg = *msg; - if (NtUserSystemParametersInfo( SPI_GETKEYBOARDDELAY, 0, &delay, 0 )) - NtUserSetSystemTimer( msg->hwnd, SYSTEM_TIMER_KEY_REPEAT, (delay + 1) * 250 ); - break; - } - - case WM_KEYUP: - case WM_SYSKEYUP: - /* Only stop repeat if the scan codes match. */ - if ((thread_info->key_repeat_msg.lParam & 0x01ff0000) == (msg->lParam & 0x01ff0000)) - kill_system_timer( thread_info->key_repeat_msg.hwnd, SYSTEM_TIMER_KEY_REPEAT ); - break; - } - } - return TRUE; }
@@ -3655,10 +3601,6 @@ LRESULT WINAPI NtUserDispatchMessage( const MSG *msg ) case SYSTEM_TIMER_TRACK_MOUSE: update_mouse_tracking_info( msg->hwnd ); return 0; - - case SYSTEM_TIMER_KEY_REPEAT: - handle_keyboard_repeat_message( msg->hwnd ); - return 0; } }
diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index f0bd14179d4..020c98005df 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -33,9 +33,6 @@ enum system_timer_id { SYSTEM_TIMER_TRACK_MOUSE = 0xfffa, SYSTEM_TIMER_CARET = 0xffff, - - /* not compatible with native */ - SYSTEM_TIMER_KEY_REPEAT = 0xfff0, };
struct user_object @@ -120,7 +117,6 @@ struct user_thread_info struct received_message_info *receive_info; /* Message being currently received */ struct user_key_state_info *key_state; /* Cache of global key state */ struct imm_thread_data *imm_thread_data; /* IMM thread data */ - MSG key_repeat_msg; /* Last WM_KEYDOWN message to repeat */ HKL kbd_layout; /* Current keyboard layout */ UINT kbd_layout_id; /* Current keyboard layout ID */ struct hardware_msg_data *rawinput; /* Current rawinput message data */ @@ -249,7 +245,6 @@ struct peek_message_filter };
extern int peek_message( MSG *msg, const struct peek_message_filter *filter ); -extern BOOL set_keyboard_auto_repeat( BOOL enable );
/* systray.c */ extern LRESULT system_tray_call( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, void *data ); diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 49bf26214e7..686982dc3e5 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -3744,6 +3744,25 @@ BOOL WINAPI NtUserPerMonitorDPIPhysicalToLogicalPoint( HWND hwnd, POINT *pt ) return ret; }
+/* Set server auto-repeat properties. delay and speed are expressed in terms of + * SPI_KEYBOARDDELAY and SPI_KEYBOARDSPEED values. Returns whether auto-repeat + * was enabled before this request. */ +static BOOL set_server_keyboard_repeat( int enable, int delay, int speed ) +{ + BOOL enabled = FALSE; + + SERVER_START_REQ( set_keyboard_repeat ) + { + req->enable = enable >= 0 ? (enable > 0) : -1; + req->delay = delay >= 0 ? (delay + 1) * 250 : -1; + req->period = speed >= 0 ? 400 / (speed + 1) : -1; + if (!wine_server_call( req )) enabled = reply->enable; + } + SERVER_END_REQ; + + return enabled; +} + /* retrieve the cached base keys for a given entry */ static BOOL get_base_keys( enum parameter_key index, HKEY *base_key, HKEY *volatile_key ) { @@ -4974,7 +4993,8 @@ BOOL WINAPI NtUserSystemParametersInfo( UINT action, UINT val, void *ptr, UINT w break; case SPI_SETKEYBOARDSPEED: if (val > 31) val = 31; - ret = set_entry( &entry_KEYBOARDSPEED, val, ptr, winini ); + if ((ret = set_entry( &entry_KEYBOARDSPEED, val, ptr, winini ))) + set_server_keyboard_repeat( -1, -1, val ); break;
WINE_SPI_WARN(SPI_LANGDRIVER); /* not implemented in Windows */ @@ -5018,7 +5038,8 @@ BOOL WINAPI NtUserSystemParametersInfo( UINT action, UINT val, void *ptr, UINT w ret = get_entry( &entry_KEYBOARDDELAY, val, ptr ); break; case SPI_SETKEYBOARDDELAY: - ret = set_entry( &entry_KEYBOARDDELAY, val, ptr, winini ); + if ((ret = set_entry( &entry_KEYBOARDDELAY, val, ptr, winini ))) + set_server_keyboard_repeat( -1, val, -1 ); break; case SPI_ICONVERTICALSPACING: if (ptr != NULL) @@ -6272,6 +6293,15 @@ static void thread_detach(void) exiting_thread_id = 0; }
+static BOOL set_keyboard_auto_repeat( BOOL enable ) +{ + UINT delay, speed; + + get_entry( &entry_KEYBOARDDELAY, 0, &delay ); + get_entry( &entry_KEYBOARDSPEED, 0, &speed ); + return set_server_keyboard_repeat( enable, delay, speed ); +} + /*********************************************************************** * NtUserCallNoParam (win32u.@) */
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=146105
Your paranoid android.
=== debian11b (64 bit WoW report) ===
user32: msg.c:6912: Test failed: SetFocus(hwnd) on a button: 3: the winevent_hook 0x8005 was expected, but got hook 0x0005 instead msg.c:6912: Test failed: SetFocus(hwnd) on a button: 3: the winevent_hook 0x8005 was expected, but got winevent_hook 0x0003 instead msg.c:6912: Test failed: SetFocus(hwnd) on a button: 3: the winevent_hook 0x8005 was expected, but got msg 0x030f instead msg.c:6912: Test failed: SetFocus(hwnd) on a button: 3: the winevent_hook 0x8005 was expected, but got msg 0x001c instead msg.c:6912: Test failed: SetFocus(hwnd) on a button: 3: the winevent_hook 0x8005 was expected, but got msg 0x0086 instead msg.c:6912: Test failed: SetFocus(hwnd) on a button: 3: the winevent_hook 0x8005 was expected, but got msg 0x0006 instead msg.c:6912: Test failed: SetFocus(hwnd) on a button: 3: the winevent_hook 0x8005 was expected, but got hook 0x0009 instead
@rbernon A last minute fix.
v5: * Avoid double-releasing the key repeat timeout after disabling key repeat.