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
This commit is contained in:
Osspial 2019-12-28 15:36:06 -05:00 committed by GitHub
parent 027c52171d
commit 20e81695ca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 190 additions and 93 deletions

View file

@ -15,6 +15,7 @@
- `RedrawRequested` is now issued only after `MainEventsCleared`. - `RedrawRequested` is now issued only after `MainEventsCleared`.
- `RedrawEventsCleared` is issued after each set of `RedrawRequested` events. - `RedrawEventsCleared` is issued after each set of `RedrawRequested` events.
- Implement synthetic window focus key events on Windows. - Implement synthetic window focus key events on Windows.
- **Breaking**: Change `ModifiersState` to a `bitflags` struct.
# 0.20.0 Alpha 5 (2019-12-09) # 0.20.0 Alpha 5 (2019-12-09)

View file

@ -25,6 +25,7 @@ libc = "0.2.64"
log = "0.4" log = "0.4"
serde = { version = "1", optional = true, features = ["serde_derive"] } serde = { version = "1", optional = true, features = ["serde_derive"] }
raw-window-handle = "0.3" raw-window-handle = "0.3"
bitflags = "1"
[dev-dependencies] [dev-dependencies]
image = "0.21" image = "0.21"
@ -48,9 +49,6 @@ version = "0.1.3"
default_features = false default_features = false
features = ["display_link"] features = ["display_link"]
[target.'cfg(any(target_os = "ios", target_os = "windows"))'.dependencies]
bitflags = "1"
[target.'cfg(target_os = "windows")'.dependencies.winapi] [target.'cfg(target_os = "windows")'.dependencies.winapi]
version = "0.3.6" version = "0.3.6"
features = [ features = [

View file

@ -30,8 +30,8 @@ fn main() {
use winit::event::VirtualKeyCode::*; use winit::event::VirtualKeyCode::*;
match key { match key {
Escape => *control_flow = ControlFlow::Exit, Escape => *control_flow = ControlFlow::Exit,
G => window.set_cursor_grab(!modifiers.shift).unwrap(), G => window.set_cursor_grab(!modifiers.shift()).unwrap(),
H => window.set_cursor_visible(modifiers.shift), H => window.set_cursor_visible(modifiers.shift()),
_ => (), _ => (),
} }
} }

View file

@ -60,7 +60,7 @@ fn main() {
.. ..
} => { } => {
window.set_title(&format!("{:?}", key)); window.set_title(&format!("{:?}", key));
let state = !modifiers.shift; let state = !modifiers.shift();
use VirtualKeyCode::*; use VirtualKeyCode::*;
match key { match key {
A => window.set_always_on_top(state), A => window.set_always_on_top(state),
@ -81,7 +81,7 @@ fn main() {
video_modes.iter().nth(video_mode_id).unwrap() 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) => { (true, false) => {
Some(Fullscreen::Borderless(window.current_monitor())) Some(Fullscreen::Borderless(window.current_monitor()))
} }

View file

@ -675,21 +675,99 @@ pub enum VirtualKeyCode {
Cut, Cut,
} }
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 /// Represents the current state of the keyboard modifiers
/// ///
/// Each field of this struct represents a modifier and is `true` if this modifier is active. /// Each flag represents a modifier and is set if this modifier is active.
#[derive(Default, Debug, Hash, PartialEq, Eq, Clone, Copy)] #[derive(Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ModifiersState: u32 {
#[cfg_attr(feature = "serde", serde(default))] // left and right modifiers are currently commented out, but we should be able to support
pub struct ModifiersState { // them in a future release
/// The "shift" key /// The "shift" key.
pub shift: bool, const SHIFT = 0b100 << 0;
/// The "control" key // const LSHIFT = 0b010 << 0;
pub ctrl: bool, // const RSHIFT = 0b001 << 0;
/// The "alt" key /// The "control" key.
pub alt: bool, const CTRL = 0b100 << 3;
/// The "logo" key // 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. /// 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, pub logo: bool,
} }
impl Serialize for ModifiersState {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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<D>(deserializer: D) -> Result<Self, D::Error>
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)
}
}
}

View file

