mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2025-01-11 05:21:31 +11:00
Make winit focus take activity into account on Windows (#2159)
winit's notion of "focus" is very simple; you're either focused or not. However, Windows has both notions of focused window and active window and paying attention only to WM_SETFOCUS/WM_KILLFOCUS can cause a window to believe the user is interacting with it when they're not. (this manifests when a user switches to another application between when a winit application starts and it creates its first window)
This commit is contained in:
parent
9116b6c8cd
commit
1091a8ba1a
|
@ -71,6 +71,7 @@ And please only add new entries to the top of this list, right below the `# Unre
|
|||
- Added `MonitorHandle::refresh_rate_millihertz` to get monitor's refresh rate.
|
||||
- **Breaking**, Replaced `VideoMode::refresh_rate` with `VideoMode::refresh_rate_millihertz` providing better precision.
|
||||
- On Web, add `with_prevent_default` and `with_focusable` to `WindowBuilderExtWebSys` to control whether events should be propagated.
|
||||
- On Windows, fix focus events being sent to inactive windows.
|
||||
|
||||
# 0.26.1 (2022-01-05)
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ use windows_sys::Win32::{
|
|||
WM_GETMINMAXINFO, WM_IME_COMPOSITION, WM_IME_ENDCOMPOSITION, WM_IME_SETCONTEXT,
|
||||
WM_IME_STARTCOMPOSITION, WM_INPUT, WM_INPUT_DEVICE_CHANGE, WM_KEYDOWN, WM_KEYUP,
|
||||
WM_KILLFOCUS, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDOWN, WM_MBUTTONUP,
|
||||
WM_MOUSEHWHEEL, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_NCCREATE, WM_NCDESTROY,
|
||||
WM_MOUSEHWHEEL, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_NCACTIVATE, WM_NCCREATE, WM_NCDESTROY,
|
||||
WM_NCLBUTTONDOWN, WM_PAINT, WM_POINTERDOWN, WM_POINTERUP, WM_POINTERUPDATE,
|
||||
WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SETCURSOR, WM_SETFOCUS, WM_SETTINGCHANGE, WM_SIZE,
|
||||
WM_SYSCHAR, WM_SYSCOMMAND, WM_SYSKEYDOWN, WM_SYSKEYUP, WM_TOUCH, WM_WINDOWPOSCHANGED,
|
||||
|
@ -795,6 +795,74 @@ fn update_modifiers<T>(window: HWND, userdata: &WindowData<T>) {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe fn gain_active_focus<T>(window: HWND, userdata: &WindowData<T>) {
|
||||
use crate::event::{ElementState::Released, WindowEvent::Focused};
|
||||
for windows_keycode in event::get_pressed_keys() {
|
||||
let scancode = MapVirtualKeyA(windows_keycode as u32, MAPVK_VK_TO_VSC);
|
||||
let virtual_keycode = event::vkey_to_winit_vkey(windows_keycode);
|
||||
|
||||
update_modifiers(window, userdata);
|
||||
|
||||
#[allow(deprecated)]
|
||||
userdata.send_event(Event::WindowEvent {
|
||||
window_id: RootWindowId(WindowId(window)),
|
||||
event: WindowEvent::KeyboardInput {
|
||||
device_id: DEVICE_ID,
|
||||
input: KeyboardInput {
|
||||
scancode,
|
||||
virtual_keycode,
|
||||
state: Released,
|
||||
modifiers: event::get_key_mods(),
|
||||
},
|
||||
is_synthetic: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
userdata.send_event(Event::WindowEvent {
|
||||
window_id: RootWindowId(WindowId(window)),
|
||||
event: Focused(true),
|
||||
});
|
||||
}
|
||||
|
||||
unsafe fn lose_active_focus<T>(window: HWND, userdata: &WindowData<T>) {
|
||||
use crate::event::{
|
||||
ElementState::Released,
|
||||
ModifiersState,
|
||||
WindowEvent::{Focused, ModifiersChanged},
|
||||
};
|
||||
for windows_keycode in event::get_pressed_keys() {
|
||||
let scancode = MapVirtualKeyA(windows_keycode as u32, MAPVK_VK_TO_VSC);
|
||||
let virtual_keycode = event::vkey_to_winit_vkey(windows_keycode);
|
||||
|
||||
#[allow(deprecated)]
|
||||
userdata.send_event(Event::WindowEvent {
|
||||
window_id: RootWindowId(WindowId(window)),
|
||||
event: WindowEvent::KeyboardInput {
|
||||
device_id: DEVICE_ID,
|
||||
input: KeyboardInput {
|
||||
scancode,
|
||||
virtual_keycode,
|
||||
state: Released,
|
||||
modifiers: event::get_key_mods(),
|
||||
},
|
||||
is_synthetic: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
userdata.window_state.lock().modifiers_state = ModifiersState::empty();
|
||||
userdata.send_event(Event::WindowEvent {
|
||||
window_id: RootWindowId(WindowId(window)),
|
||||
event: ModifiersChanged(ModifiersState::empty()),
|
||||
});
|
||||
|
||||
userdata.send_event(Event::WindowEvent {
|
||||
window_id: RootWindowId(WindowId(window)),
|
||||
event: Focused(false),
|
||||
});
|
||||
}
|
||||
|
||||
/// Any window whose callback is configured to this function will have its events propagated
|
||||
/// through the events loop of the thread the window was created in.
|
||||
//
|
||||
|
@ -1770,74 +1838,32 @@ unsafe fn public_window_callback_inner<T: 'static>(
|
|||
0
|
||||
}
|
||||
|
||||
WM_SETFOCUS => {
|
||||
use crate::event::{ElementState::Released, WindowEvent::Focused};
|
||||
for windows_keycode in event::get_pressed_keys() {
|
||||
let scancode = MapVirtualKeyA(windows_keycode as u32, MAPVK_VK_TO_VSC);
|
||||
let virtual_keycode = event::vkey_to_winit_vkey(windows_keycode);
|
||||
|
||||
update_modifiers(window, userdata);
|
||||
|
||||
#[allow(deprecated)]
|
||||
userdata.send_event(Event::WindowEvent {
|
||||
window_id: RootWindowId(WindowId(window)),
|
||||
event: WindowEvent::KeyboardInput {
|
||||
device_id: DEVICE_ID,
|
||||
input: KeyboardInput {
|
||||
scancode,
|
||||
virtual_keycode,
|
||||
state: Released,
|
||||
modifiers: event::get_key_mods(),
|
||||
},
|
||||
is_synthetic: true,
|
||||
},
|
||||
})
|
||||
WM_NCACTIVATE => {
|
||||
let is_active = wparam == 1;
|
||||
let active_focus_changed = userdata.window_state.lock().set_active(is_active);
|
||||
if active_focus_changed {
|
||||
if is_active {
|
||||
gain_active_focus(window, userdata);
|
||||
} else {
|
||||
lose_active_focus(window, userdata);
|
||||
}
|
||||
}
|
||||
DefWindowProcW(window, msg, wparam, lparam)
|
||||
}
|
||||
|
||||
userdata.send_event(Event::WindowEvent {
|
||||
window_id: RootWindowId(WindowId(window)),
|
||||
event: Focused(true),
|
||||
});
|
||||
|
||||
WM_SETFOCUS => {
|
||||
let active_focus_changed = userdata.window_state.lock().set_focused(true);
|
||||
if active_focus_changed {
|
||||
gain_active_focus(window, userdata);
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
WM_KILLFOCUS => {
|
||||
use crate::event::{
|
||||
ElementState::Released,
|
||||
ModifiersState,
|
||||
WindowEvent::{Focused, ModifiersChanged},
|
||||
};
|
||||
for windows_keycode in event::get_pressed_keys() {
|
||||
let scancode = MapVirtualKeyA(windows_keycode as u32, MAPVK_VK_TO_VSC);
|
||||
let virtual_keycode = event::vkey_to_winit_vkey(windows_keycode);
|
||||
|
||||
#[allow(deprecated)]
|
||||
userdata.send_event(Event::WindowEvent {
|
||||
window_id: RootWindowId(WindowId(window)),
|
||||
event: WindowEvent::KeyboardInput {
|
||||
device_id: DEVICE_ID,
|
||||
input: KeyboardInput {
|
||||
scancode,
|
||||
virtual_keycode,
|
||||
state: Released,
|
||||
modifiers: event::get_key_mods(),
|
||||
},
|
||||
is_synthetic: true,
|
||||
},
|
||||
})
|
||||
let active_focus_changed = userdata.window_state.lock().set_focused(false);
|
||||
if active_focus_changed {
|
||||
lose_active_focus(window, userdata);
|
||||
}
|
||||
|
||||
userdata.window_state.lock().modifiers_state = ModifiersState::empty();
|
||||
userdata.send_event(Event::WindowEvent {
|
||||
window_id: RootWindowId(WindowId(window)),
|
||||
event: ModifiersChanged(ModifiersState::empty()),
|
||||
});
|
||||
|
||||
userdata.send_event(Event::WindowEvent {
|
||||
window_id: RootWindowId(WindowId(window)),
|
||||
event: Focused(false),
|
||||
});
|
||||
0
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,10 @@ pub struct WindowState {
|
|||
|
||||
pub ime_state: ImeState,
|
||||
pub ime_allowed: bool,
|
||||
|
||||
// Used by WM_NCACTIVATE, WM_SETFOCUS and WM_KILLFOCUS
|
||||
pub is_active: bool,
|
||||
pub is_focused: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -145,6 +149,9 @@ impl WindowState {
|
|||
|
||||
ime_state: ImeState::Disabled,
|
||||
ime_allowed: false,
|
||||
|
||||
is_active: false,
|
||||
is_focused: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,6 +177,24 @@ impl WindowState {
|
|||
{
|
||||
f(&mut self.window_flags);
|
||||
}
|
||||
|
||||
pub fn has_active_focus(&self) -> bool {
|
||||
self.is_active && self.is_focused
|
||||
}
|
||||
|
||||
// Updates is_active and returns whether active-focus state has changed
|
||||
pub fn set_active(&mut self, is_active: bool) -> bool {
|
||||
let old = self.has_active_focus();
|
||||
self.is_active = is_active;
|
||||
old != self.has_active_focus()
|
||||
}
|
||||
|
||||
// Updates is_focused and returns whether active-focus state has changed
|
||||
pub fn set_focused(&mut self, is_focused: bool) -> bool {
|
||||
let old = self.has_active_focus();
|
||||
self.is_focused = is_focused;
|
||||
old != self.has_active_focus()
|
||||
}
|
||||
}
|
||||
|
||||
impl MouseProperties {
|
||||
|
|
Loading…
Reference in a new issue