From f3ccdb7aec1d3c9e386a0ecd8c349149f48791c9 Mon Sep 17 00:00:00 2001 From: Erik Rigtorp Date: Tue, 17 Jan 2017 12:01:10 -0600 Subject: [PATCH] Add keyboard modifiers to input event Making applications track modifier keys results in unnecessary work for consumers, it's error prone, and it turns out to have unavoidable bugs. For example, alt-tabbing with x11 results in the alt modifier state getting stuck. To resolve these problems, this patch adds a Mods value to the keyboard input event. Based on this patch: https://github.com/jwilm/glutin/commit/d287fa96e3a8b2568b189067eedd28807c4568d6 --- examples/cursor.rs | 2 +- examples/fullscreen.rs | 2 +- examples/grabbing.rs | 2 +- src/api/wayland/context.rs | 6 +++++- src/api/wayland/keyboard.rs | 5 ++++- src/api/x11/input.rs | 3 ++- src/events.rs | 19 ++++++++++++++++++- src/platform/macos/events_loop.rs | 10 +++++----- src/platform/windows/callback.rs | 5 +++-- 9 files changed, 40 insertions(+), 14 deletions(-) diff --git a/examples/cursor.rs b/examples/cursor.rs index bba013a92..0f65e10ab 100644 --- a/examples/cursor.rs +++ b/examples/cursor.rs @@ -13,7 +13,7 @@ fn main() { events_loop.run_forever(|event| { match event { - Event::WindowEvent { event: WindowEvent::KeyboardInput(ElementState::Pressed, _, _), .. } => { + Event::WindowEvent { event: WindowEvent::KeyboardInput(ElementState::Pressed, _, _, _), .. } => { println!("Setting cursor to \"{:?}\"", cursors[cursor_idx]); window.set_cursor(cursors[cursor_idx]); if cursor_idx < cursors.len() - 1 { diff --git a/examples/fullscreen.rs b/examples/fullscreen.rs index bfb179e07..308d9dcf3 100644 --- a/examples/fullscreen.rs +++ b/examples/fullscreen.rs @@ -37,7 +37,7 @@ fn main() { winit::Event::WindowEvent { event, .. } => { match event { winit::WindowEvent::Closed => events_loop.interrupt(), - winit::WindowEvent::KeyboardInput(_, _, Some(winit::VirtualKeyCode::Escape)) => events_loop.interrupt(), + winit::WindowEvent::KeyboardInput(_, _, Some(winit::VirtualKeyCode::Escape), _) => events_loop.interrupt(), _ => () } }, diff --git a/examples/grabbing.rs b/examples/grabbing.rs index ff3afb2a8..d156da43d 100644 --- a/examples/grabbing.rs +++ b/examples/grabbing.rs @@ -16,7 +16,7 @@ fn main() { match event { winit::Event::WindowEvent { event, .. } => { match event { - WindowEvent::KeyboardInput(ElementState::Pressed, _, _) => { + WindowEvent::KeyboardInput(ElementState::Pressed, _, _, _) => { if grabbed { grabbed = false; window.set_cursor_state(winit::CursorState::Normal) diff --git a/src/api/wayland/context.rs b/src/api/wayland/context.rs index debd5e6b4..de9d21bf1 100644 --- a/src/api/wayland/context.rs +++ b/src/api/wayland/context.rs @@ -1,5 +1,7 @@ use {WindowEvent as Event, ElementState, MouseButton, MouseScrollDelta, TouchPhase}; +use events::ModifiersState; + use std::collections::VecDeque; use std::sync::{Arc, Mutex}; @@ -627,10 +629,12 @@ impl wl_keyboard::Handler for WaylandEnv { wl_keyboard::KeyState::Released => ElementState::Released, }; let mut guard = eviter.lock().unwrap(); + // TODO implement ModifiersState guard.push_back(Event::KeyboardInput( state, key as u8, - None + None, + ModifiersState::default() )); }, KbdType::Plain(None) => () diff --git a/src/api/wayland/keyboard.rs b/src/api/wayland/keyboard.rs index 891865794..8b571a1a1 100644 --- a/src/api/wayland/keyboard.rs +++ b/src/api/wayland/keyboard.rs @@ -3,6 +3,8 @@ use std::sync::{Arc, Mutex}; use {VirtualKeyCode, ElementState, WindowEvent as Event}; +use events::ModifiersState; + use super::wayland_kbd; use wayland_client::EventQueueHandle; use wayland_client::protocol::wl_keyboard; @@ -35,7 +37,8 @@ impl wayland_kbd::Handler for KbdHandler { }; let vkcode = key_to_vkey(rawkey, keysym); let mut guard = eviter.lock().unwrap(); - guard.push_back(Event::KeyboardInput(state, rawkey as u8, vkcode)); + // TODO implement ModifiersState + guard.push_back(Event::KeyboardInput(state, rawkey as u8, vkcode, ModifiersState::default())); // send char event only on key press, not release if let ElementState::Released = state { return } if let Some(txt) = utf8 { diff --git a/src/api/x11/input.rs b/src/api/x11/input.rs index 7185a4493..91f139f36 100644 --- a/src/api/x11/input.rs +++ b/src/api/x11/input.rs @@ -8,6 +8,7 @@ use std::slice::from_raw_parts; use WindowAttributes; use events::WindowEvent as Event; +use events::ModifiersState; use super::{events, ffi}; use super::XConnection; @@ -165,7 +166,7 @@ impl XInputEventHandler { let vkey = events::keycode_to_element(keysym as libc::c_uint); - translated_events.push(KeyboardInput(state, event.keycode as u8, vkey)); + translated_events.push(KeyboardInput(state, event.keycode as u8, vkey, ModifiersState::default())); translated_events } diff --git a/src/events.rs b/src/events.rs index 7288ea9e0..851ef0c6f 100644 --- a/src/events.rs +++ b/src/events.rs @@ -35,7 +35,7 @@ pub enum WindowEvent { Focused(bool), /// An event from the keyboard has been received. - KeyboardInput(ElementState, ScanCode, Option), + KeyboardInput(ElementState, ScanCode, Option, ModifiersState), /// The cursor has moved on the window. /// @@ -320,3 +320,20 @@ pub enum VirtualKeyCode { WebStop, Yen, } + +/// 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, Clone, Copy)] +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 +} diff --git a/src/platform/macos/events_loop.rs b/src/platform/macos/events_loop.rs index 458c69b57..60ece70f4 100644 --- a/src/platform/macos/events_loop.rs +++ b/src/platform/macos/events_loop.rs @@ -1,6 +1,6 @@ use cocoa::{self, appkit, foundation}; use cocoa::appkit::{NSApplication, NSEvent, NSView, NSWindow}; -use events::{self, ElementState, Event, MouseButton, TouchPhase, WindowEvent}; +use events::{self, ElementState, Event, MouseButton, TouchPhase, WindowEvent, Modifiers}; use super::window::Window; use std; @@ -271,7 +271,7 @@ impl EventsLoop { let vkey = to_virtual_key_code(NSEvent::keyCode(ns_event)); let state = ElementState::Pressed; let code = NSEvent::keyCode(ns_event) as u8; - let window_event = WindowEvent::KeyboardInput(state, code, vkey); + let window_event = WindowEvent::KeyboardInput(state, code, vkey, ModifiersState::default()); events.push_back(into_event(window_event)); let event = events.pop_front(); self.pending_events.lock().unwrap().extend(events.into_iter()); @@ -283,7 +283,7 @@ impl EventsLoop { let state = ElementState::Released; let code = NSEvent::keyCode(ns_event) as u8; - let window_event = WindowEvent::KeyboardInput(state, code, vkey); + let window_event = WindowEvent::KeyboardInput(state, code, vkey, ModifiersState::default()); Some(into_event(window_event)) }, @@ -298,13 +298,13 @@ impl EventsLoop { if !key_pressed && NSEvent::modifierFlags(event).contains(keymask) { let state = ElementState::Pressed; let code = NSEvent::keyCode(event) as u8; - let window_event = WindowEvent::KeyboardInput(state, code, Some(key)); + let window_event = WindowEvent::KeyboardInput(state, code, Some(key), ModifiersState::default()); Some(window_event) } else if key_pressed && !NSEvent::modifierFlags(event).contains(keymask) { let state = ElementState::Released; let code = NSEvent::keyCode(event) as u8; - let window_event = WindowEvent::KeyboardInput(state, code, Some(key)); + let window_event = WindowEvent::KeyboardInput(state, code, Some(key), ModifiersState::default()); Some(window_event) } else { diff --git a/src/platform/windows/callback.rs b/src/platform/windows/callback.rs index de6116404..53f548755 100644 --- a/src/platform/windows/callback.rs +++ b/src/platform/windows/callback.rs @@ -8,6 +8,7 @@ use std::os::windows::ffi::OsStringExt; use CursorState; use WindowEvent as Event; +use events::ModifersState; use super::event; use super::WindowState; @@ -200,7 +201,7 @@ pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT, user32::DefWindowProcW(window, msg, wparam, lparam) } else { let (scancode, vkey) = event::vkeycode_to_element(wparam, lparam); - send_event(window, KeyboardInput(Pressed, scancode, vkey)); + send_event(window, KeyboardInput(Pressed, scancode, vkey, ModifersState::default())); 0 } }, @@ -209,7 +210,7 @@ pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT, use events::WindowEvent::KeyboardInput; use events::ElementState::Released; let (scancode, vkey) = event::vkeycode_to_element(wparam, lparam); - send_event(window, KeyboardInput(Released, scancode, vkey)); + send_event(window, KeyboardInput(Released, scancode, vkey, ModifersState::default())); 0 },