From 28ff731d3d88c67ad65cc447f1b08a91f313cb51 Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Mon, 19 May 2025 00:23:26 +0700 Subject: [PATCH 01/14] keyevent: add side-aware modifier state on Windows --- src/platform_impl/windows/event_loop.rs | 8 +++--- src/platform_impl/windows/keyboard_layout.rs | 30 ++++++++++++++------ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 6d0648174c..2e78649f11 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -934,17 +934,17 @@ fn update_modifiers(window: HWND, userdata: &WindowData) { let modifiers = { let mut layouts = LAYOUT_CACHE.lock().unwrap(); - layouts.get_agnostic_mods() + layouts.get_mods() }; let mut window_state = userdata.window_state.lock().unwrap(); - if window_state.modifiers_state != modifiers { - window_state.modifiers_state = modifiers; + if window_state.modifiers_state != modifiers.state() { + window_state.modifiers_state = modifiers.state(); // Drop lock drop(window_state); - userdata.send_window_event(window, ModifiersChanged(modifiers.into())); + userdata.send_window_event(window, ModifiersChanged(modifiers)); } } diff --git a/src/platform_impl/windows/keyboard_layout.rs b/src/platform_impl/windows/keyboard_layout.rs index a31362f386..2a8d384b8d 100644 --- a/src/platform_impl/windows/keyboard_layout.rs +++ b/src/platform_impl/windows/keyboard_layout.rs @@ -40,7 +40,8 @@ use windows_sys::Win32::UI::Input::KeyboardAndMouse::{ VK_SCROLL, VK_SELECT, VK_SEPARATOR, VK_SHIFT, VK_SLEEP, VK_SNAPSHOT, VK_SPACE, VK_SUBTRACT, VK_TAB, VK_UP, VK_VOLUME_DOWN, VK_VOLUME_MUTE, VK_VOLUME_UP, VK_XBUTTON1, VK_XBUTTON2, VK_ZOOM, }; -use winit_core::keyboard::{Key, KeyCode, ModifiersState, NamedKey, NativeKey, PhysicalKey}; +use winit_core::keyboard::{Key, KeyCode, ModifiersKeys, ModifiersState, NamedKey, NativeKey, PhysicalKey}; +use winit_core::event::Modifiers; use crate::platform_impl::{loword, primarylangid, scancode_to_physicalkey}; @@ -271,15 +272,28 @@ impl LayoutCache { } } - pub fn get_agnostic_mods(&mut self) -> ModifiersState { + pub fn get_mods(&mut self) -> Modifiers { let (_, layout) = self.get_current_layout(); let filter_out_altgr = layout.has_alt_graph && key_pressed(VK_RMENU); - let mut mods = ModifiersState::empty(); - mods.set(ModifiersState::SHIFT, key_pressed(VK_SHIFT)); - mods.set(ModifiersState::CONTROL, key_pressed(VK_CONTROL) && !filter_out_altgr); - mods.set(ModifiersState::ALT, key_pressed(VK_MENU) && !filter_out_altgr); - mods.set(ModifiersState::META, key_pressed(VK_LWIN) || key_pressed(VK_RWIN)); - mods + let mut state = ModifiersState::empty(); + let mut pressed_mods = ModifiersKeys::empty(); + + pressed_mods.set(ModifiersKeys::LSHIFT, key_pressed(VK_LSHIFT)); + pressed_mods.set(ModifiersKeys::RSHIFT, key_pressed(VK_RSHIFT)); + state.set(ModifiersState::SHIFT, pressed_mods.contains(ModifiersKeys::LSHIFT) || pressed_mods.contains(ModifiersKeys::RSHIFT)); + + pressed_mods.set(ModifiersKeys::LCONTROL, key_pressed(VK_LCONTROL) && !filter_out_altgr); + pressed_mods.set(ModifiersKeys::RCONTROL, key_pressed(VK_RCONTROL) && !filter_out_altgr); + state.set(ModifiersState::CONTROL, pressed_mods.contains(ModifiersKeys::LCONTROL) || pressed_mods.contains(ModifiersKeys::RCONTROL)); + + pressed_mods.set(ModifiersKeys::LALT, key_pressed(VK_LMENU) && !filter_out_altgr); + pressed_mods.set(ModifiersKeys::RALT, key_pressed(VK_RMENU) && !filter_out_altgr); + state.set(ModifiersState::ALT, pressed_mods.contains(ModifiersKeys::LALT) || pressed_mods.contains(ModifiersKeys::RALT)); + + pressed_mods.set(ModifiersKeys::LMETA, key_pressed(VK_LWIN)); + pressed_mods.set(ModifiersKeys::RMETA, key_pressed(VK_RWIN)); + state.set(ModifiersState::META, pressed_mods.contains(ModifiersKeys::LMETA) || pressed_mods.contains(ModifiersKeys::RMETA)); + Modifiers::new(state, pressed_mods) } fn prepare_layout(locale_id: u64) -> Layout { From a5629ee1407d6ec80cbd9feec152e945c5cc2568 Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Mon, 19 May 2025 16:34:44 +0700 Subject: [PATCH 02/14] add kbd_ev_print example --- examples/kbd_ev_print.rs | 84 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 examples/kbd_ev_print.rs diff --git a/examples/kbd_ev_print.rs b/examples/kbd_ev_print.rs new file mode 100644 index 0000000000..76c60c39e8 --- /dev/null +++ b/examples/kbd_ev_print.rs @@ -0,0 +1,84 @@ +//! Simple winit window example. + +use std::error::Error; + +use winit::application::ApplicationHandler; +use winit::event::WindowEvent; +use winit::event_loop::{ActiveEventLoop, EventLoop}; +#[cfg(web_platform)] +use winit::platform::web::WindowAttributesWeb; +use winit::window::{Window, WindowAttributes, WindowId}; + +#[path = "util/fill.rs"] +mod fill; +#[path = "util/tracing.rs"] +mod tracing; + +#[derive(Default, Debug)] +struct App { + window: Option>, +} + +impl ApplicationHandler for App { + fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { + #[cfg(not(web_platform))] + let window_attributes = WindowAttributes::default(); + #[cfg(web_platform)] + let window_attributes = WindowAttributes::default() + .with_platform_attributes(Box::new(WindowAttributesWeb::default().with_append(true))); + self.window = match event_loop.create_window(window_attributes) { + Ok(window) => Some(window), + Err(err) => { + eprintln!("error creating window: {err}"); + event_loop.exit(); + return; + }, + } + } + + fn window_event(&mut self, event_loop: &dyn ActiveEventLoop, _: WindowId, event: WindowEvent) { + println!("{event:?}"); + match event { + WindowEvent::CloseRequested => { + println!("Close was requested; stopping"); + event_loop.exit(); + }, + WindowEvent::SurfaceResized(_) => { + self.window.as_ref().expect("resize event without a window").request_redraw(); + }, + WindowEvent::RedrawRequested => { + // Redraw the application. + // + // It's preferable for applications that do not render continuously to render in + // this event rather than in AboutToWait, since rendering in here allows + // the program to gracefully handle redraws requested by the OS. + + let window = self.window.as_ref().expect("redraw request without a window"); + + // Notify that you're about to draw. + window.pre_present_notify(); + + // Draw. + fill::fill_window(window.as_ref()); + + // For contiguous redraw loop you can request a redraw from here. + // window.request_redraw(); + }, + _ => (), + } + } +} + +fn main() -> Result<(), Box> { + #[cfg(web_platform)] + console_error_panic_hook::set_once(); + + tracing::init(); + + let event_loop = EventLoop::new()?; + + // For alternative loop run options see `pump_events` and `run_on_demand` examples. + event_loop.run_app(App::default())?; + + Ok(()) +} From ae3c8da763d9ace4bc1835b6e20b3cb990e8828e Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Mon, 19 May 2025 16:51:00 +0700 Subject: [PATCH 03/14] update example --- examples/kbd_ev_print.rs | 104 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 101 insertions(+), 3 deletions(-) diff --git a/examples/kbd_ev_print.rs b/examples/kbd_ev_print.rs index 76c60c39e8..8e1cdd2f2b 100644 --- a/examples/kbd_ev_print.rs +++ b/examples/kbd_ev_print.rs @@ -1,4 +1,6 @@ -//! Simple winit window example. +//! Simple winit window example that prints keyboard events: + //! [KeyboardInput](https://docs.rs/winit/latest/winit/event/enum.WindowEvent.html#variant.KeyboardInput) + //! [ModifiersChanged](https://docs.rs/winit/latest/winit/event/enum.WindowEvent.html#variant.ModifiersChanged).) use std::error::Error; @@ -19,6 +21,86 @@ struct App { window: Option>, } + +use winit::event::{Modifiers, KeyEvent}; +// struct Modifiers + // state : ModifiersState, + // pressed_mods: ModifiersKeys , +// https://docs.rs/winit/latest/winit/keyboard/struct.ModifiersState.html +pub fn mod_state_side_agnostic_s(state:&ModifiersState) -> String { + let mut s = String::new(); + if state.contains(ModifiersState::SHIFT ){s.push_str(" ⇧ ")}else{s.push_str(" ")}; + if state.contains(ModifiersState::CONTROL){s.push_str(" ⎈ ")}else{s.push_str(" ")}; + if state.contains(ModifiersState::META ){s.push_str(" ◆ ")}else{s.push_str(" ")}; + if state.contains(ModifiersState::ALT ){s.push_str(" ⎇ ")}else{s.push_str(" ")}; + s +} +// https://docs.rs/winit/latest/winit/event/struct.Modifiers.html +pub fn mod_state_side_aware_s(mods:&Modifiers) -> String { + let mut s = String::new(); + if let ModifiersKeyState::Pressed = mods.lshift_state() {s.push_str("‹⇧"); + if let ModifiersKeyState::Pressed = mods.rshift_state() {s.push_str("›")}else{s.push_str(" ")}; + } else { + if let ModifiersKeyState::Pressed = mods.rshift_state() {s.push_str(" ⇧›")}else{s.push_str(" ")};} + if let ModifiersKeyState::Pressed = mods.lcontrol_state() {s.push_str("‹⎈"); + if let ModifiersKeyState::Pressed = mods.rcontrol_state() {s.push_str("›")}else{s.push_str(" ")}; + } else { + if let ModifiersKeyState::Pressed = mods.rcontrol_state() {s.push_str(" ⎈›")}else{s.push_str(" ")}; + } + if let ModifiersKeyState::Pressed = mods.lsuper_state() {s.push_str("‹◆"); + if let ModifiersKeyState::Pressed = mods.rsuper_state() {s.push_str("›")}else{s.push_str(" ")}; + } else { + if let ModifiersKeyState::Pressed = mods.rsuper_state() {s.push_str(" ◆›")}else{s.push_str(" ")}; + } + if let ModifiersKeyState::Pressed = mods.lalt_state() {s.push_str("‹⎇"); + if let ModifiersKeyState::Pressed = mods.ralt_state() {s.push_str("›")}else{s.push_str(" ")}; + } else { + if let ModifiersKeyState::Pressed = mods.ralt_state() {s.push_str(" ⎇›")}else{s.push_str(" ")}; + } + s +} +// pub struct KeyEvent + // physical_key: PhysicalKey, enum PhysicalKey + // Code ( KeyCode) + // �Unidentified(NativeKeyCode) + // logical_key: Key, enum Key + // Named(NamedKey) + // Character(Str) + // �Unidentified(NativeKey) + // 🕱Dead(Option) + // text : Option + // location: KeyLocation, enum KeyLocation Standard,Left,Right,Numpad + // state : ElementState, pressed/released + //🔁repeat : bool +use winit::keyboard::{PhysicalKey, Key, ModifiersState, ModifiersKeyState, KeyLocation}; +use winit::event::ElementState; +pub fn ev_key_s(key:&KeyEvent) -> String { + let mut s = String::new(); + match &key.state { + ElementState::Pressed => {s.push('↓')}, + ElementState::Released => {s.push('↑')}, + } + if key.repeat {s.push('🔁')}else{s.push(' ')}; //𜱣⚛ + match &key.physical_key { + PhysicalKey::Code (key_code ) => {s.push_str(&format!( "{:?} " ,key_code ))}, + PhysicalKey::Unidentified(key_code_native ) => {s.push_str(&format!("�{:?} ",key_code_native))}, + }; + match &key.logical_key { + Key ::Named (key_named ) => {s.push_str(&format!("{:?} " ,key_named ))}, + Key ::Character (key_char ) => {s.push_str(&format!("{} " ,key_char ))}, + Key ::Unidentified(key_native ) => {s.push_str(&format!("�{:?} ",key_native ))}, + Key ::Dead (maybe_char ) => {s.push_str(&format!("🕱{:?} " ,maybe_char ))}, + }; + match &key.location { + KeyLocation::Standard => {s.push('≝')}, + KeyLocation::Left => {s.push('←')}, + KeyLocation::Right => {s.push('→')}, + KeyLocation::Numpad => {s.push('🔢')}, + } + s +} + +use winit_core::keyboard::NamedKey; impl ApplicationHandler for App { fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { #[cfg(not(web_platform))] @@ -37,10 +119,26 @@ impl ApplicationHandler for App { } fn window_event(&mut self, event_loop: &dyn ActiveEventLoop, _: WindowId, event: WindowEvent) { - println!("{event:?}"); match event { + WindowEvent::ModifiersChanged(mods) => { + let state = mods.state(); + let state_s = mod_state_side_agnostic_s(&state); + let pressed_mods_s = mod_state_side_aware_s(&mods); + println!("Δ {}\tside-agnostic\n {}\tside-aware",state_s, pressed_mods_s); + }, + WindowEvent::KeyboardInput { event, is_synthetic, .. } => { + let is_synthetic_s = if is_synthetic{"⚗"}else{" "}; + let key_event_s = ev_key_s(&event); + println!("🖮 {}{}",is_synthetic_s,key_event_s); + + match event.logical_key.as_ref() { + Key::Named(NamedKey::Escape) => { + event_loop.exit(); + }, + _ => (), + } + }, WindowEvent::CloseRequested => { - println!("Close was requested; stopping"); event_loop.exit(); }, WindowEvent::SurfaceResized(_) => { From 729f04b006e29ed2d2f6b71727d628335e037e60 Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Mon, 19 May 2025 17:10:14 +0700 Subject: [PATCH 04/14] fmt example --- examples/kbd_ev_print.rs | 210 +++++++++++++++++++++++++-------------- 1 file changed, 134 insertions(+), 76 deletions(-) diff --git a/examples/kbd_ev_print.rs b/examples/kbd_ev_print.rs index 8e1cdd2f2b..496e1eccc3 100644 --- a/examples/kbd_ev_print.rs +++ b/examples/kbd_ev_print.rs @@ -1,6 +1,6 @@ //! Simple winit window example that prints keyboard events: - //! [KeyboardInput](https://docs.rs/winit/latest/winit/event/enum.WindowEvent.html#variant.KeyboardInput) - //! [ModifiersChanged](https://docs.rs/winit/latest/winit/event/enum.WindowEvent.html#variant.ModifiersChanged).) +//! [KeyboardInput](https://docs.rs/winit/latest/winit/event/enum.WindowEvent.html#variant.KeyboardInput) +//! [ModifiersChanged](https://docs.rs/winit/latest/winit/event/enum.WindowEvent.html#variant.ModifiersChanged).) use std::error::Error; @@ -21,83 +21,141 @@ struct App { window: Option>, } - -use winit::event::{Modifiers, KeyEvent}; +use winit::event::{KeyEvent, Modifiers}; // struct Modifiers - // state : ModifiersState, - // pressed_mods: ModifiersKeys , +// state : ModifiersState, +// pressed_mods: ModifiersKeys , // https://docs.rs/winit/latest/winit/keyboard/struct.ModifiersState.html -pub fn mod_state_side_agnostic_s(state:&ModifiersState) -> String { - let mut s = String::new(); - if state.contains(ModifiersState::SHIFT ){s.push_str(" ⇧ ")}else{s.push_str(" ")}; - if state.contains(ModifiersState::CONTROL){s.push_str(" ⎈ ")}else{s.push_str(" ")}; - if state.contains(ModifiersState::META ){s.push_str(" ◆ ")}else{s.push_str(" ")}; - if state.contains(ModifiersState::ALT ){s.push_str(" ⎇ ")}else{s.push_str(" ")}; - s +pub fn mod_state_side_agnostic_s(state: &ModifiersState) -> String { + let mut s = String::new(); + if state.contains(ModifiersState::SHIFT) { + s.push_str(" ⇧ ") + } else { + s.push_str(" ") + }; + if state.contains(ModifiersState::CONTROL) { + s.push_str(" ⎈ ") + } else { + s.push_str(" ") + }; + if state.contains(ModifiersState::META) { + s.push_str(" ◆ ") + } else { + s.push_str(" ") + }; + if state.contains(ModifiersState::ALT) { + s.push_str(" ⎇ ") + } else { + s.push_str(" ") + }; + s } // https://docs.rs/winit/latest/winit/event/struct.Modifiers.html -pub fn mod_state_side_aware_s(mods:&Modifiers) -> String { - let mut s = String::new(); - if let ModifiersKeyState::Pressed = mods.lshift_state() {s.push_str("‹⇧"); - if let ModifiersKeyState::Pressed = mods.rshift_state() {s.push_str("›")}else{s.push_str(" ")}; - } else { - if let ModifiersKeyState::Pressed = mods.rshift_state() {s.push_str(" ⇧›")}else{s.push_str(" ")};} - if let ModifiersKeyState::Pressed = mods.lcontrol_state() {s.push_str("‹⎈"); - if let ModifiersKeyState::Pressed = mods.rcontrol_state() {s.push_str("›")}else{s.push_str(" ")}; - } else { - if let ModifiersKeyState::Pressed = mods.rcontrol_state() {s.push_str(" ⎈›")}else{s.push_str(" ")}; - } - if let ModifiersKeyState::Pressed = mods.lsuper_state() {s.push_str("‹◆"); - if let ModifiersKeyState::Pressed = mods.rsuper_state() {s.push_str("›")}else{s.push_str(" ")}; - } else { - if let ModifiersKeyState::Pressed = mods.rsuper_state() {s.push_str(" ◆›")}else{s.push_str(" ")}; - } - if let ModifiersKeyState::Pressed = mods.lalt_state() {s.push_str("‹⎇"); - if let ModifiersKeyState::Pressed = mods.ralt_state() {s.push_str("›")}else{s.push_str(" ")}; - } else { - if let ModifiersKeyState::Pressed = mods.ralt_state() {s.push_str(" ⎇›")}else{s.push_str(" ")}; - } - s +pub fn mod_state_side_aware_s(mods: &Modifiers) -> String { + let mut s = String::new(); + if let ModifiersKeyState::Pressed = mods.lshift_state() { + s.push_str("‹⇧"); + if let ModifiersKeyState::Pressed = mods.rshift_state() { + s.push_str("›") + } else { + s.push_str(" ") + }; + } else { + if let ModifiersKeyState::Pressed = mods.rshift_state() { + s.push_str(" ⇧›") + } else { + s.push_str(" ") + }; + } + if let ModifiersKeyState::Pressed = mods.lcontrol_state() { + s.push_str("‹⎈"); + if let ModifiersKeyState::Pressed = mods.rcontrol_state() { + s.push_str("›") + } else { + s.push_str(" ") + }; + } else { + if let ModifiersKeyState::Pressed = mods.rcontrol_state() { + s.push_str(" ⎈›") + } else { + s.push_str(" ") + }; + } + if let ModifiersKeyState::Pressed = mods.lsuper_state() { + s.push_str("‹◆"); + if let ModifiersKeyState::Pressed = mods.rsuper_state() { + s.push_str("›") + } else { + s.push_str(" ") + }; + } else { + if let ModifiersKeyState::Pressed = mods.rsuper_state() { + s.push_str(" ◆›") + } else { + s.push_str(" ") + }; + } + if let ModifiersKeyState::Pressed = mods.lalt_state() { + s.push_str("‹⎇"); + if let ModifiersKeyState::Pressed = mods.ralt_state() { + s.push_str("›") + } else { + s.push_str(" ") + }; + } else { + if let ModifiersKeyState::Pressed = mods.ralt_state() { + s.push_str(" ⎇›") + } else { + s.push_str(" ") + }; + } + s } // pub struct KeyEvent - // physical_key: PhysicalKey, enum PhysicalKey - // Code ( KeyCode) - // �Unidentified(NativeKeyCode) - // logical_key: Key, enum Key - // Named(NamedKey) - // Character(Str) - // �Unidentified(NativeKey) - // 🕱Dead(Option) - // text : Option - // location: KeyLocation, enum KeyLocation Standard,Left,Right,Numpad - // state : ElementState, pressed/released - //🔁repeat : bool -use winit::keyboard::{PhysicalKey, Key, ModifiersState, ModifiersKeyState, KeyLocation}; +// physical_key: PhysicalKey, enum PhysicalKey +// Code ( KeyCode) +// �Unidentified(NativeKeyCode) +// logical_key: Key, enum Key +// Named(NamedKey) +// Character(Str) +// �Unidentified(NativeKey) +// 🕱Dead(Option) +// text : Option +// location: KeyLocation, enum KeyLocation Standard,Left,Right,Numpad +// state : ElementState, pressed/released +//🔁repeat : bool use winit::event::ElementState; -pub fn ev_key_s(key:&KeyEvent) -> String { - let mut s = String::new(); - match &key.state { - ElementState::Pressed => {s.push('↓')}, - ElementState::Released => {s.push('↑')}, - } - if key.repeat {s.push('🔁')}else{s.push(' ')}; //𜱣⚛ - match &key.physical_key { - PhysicalKey::Code (key_code ) => {s.push_str(&format!( "{:?} " ,key_code ))}, - PhysicalKey::Unidentified(key_code_native ) => {s.push_str(&format!("�{:?} ",key_code_native))}, - }; - match &key.logical_key { - Key ::Named (key_named ) => {s.push_str(&format!("{:?} " ,key_named ))}, - Key ::Character (key_char ) => {s.push_str(&format!("{} " ,key_char ))}, - Key ::Unidentified(key_native ) => {s.push_str(&format!("�{:?} ",key_native ))}, - Key ::Dead (maybe_char ) => {s.push_str(&format!("🕱{:?} " ,maybe_char ))}, - }; - match &key.location { - KeyLocation::Standard => {s.push('≝')}, - KeyLocation::Left => {s.push('←')}, - KeyLocation::Right => {s.push('→')}, - KeyLocation::Numpad => {s.push('🔢')}, - } - s +use winit::keyboard::{Key, KeyLocation, ModifiersKeyState, ModifiersState, PhysicalKey}; +pub fn ev_key_s(key: &KeyEvent) -> String { + let mut s = String::new(); + match &key.state { + ElementState::Pressed => s.push('↓'), + ElementState::Released => s.push('↑'), + } + if key.repeat { + s.push('🔁') + } else { + s.push(' ') + }; //𜱣⚛ + match &key.physical_key { + PhysicalKey::Code(key_code) => s.push_str(&format!("{:?} ", key_code)), + PhysicalKey::Unidentified(key_code_native) => { + s.push_str(&format!("�{:?} ", key_code_native)) + }, + }; + match &key.logical_key { + Key::Named(key_named) => s.push_str(&format!("{:?} ", key_named)), + Key::Character(key_char) => s.push_str(&format!("{} ", key_char)), + Key::Unidentified(key_native) => s.push_str(&format!("�{:?} ", key_native)), + Key::Dead(maybe_char) => s.push_str(&format!("🕱{:?} ", maybe_char)), + }; + match &key.location { + KeyLocation::Standard => s.push('≝'), + KeyLocation::Left => s.push('←'), + KeyLocation::Right => s.push('→'), + KeyLocation::Numpad => s.push('🔢'), + } + s } use winit_core::keyboard::NamedKey; @@ -121,15 +179,15 @@ impl ApplicationHandler for App { fn window_event(&mut self, event_loop: &dyn ActiveEventLoop, _: WindowId, event: WindowEvent) { match event { WindowEvent::ModifiersChanged(mods) => { - let state = mods.state(); + let state = mods.state(); let state_s = mod_state_side_agnostic_s(&state); let pressed_mods_s = mod_state_side_aware_s(&mods); - println!("Δ {}\tside-agnostic\n {}\tside-aware",state_s, pressed_mods_s); + println!("Δ {}\tside-agnostic\n {}\tside-aware", state_s, pressed_mods_s); }, WindowEvent::KeyboardInput { event, is_synthetic, .. } => { - let is_synthetic_s = if is_synthetic{"⚗"}else{" "}; + let is_synthetic_s = if is_synthetic { "⚗" } else { " " }; let key_event_s = ev_key_s(&event); - println!("🖮 {}{}",is_synthetic_s,key_event_s); + println!("🖮 {}{}", is_synthetic_s, key_event_s); match event.logical_key.as_ref() { Key::Named(NamedKey::Escape) => { From 57fdf68231544e9aefb460ff5c914ba9805243ec Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Mon, 19 May 2025 17:10:16 +0700 Subject: [PATCH 05/14] fmt --- src/platform_impl/windows/keyboard_layout.rs | 28 ++++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/platform_impl/windows/keyboard_layout.rs b/src/platform_impl/windows/keyboard_layout.rs index 2a8d384b8d..655003578f 100644 --- a/src/platform_impl/windows/keyboard_layout.rs +++ b/src/platform_impl/windows/keyboard_layout.rs @@ -40,8 +40,10 @@ use windows_sys::Win32::UI::Input::KeyboardAndMouse::{ VK_SCROLL, VK_SELECT, VK_SEPARATOR, VK_SHIFT, VK_SLEEP, VK_SNAPSHOT, VK_SPACE, VK_SUBTRACT, VK_TAB, VK_UP, VK_VOLUME_DOWN, VK_VOLUME_MUTE, VK_VOLUME_UP, VK_XBUTTON1, VK_XBUTTON2, VK_ZOOM, }; -use winit_core::keyboard::{Key, KeyCode, ModifiersKeys, ModifiersState, NamedKey, NativeKey, PhysicalKey}; use winit_core::event::Modifiers; +use winit_core::keyboard::{ + Key, KeyCode, ModifiersKeys, ModifiersState, NamedKey, NativeKey, PhysicalKey, +}; use crate::platform_impl::{loword, primarylangid, scancode_to_physicalkey}; @@ -280,19 +282,35 @@ impl LayoutCache { pressed_mods.set(ModifiersKeys::LSHIFT, key_pressed(VK_LSHIFT)); pressed_mods.set(ModifiersKeys::RSHIFT, key_pressed(VK_RSHIFT)); - state.set(ModifiersState::SHIFT, pressed_mods.contains(ModifiersKeys::LSHIFT) || pressed_mods.contains(ModifiersKeys::RSHIFT)); + state.set( + ModifiersState::SHIFT, + pressed_mods.contains(ModifiersKeys::LSHIFT) + || pressed_mods.contains(ModifiersKeys::RSHIFT), + ); pressed_mods.set(ModifiersKeys::LCONTROL, key_pressed(VK_LCONTROL) && !filter_out_altgr); pressed_mods.set(ModifiersKeys::RCONTROL, key_pressed(VK_RCONTROL) && !filter_out_altgr); - state.set(ModifiersState::CONTROL, pressed_mods.contains(ModifiersKeys::LCONTROL) || pressed_mods.contains(ModifiersKeys::RCONTROL)); + state.set( + ModifiersState::CONTROL, + pressed_mods.contains(ModifiersKeys::LCONTROL) + || pressed_mods.contains(ModifiersKeys::RCONTROL), + ); pressed_mods.set(ModifiersKeys::LALT, key_pressed(VK_LMENU) && !filter_out_altgr); pressed_mods.set(ModifiersKeys::RALT, key_pressed(VK_RMENU) && !filter_out_altgr); - state.set(ModifiersState::ALT, pressed_mods.contains(ModifiersKeys::LALT) || pressed_mods.contains(ModifiersKeys::RALT)); + state.set( + ModifiersState::ALT, + pressed_mods.contains(ModifiersKeys::LALT) + || pressed_mods.contains(ModifiersKeys::RALT), + ); pressed_mods.set(ModifiersKeys::LMETA, key_pressed(VK_LWIN)); pressed_mods.set(ModifiersKeys::RMETA, key_pressed(VK_RWIN)); - state.set(ModifiersState::META, pressed_mods.contains(ModifiersKeys::LMETA) || pressed_mods.contains(ModifiersKeys::RMETA)); + state.set( + ModifiersState::META, + pressed_mods.contains(ModifiersKeys::LMETA) + || pressed_mods.contains(ModifiersKeys::RMETA), + ); Modifiers::new(state, pressed_mods) } From 7f9788a87f2ffd5a7dbd31f35b65b508f5d2a95f Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Mon, 19 May 2025 17:15:45 +0700 Subject: [PATCH 06/14] Windows: update side-aware `event::Modifiers` information on state change. --- src/changelog/unreleased.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index 67ea934912..13f80dd3d1 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -201,6 +201,7 @@ changelog entry. - Move `IconExtWindows` into `WinIcon`. - Move `EventLoopExtPumpEvents` and `PumpStatus` from platform module to `winit::event_loop::pump_events`. - Move `EventLoopExtRunOnDemand` from platform module to `winit::event_loop::run_on_demand`. +- On Windows, update side-aware `event::Modifiers` information on state change. ### Removed From 19d9ce087eede692432ff2059b972f5d4c68384c Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Mon, 19 May 2025 17:24:07 +0700 Subject: [PATCH 07/14] clippy --- examples/kbd_ev_print.rs | 55 ++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/examples/kbd_ev_print.rs b/examples/kbd_ev_print.rs index 496e1eccc3..8606cf10b4 100644 --- a/examples/kbd_ev_print.rs +++ b/examples/kbd_ev_print.rs @@ -56,58 +56,50 @@ pub fn mod_state_side_aware_s(mods: &Modifiers) -> String { if let ModifiersKeyState::Pressed = mods.lshift_state() { s.push_str("‹⇧"); if let ModifiersKeyState::Pressed = mods.rshift_state() { - s.push_str("›") + s.push('›') } else { - s.push_str(" ") + s.push(' ') }; + } else if let ModifiersKeyState::Pressed = mods.rshift_state() { + s.push_str(" ⇧›") } else { - if let ModifiersKeyState::Pressed = mods.rshift_state() { - s.push_str(" ⇧›") - } else { - s.push_str(" ") - }; + s.push_str(" ") } if let ModifiersKeyState::Pressed = mods.lcontrol_state() { s.push_str("‹⎈"); if let ModifiersKeyState::Pressed = mods.rcontrol_state() { - s.push_str("›") + s.push('›') } else { - s.push_str(" ") + s.push(' ') }; + } else if let ModifiersKeyState::Pressed = mods.rcontrol_state() { + s.push_str(" ⎈›") } else { - if let ModifiersKeyState::Pressed = mods.rcontrol_state() { - s.push_str(" ⎈›") - } else { - s.push_str(" ") - }; + s.push_str(" ") } if let ModifiersKeyState::Pressed = mods.lsuper_state() { s.push_str("‹◆"); if let ModifiersKeyState::Pressed = mods.rsuper_state() { - s.push_str("›") + s.push('›') } else { - s.push_str(" ") + s.push(' ') }; + } else if let ModifiersKeyState::Pressed = mods.rsuper_state() { + s.push_str(" ◆›") } else { - if let ModifiersKeyState::Pressed = mods.rsuper_state() { - s.push_str(" ◆›") - } else { - s.push_str(" ") - }; + s.push_str(" ") } if let ModifiersKeyState::Pressed = mods.lalt_state() { s.push_str("‹⎇"); if let ModifiersKeyState::Pressed = mods.ralt_state() { - s.push_str("›") + s.push('›') } else { - s.push_str(" ") + s.push(' ') }; + } else if let ModifiersKeyState::Pressed = mods.ralt_state() { + s.push_str(" ⎇›") } else { - if let ModifiersKeyState::Pressed = mods.ralt_state() { - s.push_str(" ⎇›") - } else { - s.push_str(" ") - }; + s.push_str(" ") } s } @@ -189,11 +181,8 @@ impl ApplicationHandler for App { let key_event_s = ev_key_s(&event); println!("🖮 {}{}", is_synthetic_s, key_event_s); - match event.logical_key.as_ref() { - Key::Named(NamedKey::Escape) => { - event_loop.exit(); - }, - _ => (), + if let Key::Named(NamedKey::Escape) = event.logical_key.as_ref() { + event_loop.exit(); } }, WindowEvent::CloseRequested => { From f54ff8804240ba393695c47f39d7e871bd9ca94b Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Mon, 19 May 2025 17:27:50 +0700 Subject: [PATCH 08/14] don't quit on Escape --- examples/kbd_ev_print.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/examples/kbd_ev_print.rs b/examples/kbd_ev_print.rs index 8606cf10b4..44b1fffab8 100644 --- a/examples/kbd_ev_print.rs +++ b/examples/kbd_ev_print.rs @@ -150,7 +150,6 @@ pub fn ev_key_s(key: &KeyEvent) -> String { s } -use winit_core::keyboard::NamedKey; impl ApplicationHandler for App { fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { #[cfg(not(web_platform))] @@ -180,10 +179,6 @@ impl ApplicationHandler for App { let is_synthetic_s = if is_synthetic { "⚗" } else { " " }; let key_event_s = ev_key_s(&event); println!("🖮 {}{}", is_synthetic_s, key_event_s); - - if let Key::Named(NamedKey::Escape) = event.logical_key.as_ref() { - event_loop.exit(); - } }, WindowEvent::CloseRequested => { event_loop.exit(); From d6c38257c6e55cae15377fcf32d3d3a4ea8c0b6b Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Mon, 19 May 2025 18:04:43 +0700 Subject: [PATCH 09/14] add more info to examples --- examples/kbd_ev_print.rs | 41 ++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/examples/kbd_ev_print.rs b/examples/kbd_ev_print.rs index 44b1fffab8..015814442a 100644 --- a/examples/kbd_ev_print.rs +++ b/examples/kbd_ev_print.rs @@ -129,18 +129,40 @@ pub fn ev_key_s(key: &KeyEvent) -> String { } else { s.push(' ') }; //𜱣⚛ + s.push(' '); match &key.physical_key { - PhysicalKey::Code(key_code) => s.push_str(&format!("{:?} ", key_code)), + PhysicalKey::Code(key_code) => s.push_str(&format!("{:?}", key_code)), PhysicalKey::Unidentified(key_code_native) => { - s.push_str(&format!("�{:?} ", key_code_native)) + s.push_str(&format!("�{:?}", key_code_native)) }, }; + s.push(' '); match &key.logical_key { - Key::Named(key_named) => s.push_str(&format!("{:?} ", key_named)), - Key::Character(key_char) => s.push_str(&format!("{} ", key_char)), - Key::Unidentified(key_native) => s.push_str(&format!("�{:?} ", key_native)), - Key::Dead(maybe_char) => s.push_str(&format!("🕱{:?} ", maybe_char)), + Key::Named(key_named) => s.push_str(&format!("{:?}", key_named)), + Key::Character(key_char) => s.push_str(&format!("{}", key_char)), + Key::Unidentified(key_native) => s.push_str(&format!("�{:?}", key_native)), + Key::Dead(maybe_char) => s.push_str(&format!("🕱{:?}", maybe_char)), }; + s.push_str(" "); + if let Some(txt) = &key.text { + s.push_str(&format!("{}", txt)); + } else { + s.push(' '); + } + s.push(' '); + if let Some(txt) = &key.text_with_all_modifiers { + s.push_str(&format!("{}", txt)); + } else { + s.push(' '); + } + s.push(' '); + match &key.key_without_modifiers { + Key::Named(key_named) => s.push_str(&format!("{:?}", key_named)), + Key::Character(key_char) => s.push_str(&format!("{}", key_char)), + Key::Unidentified(key_native) => s.push_str(&format!("�{:?}", key_native)), + Key::Dead(maybe_char) => s.push_str(&format!("🕱{:?}", maybe_char)), + }; + s.push_str(" "); match &key.location { KeyLocation::Standard => s.push('≝'), KeyLocation::Left => s.push('←'), @@ -217,6 +239,13 @@ fn main() -> Result<(), Box> { let event_loop = EventLoop::new()?; + println!( + "Δ is ModifiersChanged event, showing (line #1) side-agnostic modifier state as well as \ + (#2) side-aware one." + ); + println!("🖮 is KeyboardInput: ⚗=synthetic, ↓↑=pressed/released 🔁=repeat"); + println!(" phys logic txt +mod −mod location"); + // For alternative loop run options see `pump_events` and `run_on_demand` examples. event_loop.run_app(App::default())?; From 8b891bab68a0f0faf25f5537029d1ab23614d3dd Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Tue, 20 May 2025 17:25:57 +0700 Subject: [PATCH 10/14] update changelog --- src/changelog/unreleased.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index 13f80dd3d1..3df56f7002 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -81,6 +81,7 @@ changelog entry. - `keyboard::ModifiersKey` to track which modifier is exactly pressed. - `ActivationToken::as_raw` to get a ref to raw token. - Each platform now has corresponding `WindowAttributes` struct instead of trait extension. +- On Windows, update side-aware `event::Modifiers` information on state change. ### Changed @@ -201,7 +202,6 @@ changelog entry. - Move `IconExtWindows` into `WinIcon`. - Move `EventLoopExtPumpEvents` and `PumpStatus` from platform module to `winit::event_loop::pump_events`. - Move `EventLoopExtRunOnDemand` from platform module to `winit::event_loop::run_on_demand`. -- On Windows, update side-aware `event::Modifiers` information on state change. ### Removed From 2ce6f6e7d34245414f0ca5cef3b254c0528c80e4 Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Tue, 20 May 2025 17:35:48 +0700 Subject: [PATCH 11/14] undo removing into --- src/platform_impl/windows/event_loop.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 2e78649f11..48c62f7657 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -944,7 +944,7 @@ fn update_modifiers(window: HWND, userdata: &WindowData) { // Drop lock drop(window_state); - userdata.send_window_event(window, ModifiersChanged(modifiers)); + userdata.send_window_event(window, ModifiersChanged(modifiers.into())); } } From e4139a63297c3d0d9cfa638ff02c447bbfa0c6e3 Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Tue, 20 May 2025 18:02:26 +0700 Subject: [PATCH 12/14] clippy --- src/platform_impl/windows/event_loop.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 48c62f7657..2e78649f11 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -944,7 +944,7 @@ fn update_modifiers(window: HWND, userdata: &WindowData) { // Drop lock drop(window_state); - userdata.send_window_event(window, ModifiersChanged(modifiers.into())); + userdata.send_window_event(window, ModifiersChanged(modifiers)); } } From db353a6126e0f2efd069889cf2ea62d1d8a9d926 Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Tue, 20 May 2025 18:54:24 +0700 Subject: [PATCH 13/14] save 1 keystate call for Shift --- src/platform_impl/windows/keyboard_layout.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/platform_impl/windows/keyboard_layout.rs b/src/platform_impl/windows/keyboard_layout.rs index 655003578f..b929d34c6b 100644 --- a/src/platform_impl/windows/keyboard_layout.rs +++ b/src/platform_impl/windows/keyboard_layout.rs @@ -280,12 +280,14 @@ impl LayoutCache { let mut state = ModifiersState::empty(); let mut pressed_mods = ModifiersKeys::empty(); - pressed_mods.set(ModifiersKeys::LSHIFT, key_pressed(VK_LSHIFT)); - pressed_mods.set(ModifiersKeys::RSHIFT, key_pressed(VK_RSHIFT)); - state.set( - ModifiersState::SHIFT, - pressed_mods.contains(ModifiersKeys::LSHIFT) - || pressed_mods.contains(ModifiersKeys::RSHIFT), + state.set(ModifiersState::SHIFT, key_pressed(VK_SHIFT)); + pressed_mods.set( + ModifiersKeys::LSHIFT, + state.contains(ModifiersState::SHIFT) && key_pressed(VK_LSHIFT), + ); + pressed_mods.set( + ModifiersKeys::RSHIFT, + state.contains(ModifiersState::SHIFT) && key_pressed(VK_RSHIFT), ); pressed_mods.set(ModifiersKeys::LCONTROL, key_pressed(VK_LCONTROL) && !filter_out_altgr); From 96feb0015aa741d9f8fb0ca4df88d8093d5027a4 Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Wed, 21 May 2025 01:56:41 +0700 Subject: [PATCH 14/14] add side-aware keys comparison on mod update --- src/platform_impl/windows/event_loop.rs | 9 ++++++++- src/platform_impl/windows/window_state.rs | 4 +++- winit-core/src/event.rs | 5 +++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 2e78649f11..2e05e3c2bc 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -937,10 +937,17 @@ fn update_modifiers(window: HWND, userdata: &WindowData) { layouts.get_mods() }; + let mut send_event = false; let mut window_state = userdata.window_state.lock().unwrap(); + if window_state.modifiers_keys != modifiers.pressed_mods() { + window_state.modifiers_keys = modifiers.pressed_mods(); + send_event = true; + } if window_state.modifiers_state != modifiers.state() { window_state.modifiers_state = modifiers.state(); - + send_event = true; + } + if send_event { // Drop lock drop(window_state); diff --git a/src/platform_impl/windows/window_state.rs b/src/platform_impl/windows/window_state.rs index a0ca3a539e..52ad4f8c59 100644 --- a/src/platform_impl/windows/window_state.rs +++ b/src/platform_impl/windows/window_state.rs @@ -17,7 +17,7 @@ use windows_sys::Win32::UI::WindowsAndMessaging::{ WS_MINIMIZEBOX, WS_OVERLAPPEDWINDOW, WS_POPUP, WS_SIZEBOX, WS_SYSMENU, WS_VISIBLE, }; use winit_core::icon::Icon; -use winit_core::keyboard::ModifiersState; +use winit_core::keyboard::{ModifiersKeys, ModifiersState}; use winit_core::monitor::Fullscreen; use winit_core::window::{Theme, WindowAttributes}; @@ -41,6 +41,7 @@ pub(crate) struct WindowState { pub scale_factor: f64, pub modifiers_state: ModifiersState, + pub modifiers_keys: ModifiersKeys, pub fullscreen: Option, pub current_theme: Theme, pub preferred_theme: Option, @@ -172,6 +173,7 @@ impl WindowState { scale_factor, modifiers_state: ModifiersState::default(), + modifiers_keys: ModifiersKeys::default(), fullscreen: None, current_theme, preferred_theme, diff --git a/winit-core/src/event.rs b/winit-core/src/event.rs index 416723749c..68de2f63bb 100644 --- a/winit-core/src/event.rs +++ b/winit-core/src/event.rs @@ -825,6 +825,11 @@ impl Modifiers { self.state } + /// The logical state of the modifier keys. + pub fn pressed_mods(&self) -> ModifiersKeys { + self.pressed_mods + } + /// The logical state of the left shift key. pub fn lshift_state(&self) -> ModifiersKeyState { self.mod_state(ModifiersKeys::LSHIFT)