From 33d68687c2bc91a1d4477302a8dd4cc229e1f67f Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 23 Jan 2023 11:05:47 +0100 Subject: [PATCH] Fix key input not working after loss of focus due to global shortcut When a global shortcut, like ^-Cmd-Q on macOS to lock the screen, causes a loss of window focus, we'll receive a key event from the windowing system for the modifier, but we'll never receive the "Q" in this example (as press or release). So later, when we regain focus, we'd assume that our keyboard modifier state is still "pressed ^/Cmd", which is incorrect. Therefore assume that a loss of window focus implies a reset keyboard of keyboard modifier state. Fixes #2098 --- internal/core/window.rs | 6 +++++ tests/cases/text/keyboard_modifiers.slint | 32 +++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/internal/core/window.rs b/internal/core/window.rs index a4f6f1b6d..7ae6ef674 100644 --- a/internal/core/window.rs +++ b/internal/core/window.rs @@ -464,6 +464,12 @@ impl WindowInner { if let Some(focus_item) = self.focus_item.borrow().upgrade() { focus_item.borrow().as_ref().focus_event(&event, &self.window_adapter(), &focus_item); } + + // If we lost focus due to for example a global shortcut, then when we regain focus + // should not assume that the modifiers are in the same state. + if !have_focus { + self.modifiers.take(); + } } /// Take the focus_item out of this Window diff --git a/tests/cases/text/keyboard_modifiers.slint b/tests/cases/text/keyboard_modifiers.slint index bd7e07d2f..9e84aa1ae 100644 --- a/tests/cases/text/keyboard_modifiers.slint +++ b/tests/cases/text/keyboard_modifiers.slint @@ -172,5 +172,37 @@ assert_eq!(instance.get_alt_modifier(), false); assert_eq!(instance.get_control_modifier(), false); assert_eq!(instance.get_meta_modifier(), false); +slint_testing::send_keyboard_char(&instance, 'a', true); +slint_testing::send_keyboard_char(&instance, 'a', false); +assert_eq!(instance.get_shift_modifier(), false); +assert_eq!(instance.get_alt_modifier(), false); +assert_eq!(instance.get_control_modifier(), false); +assert_eq!(instance.get_meta_modifier(), false); + +// Check that loss of windows focus and regaining it, resets the internal modifier +// state. +slint_testing::send_keyboard_char(&instance, Key::Control.into(), true); +slint_testing::send_keyboard_char(&instance, 'a', true); +slint_testing::send_keyboard_char(&instance, 'a', false); +assert_eq!(instance.get_shift_modifier(), false); +assert_eq!(instance.get_alt_modifier(), false); +assert_eq!(instance.get_control_modifier(), true); +assert_eq!(instance.get_meta_modifier(), false); + +// Pretend that Ctrl-something results in a loss of focus, so we never receive the "something" key, +// but we observe a loss of focus. +// TODO: create public API for window focus gain/loss +let window_inner = slint::private_unstable_api::re_exports::WindowInner::from_pub(instance.window()); +window_inner.set_active(false); +window_inner.set_focus(false); +window_inner.set_active(true); +window_inner.set_focus(true); + +slint_testing::send_keyboard_char(&instance, 'a', true); +slint_testing::send_keyboard_char(&instance, 'a', false); +assert_eq!(instance.get_shift_modifier(), false); +assert_eq!(instance.get_alt_modifier(), false); +assert_eq!(instance.get_control_modifier(), false); +assert_eq!(instance.get_meta_modifier(), false); ``` */