@ -119,7 +119,6 @@ extern crate log;
#[macro_use] #[macro_use]
extern crate serde; extern crate serde;
#[macro_use] #[macro_use]
#[cfg(any(target_os = "ios", target_os = "windows"))]
extern crate bitflags; extern crate bitflags;
#[cfg(any(target_os = "macos", target_os = "ios"))] #[cfg(any(target_os = "macos", target_os = "ios"))]
#[macro_use] #[macro_use]

View file

@ -404,12 +404,12 @@ fn keysym_to_vkey(keysym: u32) -> Option<VirtualKeyCode> {
impl ModifiersState { impl ModifiersState {
pub(crate) fn from_wayland(mods: keyboard::ModifiersState) -> ModifiersState { pub(crate) fn from_wayland(mods: keyboard::ModifiersState) -> ModifiersState {
ModifiersState { let mut m = ModifiersState::empty();
shift: mods.shift, m.set(ModifiersState::SHIFT, mods.shift);
ctrl: mods.ctrl, m.set(ModifiersState::CTRL, mods.ctrl);
alt: mods.alt, m.set(ModifiersState::ALT, mods.alt);
logo: mods.logo, m.set(ModifiersState::LOGO, mods.logo);
} m
} }
} }

View file

@ -17,12 +17,12 @@ impl ModifiersState {
} }
pub(crate) fn from_x11_mask(mask: c_uint) -> Self { pub(crate) fn from_x11_mask(mask: c_uint) -> Self {
ModifiersState { let mut m = ModifiersState::empty();
alt: mask & ffi::Mod1Mask != 0, m.set(ModifiersState::SHIFT, mask & ffi::Mod1Mask != 0);
shift: mask & ffi::ShiftMask != 0, m.set(ModifiersState::CTRL, mask & ffi::ShiftMask != 0);
ctrl: mask & ffi::ControlMask != 0, m.set(ModifiersState::ALT, mask & ffi::ControlMask != 0);
logo: mask & ffi::Mod4Mask != 0, m.set(ModifiersState::LOGO, mask & ffi::Mod4Mask != 0);
} m
} }
} }

View file

