diff --git a/CHANGELOG.md b/CHANGELOG.md index 537053154..af96a9808 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 additional parameter controlling whether to position the window with the initial value of the dynamic or whether to let the operating system perform the initial positioning. +- Keyboard modifiers have been added to two event structures: `ButtonClick` and + `KeyboardEvent`. Because of this change, `KeyboardEvent` no longer implements + `From`. Instead, a new api `KeyEvent::from_winit` + allows constructing from both the modifiers and key event. ### Changed @@ -85,6 +89,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `Window::inner_position` - `Window::maximized` - `Window::minimized` + - `Window::modifiers` - `Window::outer_position` - `Window::outer_size` - `Window::resize_increments` diff --git a/src/widgets/button.rs b/src/widgets/button.rs index 7f5ea6e27..653f3907a 100644 --- a/src/widgets/button.rs +++ b/src/widgets/button.rs @@ -3,7 +3,7 @@ use std::time::Duration; use figures::units::{Lp, Px, UPx}; use figures::{IntoSigned, Point, Rect, Round, ScreenScale, Size}; -use kludgine::app::winit::event::MouseButton; +use kludgine::app::winit::event::{Modifiers, MouseButton}; use kludgine::app::winit::window::CursorIcon; use kludgine::shapes::{Shape, StrokeOptions}; use kludgine::Color; @@ -40,6 +40,7 @@ pub struct Button { #[derive(Debug, Default)] struct PerWindow { buttons_pressed: usize, + modifiers: Modifiers, cached_state: CacheState, active_colors: Option>, color_animation: AnimationHandle, @@ -432,7 +433,9 @@ impl Widget for Button { _button: MouseButton, context: &mut EventContext<'_>, ) -> EventHandling { - self.per_window.entry(context).or_default().buttons_pressed += 1; + let per_window = self.per_window.entry(context).or_default(); + per_window.buttons_pressed += 1; + per_window.modifiers = context.modifiers(); context.activate(); HANDLED } @@ -475,11 +478,13 @@ impl Widget for Button { if Rect::from(last_layout.size).contains(location) { context.focus(); + let modifiers = window_local.modifiers; self.invoke_on_click( Some(ButtonClick { mouse_button: button, location, window_location: location + last_layout.origin, + modifiers, }), context, ); @@ -598,4 +603,7 @@ pub struct ButtonClick { pub location: Point, /// The location relative to the window of the click. pub window_location: Point, + + /// The keyboard modifiers state when this click began. + pub modifiers: Modifiers, } diff --git a/src/window.rs b/src/window.rs index b49515141..a11f4e97a 100644 --- a/src/window.rs +++ b/src/window.rs @@ -550,6 +550,7 @@ where outer_position: Option>>, close_requested: Option>, icon: Option>>, + modifiers: Option>, } impl Default for Window @@ -642,6 +643,7 @@ where inner_position: None, outer_position: None, icon: None, + modifiers: None, } } @@ -982,6 +984,13 @@ where self.icon = Some(icon.into_value()); self } + + /// Sets `modifiers` to contain the state of the keyboard modifiers when + /// this window has keyboard focus. + pub fn modifiers(mut self, modifiers: impl IntoDynamic) -> Self { + self.modifiers = Some(modifiers.into_dynamic()); + self + } } impl Run for Window @@ -1050,6 +1059,7 @@ where outer_position: this.outer_position.unwrap_or_default(), outer_size: this.outer_size.unwrap_or_default(), window_icon: this.icon.unwrap_or_default(), + modifiers: this.modifiers.unwrap_or_default(), }), pending: this.pending, }, @@ -1207,6 +1217,7 @@ struct OpenWindow { outer_position: Tracked>>, inner_position: Dynamic>, window_icon: Tracked>>, + modifiers: Dynamic, } impl OpenWindow @@ -1643,6 +1654,7 @@ where inner_position: settings.inner_position, outer_position: Tracked::from(settings.outer_position).ignoring_first(), window_icon: Tracked::from(settings.window_icon), + modifiers: settings.modifiers, }; this.synchronize_platform_window(&mut window); @@ -2469,13 +2481,8 @@ where input: winit::event::KeyEvent, is_synthetic: bool, ) { - self.keyboard_input( - window, - kludgine, - device_id.into(), - input.into(), - is_synthetic, - ); + let event = KeyEvent::from_winit(input, window.modifiers()); + self.keyboard_input(window, kludgine, device_id.into(), event, is_synthetic); } fn mouse_wheel( @@ -2489,7 +2496,13 @@ where self.mouse_wheel(window, kludgine, device_id.into(), delta, phase); } - // fn modifiers_changed(&mut self, window: kludgine::app::Window<'_, ()>) {} + fn modifiers_changed( + &mut self, + window: kludgine::app::Window<'_, WindowCommand>, + _kludgine: &mut Kludgine, + ) { + self.modifiers.set(window.modifiers()); + } fn ime( &mut self, @@ -2673,6 +2686,7 @@ pub(crate) mod sealed { use figures::units::{Px, UPx}; use figures::{Fraction, Point, Size}; use image::{DynamicImage, RgbaImage}; + use kludgine::app::winit::event::Modifiers; use kludgine::app::winit::window::{UserAttentionType, WindowLevel}; use kludgine::Color; use parking_lot::Mutex; @@ -2731,6 +2745,7 @@ pub(crate) mod sealed { pub outer_position: Dynamic>, pub outer_size: Dynamic>, pub window_icon: Value>, + pub modifiers: Dynamic, } #[derive(Debug, Clone)] @@ -3343,6 +3358,7 @@ impl StandaloneWindowBuilder { outer_position: Dynamic::default(), outer_size: Dynamic::default(), window_icon: Value::Constant(None), + modifiers: Dynamic::default(), }, ); @@ -4348,6 +4364,7 @@ where state: ElementState::Pressed, repeat: false, location: KeyLocation::Standard, + modifiers: Modifiers::default(), }; self.recorder .window @@ -4379,6 +4396,7 @@ where location: KeyLocation::Standard, state: ElementState::Pressed, repeat: false, + modifiers: Modifiers::default(), }; let _handled = self.recorder @@ -4661,7 +4679,7 @@ impl FrameAssembler { } /// Describes a keyboard input targeting a window. -#[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct KeyEvent { /// The logical key that is interpretted from the `physical_key`. /// @@ -4697,10 +4715,15 @@ pub struct KeyEvent { /// See [`KeyEvent::logical_key`](winit::event::KeyEvent::logical_key) for /// more information. pub repeat: bool, + + /// The modifiers state active for this event. + pub modifiers: Modifiers, } -impl From for KeyEvent { - fn from(event: winit::event::KeyEvent) -> Self { +impl KeyEvent { + /// Returns a new key event from a winit key event and modifiers. + #[must_use] + pub fn from_winit(event: winit::event::KeyEvent, modifiers: Modifiers) -> Self { Self { physical_key: event.physical_key, logical_key: event.logical_key, @@ -4708,6 +4731,7 @@ impl From for KeyEvent { location: event.location, state: event.state, repeat: event.repeat, + modifiers, } } }