From 20e81695ca29dc742e610e0c12edc96655f4024d Mon Sep 17 00:00:00 2001 From: Osspial Date: Sat, 28 Dec 2019 15:36:06 -0500 Subject: [PATCH] Change ModifiersState to a bitflags struct (#1306) * Change ModifiersState to a bitflags struct * Make examples work * Add modifier state methods * all things considered, only erroring out in one file throughout all of these changes is kinda impressive * Make expansion plans more clear * Move changelog entry * Try to fix macos build * Revert modifiers println in cursor_grab * Make serde serialization less bug-prone --- CHANGELOG.md | 1 + Cargo.toml | 4 +- examples/cursor_grab.rs | 4 +- examples/multithreaded.rs | 4 +- src/event.rs | 112 +++++++++++++++--- src/lib.rs | 1 - src/platform_impl/linux/wayland/keyboard.rs | 12 +- src/platform_impl/linux/x11/util/input.rs | 12 +- src/platform_impl/linux/x11/util/modifiers.rs | 24 ++-- src/platform_impl/macos/app_state.rs | 2 +- src/platform_impl/macos/event.rs | 24 +++- src/platform_impl/macos/view.rs | 16 +-- src/platform_impl/web/stdweb/event.rs | 24 ++-- src/platform_impl/web/web_sys/event.rs | 24 ++-- src/platform_impl/windows/event.rs | 19 ++- 15 files changed, 190 insertions(+), 93 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0c3c1bc..957a2e47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ - `RedrawRequested` is now issued only after `MainEventsCleared`. - `RedrawEventsCleared` is issued after each set of `RedrawRequested` events. - Implement synthetic window focus key events on Windows. +- **Breaking**: Change `ModifiersState` to a `bitflags` struct. # 0.20.0 Alpha 5 (2019-12-09) diff --git a/Cargo.toml b/Cargo.toml index 4887f364..3f918409 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ libc = "0.2.64" log = "0.4" serde = { version = "1", optional = true, features = ["serde_derive"] } raw-window-handle = "0.3" +bitflags = "1" [dev-dependencies] image = "0.21" @@ -48,9 +49,6 @@ version = "0.1.3" default_features = false features = ["display_link"] -[target.'cfg(any(target_os = "ios", target_os = "windows"))'.dependencies] -bitflags = "1" - [target.'cfg(target_os = "windows")'.dependencies.winapi] version = "0.3.6" features = [ diff --git a/examples/cursor_grab.rs b/examples/cursor_grab.rs index 726aba56..ac3a0f27 100644 --- a/examples/cursor_grab.rs +++ b/examples/cursor_grab.rs @@ -30,8 +30,8 @@ fn main() { use winit::event::VirtualKeyCode::*; match key { Escape => *control_flow = ControlFlow::Exit, - G => window.set_cursor_grab(!modifiers.shift).unwrap(), - H => window.set_cursor_visible(modifiers.shift), + G => window.set_cursor_grab(!modifiers.shift()).unwrap(), + H => window.set_cursor_visible(modifiers.shift()), _ => (), } } diff --git a/examples/multithreaded.rs b/examples/multithreaded.rs index 8ce36077..edfe72cf 100644 --- a/examples/multithreaded.rs +++ b/examples/multithreaded.rs @@ -60,7 +60,7 @@ fn main() { .. } => { window.set_title(&format!("{:?}", key)); - let state = !modifiers.shift; + let state = !modifiers.shift(); use VirtualKeyCode::*; match key { A => window.set_always_on_top(state), @@ -81,7 +81,7 @@ fn main() { video_modes.iter().nth(video_mode_id).unwrap() ); } - F => window.set_fullscreen(match (state, modifiers.alt) { + F => window.set_fullscreen(match (state, modifiers.alt()) { (true, false) => { Some(Fullscreen::Borderless(window.current_monitor())) } diff --git a/src/event.rs b/src/event.rs index a9be124a..b66ca992 100644 --- a/src/event.rs +++ b/src/event.rs @@ -675,21 +675,99 @@ pub enum VirtualKeyCode { Cut, } -/// Represents the current state of the keyboard modifiers -/// -/// Each field of this struct represents a modifier and is `true` if this modifier is active. -#[derive(Default, Debug, Hash, PartialEq, Eq, Clone, Copy)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "serde", serde(default))] -pub struct ModifiersState { - /// The "shift" key - pub shift: bool, - /// The "control" key - pub ctrl: bool, - /// The "alt" key - pub alt: bool, - /// The "logo" key - /// - /// This is the "windows" key on PC and "command" key on Mac. - pub logo: bool, +impl ModifiersState { + /// Returns `true` if the shift key is pressed. + pub fn shift(&self) -> bool { + self.intersects(Self::SHIFT) + } + /// Returns `true` if the control key is pressed. + pub fn ctrl(&self) -> bool { + self.intersects(Self::CTRL) + } + /// Returns `true` if the alt key is pressed. + pub fn alt(&self) -> bool { + self.intersects(Self::ALT) + } + /// Returns `true` if the logo key is pressed. + pub fn logo(&self) -> bool { + self.intersects(Self::LOGO) + } +} + +bitflags! { + /// Represents the current state of the keyboard modifiers + /// + /// Each flag represents a modifier and is set if this modifier is active. + #[derive(Default)] + pub struct ModifiersState: u32 { + // left and right modifiers are currently commented out, but we should be able to support + // them in a future release + /// The "shift" key. + const SHIFT = 0b100 << 0; + // const LSHIFT = 0b010 << 0; + // const RSHIFT = 0b001 << 0; + /// The "control" key. + const CTRL = 0b100 << 3; + // const LCTRL = 0b010 << 3; + // const RCTRL = 0b001 << 3; + /// The "alt" key. + const ALT = 0b100 << 6; + // const LALT = 0b010 << 6; + // const RALT = 0b001 << 6; + /// This is the "windows" key on PC and "command" key on Mac. + const LOGO = 0b100 << 9; + // const LLOGO = 0b010 << 9; + // const RLOGO = 0b001 << 9; + } +} + +#[cfg(feature = "serde")] +mod modifiers_serde { + use super::ModifiersState; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + #[derive(Default, Serialize, Deserialize)] + #[serde(default)] + #[serde(rename = "ModifiersState")] + pub struct ModifiersStateSerialize { + pub shift: bool, + pub ctrl: bool, + pub alt: bool, + pub logo: bool, + } + + impl Serialize for ModifiersState { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let s = ModifiersStateSerialize { + shift: self.shift(), + ctrl: self.ctrl(), + alt: self.alt(), + logo: self.logo(), + }; + s.serialize(serializer) + } + } + + impl<'de> Deserialize<'de> for ModifiersState { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let ModifiersStateSerialize { + shift, + ctrl, + alt, + logo, + } = ModifiersStateSerialize::deserialize(deserializer)?; + let mut m = ModifiersState::empty(); + m.set(ModifiersState::SHIFT, shift); + m.set(ModifiersState::CTRL, ctrl); + m.set(ModifiersState::ALT, alt); + m.set(ModifiersState::LOGO, logo); + Ok(m) + } + } } diff --git a/src/lib.rs b/src/lib.rs index 9d0340ee..cd99b89f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -119,7 +119,6 @@ extern crate log; #[macro_use] extern crate serde; #[macro_use] -#[cfg(any(target_os = "ios", target_os = "windows"))] extern crate bitflags; #[cfg(any(target_os = "macos", target_os = "ios"))] #[macro_use] diff --git a/src/platform_impl/linux/wayland/keyboard.rs b/src/platform_impl/linux/wayland/keyboard.rs index ef026c3a..b361cb1b 100644 --- a/src/platform_impl/linux/wayland/keyboard.rs +++ b/src/platform_impl/linux/wayland/keyboard.rs @@ -404,12 +404,12 @@ fn keysym_to_vkey(keysym: u32) -> Option { impl ModifiersState { pub(crate) fn from_wayland(mods: keyboard::ModifiersState) -> ModifiersState { - ModifiersState { - shift: mods.shift, - ctrl: mods.ctrl, - alt: mods.alt, - logo: mods.logo, - } + let mut m = ModifiersState::empty(); + m.set(ModifiersState::SHIFT, mods.shift); + m.set(ModifiersState::CTRL, mods.ctrl); + m.set(ModifiersState::ALT, mods.alt); + m.set(ModifiersState::LOGO, mods.logo); + m } } diff --git a/src/platform_impl/linux/x11/util/input.rs b/src/platform_impl/linux/x11/util/input.rs index 2fbabe1e..5af033d3 100644 --- a/src/platform_impl/linux/x11/util/input.rs +++ b/src/platform_impl/linux/x11/util/input.rs @@ -17,12 +17,12 @@ impl ModifiersState { } pub(crate) fn from_x11_mask(mask: c_uint) -> Self { - ModifiersState { - alt: mask & ffi::Mod1Mask != 0, - shift: mask & ffi::ShiftMask != 0, - ctrl: mask & ffi::ControlMask != 0, - logo: mask & ffi::Mod4Mask != 0, - } + let mut m = ModifiersState::empty(); + m.set(ModifiersState::SHIFT, mask & ffi::Mod1Mask != 0); + m.set(ModifiersState::CTRL, mask & ffi::ShiftMask != 0); + m.set(ModifiersState::ALT, mask & ffi::ControlMask != 0); + m.set(ModifiersState::LOGO, mask & ffi::Mod4Mask != 0); + m } } diff --git a/src/platform_impl/linux/x11/util/modifiers.rs b/src/platform_impl/linux/x11/util/modifiers.rs index 9bdc6e99..7c951997 100644 --- a/src/platform_impl/linux/x11/util/modifiers.rs +++ b/src/platform_impl/linux/x11/util/modifiers.rs @@ -116,10 +116,10 @@ impl ModifierKeyState { let mut new_state = *state; match except { - Some(Modifier::Alt) => new_state.alt = self.state.alt, - Some(Modifier::Ctrl) => new_state.ctrl = self.state.ctrl, - Some(Modifier::Shift) => new_state.shift = self.state.shift, - Some(Modifier::Logo) => new_state.logo = self.state.logo, + Some(Modifier::Alt) => new_state.set(ModifiersState::ALT, self.state.alt()), + Some(Modifier::Ctrl) => new_state.set(ModifiersState::CTRL, self.state.ctrl()), + Some(Modifier::Shift) => new_state.set(ModifiersState::SHIFT, self.state.shift()), + Some(Modifier::Logo) => new_state.set(ModifiersState::LOGO, self.state.logo()), None => (), } @@ -170,18 +170,18 @@ impl ModifierKeyState { fn get_modifier(state: &ModifiersState, modifier: Modifier) -> bool { match modifier { - Modifier::Alt => state.alt, - Modifier::Ctrl => state.ctrl, - Modifier::Shift => state.shift, - Modifier::Logo => state.logo, + Modifier::Alt => state.alt(), + Modifier::Ctrl => state.ctrl(), + Modifier::Shift => state.shift(), + Modifier::Logo => state.logo(), } } fn set_modifier(state: &mut ModifiersState, modifier: Modifier, value: bool) { match modifier { - Modifier::Alt => state.alt = value, - Modifier::Ctrl => state.ctrl = value, - Modifier::Shift => state.shift = value, - Modifier::Logo => state.logo = value, + Modifier::Alt => state.set(ModifiersState::ALT, value), + Modifier::Ctrl => state.set(ModifiersState::CTRL, value), + Modifier::Shift => state.set(ModifiersState::SHIFT, value), + Modifier::Logo => state.set(ModifiersState::LOGO, value), } } diff --git a/src/platform_impl/macos/app_state.rs b/src/platform_impl/macos/app_state.rs index be3aeb12..67de6ce6 100644 --- a/src/platform_impl/macos/app_state.rs +++ b/src/platform_impl/macos/app_state.rs @@ -14,7 +14,7 @@ use std::{ use cocoa::{appkit::NSApp, base::nil, foundation::NSString}; use crate::{ - event::{Event, StartCause, WindowEvent}, + event::{Event, StartCause}, event_loop::{ControlFlow, EventLoopWindowTarget as RootWindowTarget}, platform_impl::platform::{observer::EventLoopWaker, util::Never}, window::WindowId, diff --git a/src/platform_impl/macos/event.rs b/src/platform_impl/macos/event.rs index 508347e6..4f8123d4 100644 --- a/src/platform_impl/macos/event.rs +++ b/src/platform_impl/macos/event.rs @@ -224,12 +224,24 @@ pub fn check_function_keys(string: &str) -> Option { pub fn event_mods(event: id) -> ModifiersState { let flags = unsafe { NSEvent::modifierFlags(event) }; - ModifiersState { - shift: flags.contains(NSEventModifierFlags::NSShiftKeyMask), - ctrl: flags.contains(NSEventModifierFlags::NSControlKeyMask), - alt: flags.contains(NSEventModifierFlags::NSAlternateKeyMask), - logo: flags.contains(NSEventModifierFlags::NSCommandKeyMask), - } + let mut m = ModifiersState::empty(); + m.set( + ModifiersState::SHIFT, + flags.contains(NSEventModifierFlags::NSShiftKeyMask), + ); + m.set( + ModifiersState::CTRL, + flags.contains(NSEventModifierFlags::NSControlKeyMask), + ); + m.set( + ModifiersState::ALT, + flags.contains(NSEventModifierFlags::NSAlternateKeyMask), + ); + m.set( + ModifiersState::LOGO, + flags.contains(NSEventModifierFlags::NSCommandKeyMask), + ); + m } pub fn get_scancode(event: cocoa::base::id) -> c_ushort { diff --git a/src/platform_impl/macos/view.rs b/src/platform_impl/macos/view.rs index 2b69bfbe..eb373d98 100644 --- a/src/platform_impl/macos/view.rs +++ b/src/platform_impl/macos/view.rs @@ -646,36 +646,36 @@ extern "C" fn flags_changed(this: &Object, _sel: Sel, event: id) { if let Some(window_event) = modifier_event( event, NSEventModifierFlags::NSShiftKeyMask, - state.modifiers.shift, + state.modifiers.shift(), ) { - state.modifiers.shift = !state.modifiers.shift; + state.modifiers.toggle(ModifiersState::SHIFT); events.push_back(window_event); } if let Some(window_event) = modifier_event( event, NSEventModifierFlags::NSControlKeyMask, - state.modifiers.ctrl, + state.modifiers.ctrl(), ) { - state.modifiers.ctrl = !state.modifiers.ctrl; + state.modifiers.toggle(ModifiersState::CTRL); events.push_back(window_event); } if let Some(window_event) = modifier_event( event, NSEventModifierFlags::NSCommandKeyMask, - state.modifiers.logo, + state.modifiers.logo(), ) { - state.modifiers.logo = !state.modifiers.logo; + state.modifiers.toggle(ModifiersState::LOGO); events.push_back(window_event); } if let Some(window_event) = modifier_event( event, NSEventModifierFlags::NSAlternateKeyMask, - state.modifiers.alt, + state.modifiers.alt(), ) { - state.modifiers.alt = !state.modifiers.alt; + state.modifiers.toggle(ModifiersState::ALT); events.push_back(window_event); } diff --git a/src/platform_impl/web/stdweb/event.rs b/src/platform_impl/web/stdweb/event.rs index 14456dc0..223ef693 100644 --- a/src/platform_impl/web/stdweb/event.rs +++ b/src/platform_impl/web/stdweb/event.rs @@ -15,12 +15,12 @@ pub fn mouse_button(event: &impl IMouseEvent) -> MouseButton { } pub fn mouse_modifiers(event: &impl IMouseEvent) -> ModifiersState { - ModifiersState { - shift: event.shift_key(), - ctrl: event.ctrl_key(), - alt: event.alt_key(), - logo: event.meta_key(), - } + let mut m = ModifiersState::empty(); + m.set(ModifiersState::SHIFT, event.shift_key()); + m.set(ModifiersState::CTRL, event.ctrl_key()); + m.set(ModifiersState::ALT, event.alt_key()); + m.set(ModifiersState::LOGO, event.meta_key()); + m } pub fn mouse_position(event: &impl IMouseEvent) -> LogicalPosition { @@ -213,12 +213,12 @@ pub fn virtual_key_code(event: &impl IKeyboardEvent) -> Option { } pub fn keyboard_modifiers(event: &impl IKeyboardEvent) -> ModifiersState { - ModifiersState { - shift: event.shift_key(), - ctrl: event.ctrl_key(), - alt: event.alt_key(), - logo: event.meta_key(), - } + let mut m = ModifiersState::empty(); + m.set(ModifiersState::SHIFT, event.shift_key()); + m.set(ModifiersState::CTRL, event.ctrl_key()); + m.set(ModifiersState::ALT, event.alt_key()); + m.set(ModifiersState::LOGO, event.meta_key()); + m } pub fn codepoint(event: &impl IKeyboardEvent) -> char { diff --git a/src/platform_impl/web/web_sys/event.rs b/src/platform_impl/web/web_sys/event.rs index af557b99..9a11f3bf 100644 --- a/src/platform_impl/web/web_sys/event.rs +++ b/src/platform_impl/web/web_sys/event.rs @@ -14,12 +14,12 @@ pub fn mouse_button(event: &MouseEvent) -> MouseButton { } pub fn mouse_modifiers(event: &MouseEvent) -> ModifiersState { - ModifiersState { - shift: event.shift_key(), - ctrl: event.ctrl_key(), - alt: event.alt_key(), - logo: event.meta_key(), - } + let mut m = ModifiersState::empty(); + m.set(ModifiersState::SHIFT, event.shift_key()); + m.set(ModifiersState::CTRL, event.ctrl_key()); + m.set(ModifiersState::ALT, event.alt_key()); + m.set(ModifiersState::LOGO, event.meta_key()); + m } pub fn mouse_position(event: &MouseEvent) -> LogicalPosition { @@ -211,12 +211,12 @@ pub fn virtual_key_code(event: &KeyboardEvent) -> Option { } pub fn keyboard_modifiers(event: &KeyboardEvent) -> ModifiersState { - ModifiersState { - shift: event.shift_key(), - ctrl: event.ctrl_key(), - alt: event.alt_key(), - logo: event.meta_key(), - } + let mut m = ModifiersState::empty(); + m.set(ModifiersState::SHIFT, event.shift_key()); + m.set(ModifiersState::CTRL, event.ctrl_key()); + m.set(ModifiersState::ALT, event.alt_key()); + m.set(ModifiersState::LOGO, event.meta_key()); + m } pub fn codepoint(event: &KeyboardEvent) -> char { diff --git a/src/platform_impl/windows/event.rs b/src/platform_impl/windows/event.rs index 60f6a925..04ef7692 100644 --- a/src/platform_impl/windows/event.rs +++ b/src/platform_impl/windows/event.rs @@ -17,13 +17,22 @@ fn key_pressed(vkey: c_int) -> bool { } pub fn get_key_mods() -> ModifiersState { - let mut mods = ModifiersState::default(); let filter_out_altgr = layout_uses_altgr() && key_pressed(winuser::VK_RMENU); - mods.shift = key_pressed(winuser::VK_SHIFT); - mods.ctrl = key_pressed(winuser::VK_CONTROL) && !filter_out_altgr; - mods.alt = key_pressed(winuser::VK_MENU) && !filter_out_altgr; - mods.logo = key_pressed(winuser::VK_LWIN) || key_pressed(winuser::VK_RWIN); + let mut mods = ModifiersState::empty(); + mods.set(ModifiersState::SHIFT, key_pressed(winuser::VK_SHIFT)); + mods.set( + ModifiersState::CTRL, + key_pressed(winuser::VK_CONTROL) && !filter_out_altgr, + ); + mods.set( + ModifiersState::ALT, + key_pressed(winuser::VK_MENU) && !filter_out_altgr, + ); + mods.set( + ModifiersState::LOGO, + key_pressed(winuser::VK_LWIN) || key_pressed(winuser::VK_RWIN), + ); mods }