Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
150 changes: 88 additions & 62 deletions src/platform_impl/windows/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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.
//
Expand Down Expand Up @@ -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
}

Expand Down
25 changes: 25 additions & 0 deletions src/platform_impl/windows/window_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -145,6 +149,9 @@ impl WindowState {

ime_state: ImeState::Disabled,
ime_allowed: false,

is_active: false,
is_focused: false,
}
}

Expand All @@ -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 {
Expand Down