[PATCH v2 0/2] MR4399: win32u: Support key message repeat for winewayland.
-- v2: win32u: Implement opt-in auto-repeat for WM_(SYS)KEYDOWN messages. winewayland.drv: Configure win32u keyboard repeat delay and speed. https://gitlab.winehq.org/wine/wine/-/merge_requests/4399
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/win32u/message.c | 8 ++++++++ dlls/win32u/ntuser_private.h | 3 +++ dlls/win32u/sysparams.c | 3 +++ dlls/winewayland.drv/wayland_keyboard.c | 11 ++++++++++- include/ntuser.h | 1 + 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index d2909339983..e897ead329e 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -288,6 +288,7 @@ 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 */ @@ -508,6 +509,13 @@ 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 * diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index b39e38db5d6..915aeb50bdc 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -242,6 +242,9 @@ HICON alloc_cursoricon_handle( BOOL is_icon ) DECLSPEC_HIDDEN; extern void free_dce( struct dce *dce, HWND hwnd ) DECLSPEC_HIDDEN; extern void invalidate_dce( WND *win, const RECT *extra_rect ) DECLSPEC_HIDDEN; +/* message.c */ +extern BOOL set_keyboard_auto_repeat( BOOL enable ) DECLSPEC_HIDDEN; + /* window.c */ HANDLE alloc_user_handle( struct user_object *ptr, unsigned int type ) DECLSPEC_HIDDEN; void *free_user_handle( HANDLE handle, unsigned int type ) DECLSPEC_HIDDEN; diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index b134c5af680..dd409fe992f 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -6320,6 +6320,9 @@ ULONG_PTR WINAPI NtUserCallOneParam( ULONG_PTR arg, ULONG code ) process_layout = arg; return TRUE; + case NtUserCallOneParam_SetKeyboardAutoRepeat: + return set_keyboard_auto_repeat( arg ); + /* temporary exports */ case NtUserGetDeskPattern: return get_entry( &entry_DESKPATTERN, 256, (WCHAR *)arg ); diff --git a/dlls/winewayland.drv/wayland_keyboard.c b/dlls/winewayland.drv/wayland_keyboard.c index 741dbfe1157..bb865ff3881 100644 --- a/dlls/winewayland.drv/wayland_keyboard.c +++ b/dlls/winewayland.drv/wayland_keyboard.c @@ -219,7 +219,15 @@ static void keyboard_handle_modifiers(void *data, struct wl_keyboard *wl_keyboar static void keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int rate, int delay) { - FIXME("rate=%d delay=%d stub!\n", rate, delay); + TRACE("rate=%d delay=%d\n", rate, delay); + + /* Handle non-negative rate values, ignore invalid (negative) values. A + * rate of 0 disables repeat. */ + rate = max(0, min(80, rate)) * 400 / 1000 - 1; + delay = max(0, min(3, round(delay / 250.0) - 1)); + NtUserSystemParametersInfo(SPI_SETKEYBOARDSPEED, rate, NULL, 0); + NtUserSystemParametersInfo(SPI_SETKEYBOARDDELAY, delay, NULL, 0); + NtUserCallOneParam(rate > 0, NtUserCallOneParam_SetKeyboardAutoRepeat); } static const struct wl_keyboard_listener keyboard_listener = { @@ -245,6 +253,7 @@ void wayland_keyboard_init(struct wl_keyboard *wl_keyboard) return; } + NtUserCallOneParam(TRUE, NtUserCallOneParam_SetKeyboardAutoRepeat); pthread_mutex_lock(&keyboard->mutex); keyboard->wl_keyboard = wl_keyboard; keyboard->xkb_context = xkb_context; diff --git a/include/ntuser.h b/include/ntuser.h index def89a82aff..b62c2e60538 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -878,6 +878,7 @@ enum NtUserCallOneParam_ReplyMessage, NtUserCallOneParam_SetCaretBlinkTime, NtUserCallOneParam_SetProcessDefaultLayout, + NtUserCallOneParam_SetKeyboardAutoRepeat, /* temporary exports */ NtUserGetDeskPattern, }; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4399
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/win32u/message.c | 47 ++++++++++++++++++++++++++++++++++++ dlls/win32u/ntuser_private.h | 4 +++ 2 files changed, 51 insertions(+) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index e897ead329e..3c59eb8ee1d 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2292,6 +2292,22 @@ 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_keyboard_message * @@ -2371,6 +2387,33 @@ 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; + + 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: + kill_system_timer( thread_info->key_repeat_msg.hwnd, SYSTEM_TIMER_KEY_REPEAT ); + break; + } + } + return TRUE; } @@ -3565,6 +3608,10 @@ 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 915aeb50bdc..72a2f24bc49 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -32,6 +32,9 @@ enum system_timer_id { SYSTEM_TIMER_TRACK_MOUSE = 0xfffa, SYSTEM_TIMER_CARET = 0xffff, + + /* not compatible with native */ + SYSTEM_TIMER_KEY_REPEAT = 0xfff0, }; struct rawinput_thread_data @@ -126,6 +129,7 @@ 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 rawinput_thread_data *rawinput; /* RawInput thread local data / buffer */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4399
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 full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=140109 Your paranoid android. === debian11 (build log) === error: patch failed: dlls/win32u/ntuser_private.h:242 Task: Patch failed to apply === debian11b (build log) === error: patch failed: dlls/win32u/ntuser_private.h:242 Task: Patch failed to apply
This merge request was approved by Rémi Bernon. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/4399
Alexandros Frantzis (@afrantzis) commented about dlls/winewayland.drv/wayland_keyboard.c:
static void keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int rate, int delay) { - FIXME("rate=%d delay=%d stub!\n", rate, delay); + TRACE("rate=%d delay=%d\n", rate, delay); + + /* Handle non-negative rate values, ignore invalid (negative) values. A + * rate of 0 disables repeat. */ + rate = max(0, min(80, rate)) * 400 / 1000 - 1; The updated calculation gives -1 for wayland rate < 3. Is this on purpose? Perhaps use `max(3, ...` ?
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/4399#note_53107
Alexandros Frantzis (@afrantzis) commented about dlls/winewayland.drv/wayland_keyboard.c:
static void keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int rate, int delay) { - FIXME("rate=%d delay=%d stub!\n", rate, delay); + TRACE("rate=%d delay=%d\n", rate, delay); + + /* Handle non-negative rate values, ignore invalid (negative) values. A + * rate of 0 disables repeat. */ + rate = max(0, min(80, rate)) * 400 / 1000 - 1; + delay = max(0, min(3, round(delay / 250.0) - 1)); + NtUserSystemParametersInfo(SPI_SETKEYBOARDSPEED, rate, NULL, 0); + NtUserSystemParametersInfo(SPI_SETKEYBOARDDELAY, delay, NULL, 0); + NtUserCallOneParam(rate > 0, NtUserCallOneParam_SetKeyboardAutoRepeat); In the new code the `rate` variable is overwritten by the SPI speed, so on the lower edge of the wayland range rates (<5) the above doesn't work as expected.
Is this meant to interact with the -1 value from the current rate calculation? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/4399#note_53108
On Tue Nov 21 15:45:05 2023 +0000, Alexandros Frantzis wrote:
In the new code the `rate` variable is overwritten by the SPI speed, so on the lower edge of the wayland range rates (<5) the above doesn't work as expected. Is this meant to interact with the -1 value from the current rate calculation? No, sorry this is a bad attempt at being clever. I'll revert.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/4399#note_53110
participants (3)
-
Alexandros Frantzis (@afrantzis) -
Marvin -
Rémi Bernon