@ -116,10 +116,10 @@ impl ModifierKeyState {
let mut new_state = *state; let mut new_state = *state;
match except { match except {
Some(Modifier::Alt) => new_state.alt = self.state.alt, Some(Modifier::Alt) => new_state.set(ModifiersState::ALT, self.state.alt()),
Some(Modifier::Ctrl) => new_state.ctrl = self.state.ctrl, Some(Modifier::Ctrl) => new_state.set(ModifiersState::CTRL, self.state.ctrl()),
Some(Modifier::Shift) => new_state.shift = self.state.shift, Some(Modifier::Shift) => new_state.set(ModifiersState::SHIFT, self.state.shift()),
Some(Modifier::Logo) => new_state.logo = self.state.logo, Some(Modifier::Logo) => new_state.set(ModifiersState::LOGO, self.state.logo()),
None => (), None => (),
} }
@ -170,18 +170,18 @@ impl ModifierKeyState {
fn get_modifier(state: &ModifiersState, modifier: Modifier) -> bool { fn get_modifier(state: &ModifiersState, modifier: Modifier) -> bool {
match modifier { match modifier {
Modifier::Alt => state.alt, Modifier::Alt => state.alt(),
Modifier::Ctrl => state.ctrl, Modifier::Ctrl => state.ctrl(),
Modifier::Shift => state.shift, Modifier::Shift => state.shift(),
Modifier::Logo => state.logo, Modifier::Logo => state.logo(),
} }
} }
fn set_modifier(state: &mut ModifiersState, modifier: Modifier, value: bool) { fn set_modifier(state: &mut ModifiersState, modifier: Modifier, value: bool) {
match modifier { match modifier {
Modifier::Alt => state.alt = value, Modifier::Alt => state.set(ModifiersState::ALT, value),
Modifier::Ctrl => state.ctrl = value, Modifier::Ctrl => state.set(ModifiersState::CTRL, value),
Modifier::Shift => state.shift = value, Modifier::Shift => state.set(ModifiersState::SHIFT, value),
Modifier::Logo => state.logo = value, Modifier::Logo => state.set(ModifiersState::LOGO, value),
} }
} }

View file

@ -14,7 +14,7 @@ use std::{
use cocoa::{appkit::NSApp, base::nil, foundation::NSString}; use cocoa::{appkit::NSApp, base::nil, foundation::NSString};
use crate::{ use crate::{
event::{Event, StartCause, WindowEvent}, event::{Event, StartCause},
event_loop::{ControlFlow, EventLoopWindowTarget as RootWindowTarget}, event_loop::{ControlFlow, EventLoopWindowTarget as RootWindowTarget},
platform_impl::platform::{observer::EventLoopWaker, util::Never}, platform_impl::platform::{observer::EventLoopWaker, util::Never},
window::WindowId, window::WindowId,

View file

@ -224,12 +224,24 @@ pub fn check_function_keys(string: &str) -> Option<VirtualKeyCode> {
pub fn event_mods(event: id) -> ModifiersState { pub fn event_mods(event: id) -> ModifiersState {
let flags = unsafe { NSEvent::modifierFlags(event) }; let flags = unsafe { NSEvent::modifierFlags(event) };
ModifiersState { let mut m = ModifiersState::empty();
shift: flags.contains(NSEventModifierFlags::NSShiftKeyMask), m.set(
ctrl: flags.contains(NSEventModifierFlags::NSControlKeyMask), ModifiersState::SHIFT,
alt: flags.contains(NSEventModifierFlags::NSAlternateKeyMask), flags.contains(NSEventModifierFlags::NSShiftKeyMask),
logo: flags.contains(NSEventModifierFlags::NSCommandKeyMask), );
} 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 { pub fn get_scancode(event: cocoa::base::id) -> c_ushort {

View file

@ -646,36 +646,36 @@ extern "C" fn flags_changed(this: &Object, _sel: Sel, event: id) {
if let Some(window_event) = modifier_event( if let Some(window_event) = modifier_event(
event, event,
NSEventModifierFlags::NSShiftKeyMask, NSEventModifierFlags::NSShiftKeyMask,
state.modifiers.shift, state.modifiers.shift(),
) { ) {
state.modifiers.shift = !state.modifiers.shift; state.modifiers.toggle(ModifiersState::SHIFT);
events.push_back(window_event); events.push_back(window_event);
} }
if let Some(window_event) = modifier_event( if let Some(window_event) = modifier_event(
event, event,
NSEventModifierFlags::NSControlKeyMask, NSEventModifierFlags::NSControlKeyMask,
state.modifiers.ctrl, state.modifiers.ctrl(),
) { ) {
state.modifiers.ctrl = !state.modifiers.ctrl; state.modifiers.toggle(ModifiersState::CTRL);
events.push_back(window_event); events.push_back(window_event);
} }
if let Some(window_event) = modifier_event( if let Some(window_event) = modifier_event(
event, event,
NSEventModifierFlags::NSCommandKeyMask, NSEventModifierFlags::NSCommandKeyMask,
state.modifiers.logo, state.modifiers.logo(),
) { ) {
state.modifiers.logo = !state.modifiers.logo; state.modifiers.toggle(ModifiersState::LOGO);
events.push_back(window_event); events.push_back(window_event);
} }
if let Some(window_event) = modifier_event( if let Some(window_event) = modifier_event(
event, event,
NSEventModifierFlags::NSAlternateKeyMask, NSEventModifierFlags::NSAlternateKeyMask,
state.modifiers.alt, state.modifiers.alt(),
) { ) {
state.modifiers.alt = !state.modifiers.alt; state.modifiers.toggle(ModifiersState::ALT);
events.push_back(window_event); events.push_back(window_event);
} }

View file

@ -15,12 +15,12 @@ pub fn mouse_button(event: &impl IMouseEvent) -> MouseButton {
} }
pub fn mouse_modifiers(event: &impl IMouseEvent) -> ModifiersState { pub fn mouse_modifiers(event: &impl IMouseEvent) -> ModifiersState {
ModifiersState { let mut m = ModifiersState::empty();
shift: event.shift_key(), m.set(ModifiersState::SHIFT, event.shift_key());
ctrl: event.ctrl_key(), m.set(ModifiersState::CTRL, event.ctrl_key());
alt: event.alt_key(), m.set(ModifiersState::ALT, event.alt_key());
logo: event.meta_key(), m.set(ModifiersState::LOGO, event.meta_key());
} m
} }
pub fn mouse_position(event: &impl IMouseEvent) -> LogicalPosition { pub fn mouse_position(event: &impl IMouseEvent) -> LogicalPosition {
@ -213,12 +213,12 @@ pub fn virtual_key_code(event: &impl IKeyboardEvent) -> Option<VirtualKeyCode> {
} }
pub fn keyboard_modifiers(event: &impl IKeyboardEvent) -> ModifiersState { pub fn keyboard_modifiers(event: &impl IKeyboardEvent) -> ModifiersState {
ModifiersState { let mut m = ModifiersState::empty();
shift: event.shift_key(), m.set(ModifiersState::SHIFT, event.shift_key());
ctrl: event.ctrl_key(), m.set(ModifiersState::CTRL, event.ctrl_key());
alt: event.alt_key(), m.set(ModifiersState::ALT, event.alt_key());
logo: event.meta_key(), m.set(ModifiersState::LOGO, event.meta_key());
} m
} }
pub fn codepoint(event: &impl IKeyboardEvent) -> char { pub fn codepoint(event: &impl IKeyboardEvent) -> char {

View file

@ -14,12 +14,12 @@ pub fn mouse_button(event: &MouseEvent) -> MouseButton {
} }
pub fn mouse_modifiers(event: &MouseEvent) -> ModifiersState { pub fn mouse_modifiers(event: &MouseEvent) -> ModifiersState {
ModifiersState { let mut m = ModifiersState::empty();
shift: event.shift_key(), m.set(ModifiersState::SHIFT, event.shift_key());
ctrl: event.ctrl_key(), m.set(ModifiersState::CTRL, event.ctrl_key());
alt: event.alt_key(), m.set(ModifiersState::ALT, event.alt_key());
logo: event.meta_key(), m.set(ModifiersState::LOGO, event.meta_key());
} m
} }
pub fn mouse_position(event: &MouseEvent) -> LogicalPosition { pub fn mouse_position(event: &MouseEvent) -> LogicalPosition {
@ -211,12 +211,12 @@ pub fn virtual_key_code(event: &KeyboardEvent) -> Option<VirtualKeyCode> {
} }
pub fn keyboard_modifiers(event: &KeyboardEvent) -> ModifiersState { pub fn keyboard_modifiers(event: &KeyboardEvent) -> ModifiersState {
ModifiersState { let mut m = ModifiersState::empty();
shift: event.shift_key(), m.set(ModifiersState::SHIFT, event.shift_key());
ctrl: event.ctrl_key(), m.set(ModifiersState::CTRL, event.ctrl_key());
alt: event.alt_key(), m.set(ModifiersState::ALT, event.alt_key());
logo: event.meta_key(), m.set(ModifiersState::LOGO, event.meta_key());
} m
} }
pub fn codepoint(event: &KeyboardEvent) -> char { pub fn codepoint(event: &KeyboardEvent) -> char {

View file

@ -17,13 +17,22 @@ fn key_pressed(vkey: c_int) -> bool {
} }
pub fn get_key_mods() -> ModifiersState { pub fn get_key_mods() -> ModifiersState {
let mut mods = ModifiersState::default();
let filter_out_altgr = layout_uses_altgr() && key_pressed(winuser::VK_RMENU); let filter_out_altgr = layout_uses_altgr() && key_pressed(winuser::VK_RMENU);
mods.shift = key_pressed(winuser::VK_SHIFT); let mut mods = ModifiersState::empty();
mods.ctrl = key_pressed(winuser::VK_CONTROL) && !filter_out_altgr; mods.set(ModifiersState::SHIFT, key_pressed(winuser::VK_SHIFT));
mods.alt = key_pressed(winuser::VK_MENU) && !filter_out_altgr; mods.set(
mods.logo = key_pressed(winuser::VK_LWIN) || key_pressed(winuser::VK_RWIN); 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 mods
} }