Clear all keys and modifies on focus change (#2933)
It is very easy for keys to become stuck when we alt-tab, or a save-dialog opens by Ctrl+S, etc. Therefore we new clear all the modifiers and down keys to avoid that.
This commit is contained in:
parent
ede3ded977
commit
d1af798a9b
|
|
@ -927,6 +927,8 @@ pub struct WindowInfo {
|
||||||
pub maximized: bool,
|
pub maximized: bool,
|
||||||
|
|
||||||
/// Is the window focused and able to receive input?
|
/// Is the window focused and able to receive input?
|
||||||
|
///
|
||||||
|
/// This should be the same as [`egui::InputState::focused`].
|
||||||
pub focused: bool,
|
pub focused: bool,
|
||||||
|
|
||||||
/// Window inner size in egui points (logical pixels).
|
/// Window inner size in egui points (logical pixels).
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,10 @@ impl WebInput {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_web_page_focus_change(&mut self, has_focus: bool) {
|
pub fn on_web_page_focus_change(&mut self, focused: bool) {
|
||||||
self.raw.modifiers = egui::Modifiers::default();
|
self.raw.modifiers = egui::Modifiers::default();
|
||||||
self.raw.has_focus = has_focus;
|
self.raw.focused = focused;
|
||||||
|
self.raw.events.push(egui::Event::WindowFocused(focused));
|
||||||
self.latest_touch_pos = None;
|
self.latest_touch_pos = None;
|
||||||
self.latest_touch_pos_id = None;
|
self.latest_touch_pos_id = None;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ impl State {
|
||||||
/// The returned `State` must not outlive the input `display_target`.
|
/// The returned `State` must not outlive the input `display_target`.
|
||||||
pub fn new(display_target: &dyn HasRawDisplayHandle) -> Self {
|
pub fn new(display_target: &dyn HasRawDisplayHandle) -> Self {
|
||||||
let egui_input = egui::RawInput {
|
let egui_input = egui::RawInput {
|
||||||
has_focus: false, // winit will tell us when we have focus
|
focused: false, // winit will tell us when we have focus
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -314,11 +314,14 @@ impl State {
|
||||||
consumed,
|
consumed,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WindowEvent::Focused(has_focus) => {
|
WindowEvent::Focused(focused) => {
|
||||||
self.egui_input.has_focus = *has_focus;
|
self.egui_input.focused = *focused;
|
||||||
// We will not be given a KeyboardInput event when the modifiers are released while
|
// We will not be given a KeyboardInput event when the modifiers are released while
|
||||||
// the window does not have focus. Unset all modifier state to be safe.
|
// the window does not have focus. Unset all modifier state to be safe.
|
||||||
self.egui_input.modifiers = egui::Modifiers::default();
|
self.egui_input.modifiers = egui::Modifiers::default();
|
||||||
|
self.egui_input
|
||||||
|
.events
|
||||||
|
.push(egui::Event::WindowFocused(*focused));
|
||||||
EventResponse {
|
EventResponse {
|
||||||
repaint: true,
|
repaint: true,
|
||||||
consumed: false,
|
consumed: false,
|
||||||
|
|
|
||||||
|
|
@ -1139,7 +1139,7 @@ impl Context {
|
||||||
{
|
{
|
||||||
let state = self.frame_state_mut(|fs| fs.accesskit_state.take());
|
let state = self.frame_state_mut(|fs| fs.accesskit_state.take());
|
||||||
if let Some(state) = state {
|
if let Some(state) = state {
|
||||||
let has_focus = self.input(|i| i.raw.has_focus);
|
let has_focus = self.input(|i| i.raw.focused);
|
||||||
let root_id = crate::accesskit_root_id().accesskit_id();
|
let root_id = crate::accesskit_root_id().accesskit_id();
|
||||||
let nodes = self.write(|ctx| {
|
let nodes = self.write(|ctx| {
|
||||||
state
|
state
|
||||||
|
|
|
||||||
|
|
@ -63,8 +63,10 @@ pub struct RawInput {
|
||||||
/// drag-and-drop support using `eframe::NativeOptions`.
|
/// drag-and-drop support using `eframe::NativeOptions`.
|
||||||
pub dropped_files: Vec<DroppedFile>,
|
pub dropped_files: Vec<DroppedFile>,
|
||||||
|
|
||||||
/// The window has the keyboard focus (i.e. is receiving key presses).
|
/// The native window has the keyboard focus (i.e. is receiving key presses).
|
||||||
pub has_focus: bool,
|
///
|
||||||
|
/// False when the user alt-tab away from the application, for instance.
|
||||||
|
pub focused: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for RawInput {
|
impl Default for RawInput {
|
||||||
|
|
@ -79,7 +81,7 @@ impl Default for RawInput {
|
||||||
events: vec![],
|
events: vec![],
|
||||||
hovered_files: Default::default(),
|
hovered_files: Default::default(),
|
||||||
dropped_files: Default::default(),
|
dropped_files: Default::default(),
|
||||||
has_focus: true, // integrations opt into global focus tracking
|
focused: true, // integrations opt into global focus tracking
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -100,7 +102,7 @@ impl RawInput {
|
||||||
events: std::mem::take(&mut self.events),
|
events: std::mem::take(&mut self.events),
|
||||||
hovered_files: self.hovered_files.clone(),
|
hovered_files: self.hovered_files.clone(),
|
||||||
dropped_files: std::mem::take(&mut self.dropped_files),
|
dropped_files: std::mem::take(&mut self.dropped_files),
|
||||||
has_focus: self.has_focus,
|
focused: self.focused,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,7 +118,7 @@ impl RawInput {
|
||||||
mut events,
|
mut events,
|
||||||
mut hovered_files,
|
mut hovered_files,
|
||||||
mut dropped_files,
|
mut dropped_files,
|
||||||
has_focus,
|
focused,
|
||||||
} = newer;
|
} = newer;
|
||||||
|
|
||||||
self.screen_rect = screen_rect.or(self.screen_rect);
|
self.screen_rect = screen_rect.or(self.screen_rect);
|
||||||
|
|
@ -128,7 +130,7 @@ impl RawInput {
|
||||||
self.events.append(&mut events);
|
self.events.append(&mut events);
|
||||||
self.hovered_files.append(&mut hovered_files);
|
self.hovered_files.append(&mut hovered_files);
|
||||||
self.dropped_files.append(&mut dropped_files);
|
self.dropped_files.append(&mut dropped_files);
|
||||||
self.has_focus = has_focus;
|
self.focused = focused;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -294,6 +296,9 @@ pub enum Event {
|
||||||
modifiers: Modifiers,
|
modifiers: Modifiers,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// The native window gained or lost focused (e.g. the user clicked alt-tab).
|
||||||
|
WindowFocused(bool),
|
||||||
|
|
||||||
/// An assistive technology (e.g. screen reader) requested an action.
|
/// An assistive technology (e.g. screen reader) requested an action.
|
||||||
#[cfg(feature = "accesskit")]
|
#[cfg(feature = "accesskit")]
|
||||||
AccessKitActionRequest(accesskit::ActionRequest),
|
AccessKitActionRequest(accesskit::ActionRequest),
|
||||||
|
|
@ -847,7 +852,7 @@ impl RawInput {
|
||||||
events,
|
events,
|
||||||
hovered_files,
|
hovered_files,
|
||||||
dropped_files,
|
dropped_files,
|
||||||
has_focus,
|
focused,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
ui.label(format!("screen_rect: {:?} points", screen_rect));
|
ui.label(format!("screen_rect: {:?} points", screen_rect));
|
||||||
|
|
@ -865,7 +870,7 @@ impl RawInput {
|
||||||
ui.label(format!("modifiers: {:#?}", modifiers));
|
ui.label(format!("modifiers: {:#?}", modifiers));
|
||||||
ui.label(format!("hovered_files: {}", hovered_files.len()));
|
ui.label(format!("hovered_files: {}", hovered_files.len()));
|
||||||
ui.label(format!("dropped_files: {}", dropped_files.len()));
|
ui.label(format!("dropped_files: {}", dropped_files.len()));
|
||||||
ui.label(format!("has_focus: {}", has_focus));
|
ui.label(format!("focused: {}", focused));
|
||||||
ui.scope(|ui| {
|
ui.scope(|ui| {
|
||||||
ui.set_min_height(150.0);
|
ui.set_min_height(150.0);
|
||||||
ui.label(format!("events: {:#?}", events))
|
ui.label(format!("events: {:#?}", events))
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,11 @@ pub struct InputState {
|
||||||
/// and will effectively slow down the animation when FPS drops below 10.
|
/// and will effectively slow down the animation when FPS drops below 10.
|
||||||
pub stable_dt: f32,
|
pub stable_dt: f32,
|
||||||
|
|
||||||
|
/// The native window has the keyboard focus (i.e. is receiving key presses).
|
||||||
|
///
|
||||||
|
/// False when the user alt-tab away from the application, for instance.
|
||||||
|
pub focused: bool,
|
||||||
|
|
||||||
/// Which modifier keys are down at the start of the frame?
|
/// Which modifier keys are down at the start of the frame?
|
||||||
pub modifiers: Modifiers,
|
pub modifiers: Modifiers,
|
||||||
|
|
||||||
|
|
@ -129,6 +134,7 @@ impl Default for InputState {
|
||||||
unstable_dt: 1.0 / 60.0,
|
unstable_dt: 1.0 / 60.0,
|
||||||
predicted_dt: 1.0 / 60.0,
|
predicted_dt: 1.0 / 60.0,
|
||||||
stable_dt: 1.0 / 60.0,
|
stable_dt: 1.0 / 60.0,
|
||||||
|
focused: false,
|
||||||
modifiers: Default::default(),
|
modifiers: Default::default(),
|
||||||
keys_down: Default::default(),
|
keys_down: Default::default(),
|
||||||
events: Default::default(),
|
events: Default::default(),
|
||||||
|
|
@ -189,6 +195,20 @@ impl InputState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut modifiers = new.modifiers;
|
||||||
|
|
||||||
|
let focused_changed = self.focused != new.focused
|
||||||
|
|| new
|
||||||
|
.events
|
||||||
|
.iter()
|
||||||
|
.any(|e| matches!(e, Event::WindowFocused(_)));
|
||||||
|
if focused_changed {
|
||||||
|
// It is very common for keys to become stuck when we alt-tab, or a save-dialog opens by Ctrl+S.
|
||||||
|
// Therefore we clear all the modifiers and down keys here to avoid that.
|
||||||
|
modifiers = Default::default();
|
||||||
|
keys_down = Default::default();
|
||||||
|
}
|
||||||
|
|
||||||
InputState {
|
InputState {
|
||||||
pointer,
|
pointer,
|
||||||
touch_states: self.touch_states,
|
touch_states: self.touch_states,
|
||||||
|
|
@ -201,7 +221,8 @@ impl InputState {
|
||||||
unstable_dt,
|
unstable_dt,
|
||||||
predicted_dt: new.predicted_dt,
|
predicted_dt: new.predicted_dt,
|
||||||
stable_dt,
|
stable_dt,
|
||||||
modifiers: new.modifiers,
|
focused: new.focused,
|
||||||
|
modifiers,
|
||||||
keys_down,
|
keys_down,
|
||||||
events: new.events.clone(), // TODO(emilk): remove clone() and use raw.events
|
events: new.events.clone(), // TODO(emilk): remove clone() and use raw.events
|
||||||
raw: new,
|
raw: new,
|
||||||
|
|
@ -926,6 +947,7 @@ impl InputState {
|
||||||
unstable_dt,
|
unstable_dt,
|
||||||
predicted_dt,
|
predicted_dt,
|
||||||
stable_dt,
|
stable_dt,
|
||||||
|
focused,
|
||||||
modifiers,
|
modifiers,
|
||||||
keys_down,
|
keys_down,
|
||||||
events,
|
events,
|
||||||
|
|
@ -969,6 +991,7 @@ impl InputState {
|
||||||
));
|
));
|
||||||
ui.label(format!("predicted_dt: {:.1} ms", 1e3 * predicted_dt));
|
ui.label(format!("predicted_dt: {:.1} ms", 1e3 * predicted_dt));
|
||||||
ui.label(format!("stable_dt: {:.1} ms", 1e3 * stable_dt));
|
ui.label(format!("stable_dt: {:.1} ms", 1e3 * stable_dt));
|
||||||
|
ui.label(format!("focused: {}", focused));
|
||||||
ui.label(format!("modifiers: {:#?}", modifiers));
|
ui.label(format!("modifiers: {:#?}", modifiers));
|
||||||
ui.label(format!("keys_down: {:?}", keys_down));
|
ui.label(format!("keys_down: {:?}", keys_down));
|
||||||
ui.scope(|ui| {
|
ui.scope(|ui| {
|
||||||
|
|
|
||||||
|
|
@ -233,7 +233,7 @@ impl Response {
|
||||||
/// also has the keyboard focus. That makes this function suitable
|
/// also has the keyboard focus. That makes this function suitable
|
||||||
/// for style choices, e.g. a thicker border around focused widgets.
|
/// for style choices, e.g. a thicker border around focused widgets.
|
||||||
pub fn has_focus(&self) -> bool {
|
pub fn has_focus(&self) -> bool {
|
||||||
self.ctx.input(|i| i.raw.has_focus) && self.ctx.memory(|mem| mem.has_focus(self.id))
|
self.ctx.input(|i| i.focused) && self.ctx.memory(|mem| mem.has_focus(self.id))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// True if this widget has keyboard focus this frame, but didn't last frame.
|
/// True if this widget has keyboard focus this frame, but didn't last frame.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue