Fix window spawning triggering ButtonInput<KeyCode>::just_pressed/just_released (#12372)
# Objective Fix #12273 ## Solution – Only emit `KeyboardFocusLost` when the keyboard focus is lost – ignore synthetic key releases too, not just key presses (as they're already covered by `KeyboardFocusLost`) --- ## Changelog ### Fixed - Don't trigger `ButtonInput<KeyCode>::just_pressed`/`just_released` when spawning a window/focus moving between Bevy windows
This commit is contained in:
parent
c2d193abd5
commit
e7c6228e8b
@ -62,8 +62,7 @@ use {
|
|||||||
///
|
///
|
||||||
/// `ButtonInput<KeyCode>` is tied to window focus. For example, if the user holds a button
|
/// `ButtonInput<KeyCode>` is tied to window focus. For example, if the user holds a button
|
||||||
/// while the window loses focus, [`ButtonInput::just_released`] will be triggered. Similarly if the window
|
/// while the window loses focus, [`ButtonInput::just_released`] will be triggered. Similarly if the window
|
||||||
/// regains focus, [`ButtonInput::just_pressed`] will be triggered. Currently this happens even if the
|
/// regains focus, [`ButtonInput::just_pressed`] will be triggered.
|
||||||
/// focus switches from one Bevy window to another (for example because a new window was just spawned).
|
|
||||||
///
|
///
|
||||||
/// `ButtonInput<GamepadButton>` is independent of window focus.
|
/// `ButtonInput<GamepadButton>` is independent of window focus.
|
||||||
///
|
///
|
||||||
|
|||||||
@ -134,7 +134,7 @@ pub struct KeyboardFocusLost;
|
|||||||
/// ## Differences
|
/// ## Differences
|
||||||
///
|
///
|
||||||
/// The main difference between the [`KeyboardInput`] event and the [`ButtonInput<KeyCode>`] resources is that
|
/// The main difference between the [`KeyboardInput`] event and the [`ButtonInput<KeyCode>`] resources is that
|
||||||
/// the latter have convenient functions such as [`ButtonInput::pressed`], [`ButtonInput::just_pressed`] and [`ButtonInput::just_released`].
|
/// the latter has convenient functions such as [`ButtonInput::pressed`], [`ButtonInput::just_pressed`] and [`ButtonInput::just_released`] and is window id agnostic.
|
||||||
pub fn keyboard_input_system(
|
pub fn keyboard_input_system(
|
||||||
mut key_input: ResMut<ButtonInput<KeyCode>>,
|
mut key_input: ResMut<ButtonInput<KeyCode>>,
|
||||||
mut keyboard_input_events: EventReader<KeyboardInput>,
|
mut keyboard_input_events: EventReader<KeyboardInput>,
|
||||||
|
|||||||
@ -27,7 +27,7 @@ use bevy_ecs::prelude::*;
|
|||||||
use bevy_window::{exit_on_all_closed, Window, WindowCreated};
|
use bevy_window::{exit_on_all_closed, Window, WindowCreated};
|
||||||
pub use converters::convert_system_cursor_icon;
|
pub use converters::convert_system_cursor_icon;
|
||||||
pub use state::{CursorSource, CustomCursorCache, CustomCursorCacheKey, PendingCursor};
|
pub use state::{CursorSource, CustomCursorCache, CustomCursorCacheKey, PendingCursor};
|
||||||
use system::{changed_windows, despawn_windows};
|
use system::{changed_windows, check_keyboard_focus_lost, despawn_windows};
|
||||||
pub use system::{create_monitors, create_windows};
|
pub use system::{create_monitors, create_windows};
|
||||||
#[cfg(all(target_family = "wasm", target_os = "unknown"))]
|
#[cfg(all(target_family = "wasm", target_os = "unknown"))]
|
||||||
pub use winit::platform::web::CustomCursorExtWebSys;
|
pub use winit::platform::web::CustomCursorExtWebSys;
|
||||||
@ -133,6 +133,7 @@ impl<T: Event> Plugin for WinitPlugin<T> {
|
|||||||
// so we don't need to care about its ordering relative to `changed_windows`
|
// so we don't need to care about its ordering relative to `changed_windows`
|
||||||
changed_windows.ambiguous_with(exit_on_all_closed),
|
changed_windows.ambiguous_with(exit_on_all_closed),
|
||||||
despawn_windows,
|
despawn_windows,
|
||||||
|
check_keyboard_focus_lost,
|
||||||
)
|
)
|
||||||
.chain(),
|
.chain(),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -10,7 +10,6 @@ use bevy_ecs::{
|
|||||||
};
|
};
|
||||||
use bevy_input::{
|
use bevy_input::{
|
||||||
gestures::*,
|
gestures::*,
|
||||||
keyboard::KeyboardFocusLost,
|
|
||||||
mouse::{MouseButtonInput, MouseMotion, MouseScrollUnit, MouseWheel},
|
mouse::{MouseButtonInput, MouseMotion, MouseScrollUnit, MouseWheel},
|
||||||
};
|
};
|
||||||
use bevy_log::{error, trace, warn};
|
use bevy_log::{error, trace, warn};
|
||||||
@ -267,18 +266,14 @@ impl<T: Event> ApplicationHandler<T> for WinitAppRunnerState<T> {
|
|||||||
.send(WindowCloseRequested { window }),
|
.send(WindowCloseRequested { window }),
|
||||||
WindowEvent::KeyboardInput {
|
WindowEvent::KeyboardInput {
|
||||||
ref event,
|
ref event,
|
||||||
is_synthetic,
|
// On some platforms, winit sends "synthetic" key press events when the window
|
||||||
|
// gains or loses focus. These should not be handled, so we only process key
|
||||||
|
// events if they are not synthetic key presses.
|
||||||
|
is_synthetic: false,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
// Winit sends "synthetic" key press events when the window gains focus. These
|
self.bevy_window_events
|
||||||
// should not be handled, so we only process key events if they are not synthetic
|
.send(converters::convert_keyboard_input(event, window));
|
||||||
// key presses. "synthetic" key release events should still be handled though, for
|
|
||||||
// properly releasing keys when the window loses focus.
|
|
||||||
if !(is_synthetic && event.state.is_pressed()) {
|
|
||||||
// Process the keyboard input event, as long as it's not a synthetic key press.
|
|
||||||
self.bevy_window_events
|
|
||||||
.send(converters::convert_keyboard_input(event, window));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
WindowEvent::CursorMoved { position, .. } => {
|
WindowEvent::CursorMoved { position, .. } => {
|
||||||
let physical_position = DVec2::new(position.x, position.y);
|
let physical_position = DVec2::new(position.x, position.y);
|
||||||
@ -354,9 +349,6 @@ impl<T: Event> ApplicationHandler<T> for WinitAppRunnerState<T> {
|
|||||||
win.focused = focused;
|
win.focused = focused;
|
||||||
self.bevy_window_events
|
self.bevy_window_events
|
||||||
.send(WindowFocused { window, focused });
|
.send(WindowFocused { window, focused });
|
||||||
if !focused {
|
|
||||||
self.bevy_window_events.send(KeyboardFocusLost);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
WindowEvent::Occluded(occluded) => {
|
WindowEvent::Occluded(occluded) => {
|
||||||
self.bevy_window_events
|
self.bevy_window_events
|
||||||
|
|||||||
@ -6,10 +6,11 @@ use bevy_ecs::{
|
|||||||
removal_detection::RemovedComponents,
|
removal_detection::RemovedComponents,
|
||||||
system::{Local, NonSendMut, Query, SystemParamItem},
|
system::{Local, NonSendMut, Query, SystemParamItem},
|
||||||
};
|
};
|
||||||
|
use bevy_input::keyboard::KeyboardFocusLost;
|
||||||
use bevy_utils::tracing::{error, info, warn};
|
use bevy_utils::tracing::{error, info, warn};
|
||||||
use bevy_window::{
|
use bevy_window::{
|
||||||
ClosingWindow, Monitor, PrimaryMonitor, RawHandleWrapper, VideoMode, Window, WindowClosed,
|
ClosingWindow, Monitor, PrimaryMonitor, RawHandleWrapper, VideoMode, Window, WindowClosed,
|
||||||
WindowClosing, WindowCreated, WindowMode, WindowResized, WindowWrapper,
|
WindowClosing, WindowCreated, WindowFocused, WindowMode, WindowResized, WindowWrapper,
|
||||||
};
|
};
|
||||||
|
|
||||||
use winit::{
|
use winit::{
|
||||||
@ -122,6 +123,26 @@ pub fn create_windows<F: QueryFilter + 'static>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check whether keyboard focus was lost. This is different from window
|
||||||
|
/// focus in that swapping between Bevy windows keeps window focus.
|
||||||
|
pub(crate) fn check_keyboard_focus_lost(
|
||||||
|
mut focus_events: EventReader<WindowFocused>,
|
||||||
|
mut keyboard_focus: EventWriter<KeyboardFocusLost>,
|
||||||
|
) {
|
||||||
|
let mut focus_lost = false;
|
||||||
|
let mut focus_gained = false;
|
||||||
|
for e in focus_events.read() {
|
||||||
|
if e.focused {
|
||||||
|
focus_gained = true;
|
||||||
|
} else {
|
||||||
|
focus_lost = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if focus_lost & !focus_gained {
|
||||||
|
keyboard_focus.send(KeyboardFocusLost);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Synchronize available monitors as reported by [`winit`] with [`Monitor`] entities in the world.
|
/// Synchronize available monitors as reported by [`winit`] with [`Monitor`] entities in the world.
|
||||||
pub fn create_monitors(
|
pub fn create_monitors(
|
||||||
event_loop: &ActiveEventLoop,
|
event_loop: &ActiveEventLoop,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user