Merge pull request #112 from rigtorp/keyboard-mods

Add keyboard modifiers to input event
This commit is contained in:
tomaka 2017-03-02 20:37:33 +01:00 committed by GitHub
commit 4c6e4e827a
10 changed files with 94 additions and 14 deletions

View file

@ -13,7 +13,7 @@ fn main() {
events_loop.run_forever(|event| { events_loop.run_forever(|event| {
match event { match event {
Event::WindowEvent { event: WindowEvent::KeyboardInput(ElementState::Pressed, _, _), .. } => { Event::WindowEvent { event: WindowEvent::KeyboardInput(ElementState::Pressed, _, _, _), .. } => {
println!("Setting cursor to \"{:?}\"", cursors[cursor_idx]); println!("Setting cursor to \"{:?}\"", cursors[cursor_idx]);
window.set_cursor(cursors[cursor_idx]); window.set_cursor(cursors[cursor_idx]);
if cursor_idx < cursors.len() - 1 { if cursor_idx < cursors.len() - 1 {

View file

@ -37,7 +37,7 @@ fn main() {
winit::Event::WindowEvent { event, .. } => { winit::Event::WindowEvent { event, .. } => {
match event { match event {
winit::WindowEvent::Closed => events_loop.interrupt(), 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(),
_ => () _ => ()
} }
}, },

View file

@ -16,7 +16,7 @@ fn main() {
match event { match event {
winit::Event::WindowEvent { event, .. } => { winit::Event::WindowEvent { event, .. } => {
match event { match event {
WindowEvent::KeyboardInput(ElementState::Pressed, _, _) => { WindowEvent::KeyboardInput(ElementState::Pressed, _, _, _) => {
if grabbed { if grabbed {
grabbed = false; grabbed = false;
window.set_cursor_state(winit::CursorState::Normal) window.set_cursor_state(winit::CursorState::Normal)

View file

@ -1,5 +1,7 @@
use {WindowEvent as Event, ElementState, MouseButton, MouseScrollDelta, TouchPhase}; use {WindowEvent as Event, ElementState, MouseButton, MouseScrollDelta, TouchPhase};
use events::ModifiersState;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
@ -627,10 +629,12 @@ impl wl_keyboard::Handler for WaylandEnv {
wl_keyboard::KeyState::Released => ElementState::Released, wl_keyboard::KeyState::Released => ElementState::Released,
}; };
let mut guard = eviter.lock().unwrap(); let mut guard = eviter.lock().unwrap();
// TODO implement ModifiersState
guard.push_back(Event::KeyboardInput( guard.push_back(Event::KeyboardInput(
state, state,
key as u8, key as u8,
None None,
ModifiersState::default()
)); ));
}, },
KbdType::Plain(None) => () KbdType::Plain(None) => ()

View file

@ -3,6 +3,8 @@ use std::sync::{Arc, Mutex};
use {VirtualKeyCode, ElementState, WindowEvent as Event}; use {VirtualKeyCode, ElementState, WindowEvent as Event};
use events::ModifiersState;
use super::wayland_kbd; use super::wayland_kbd;
use wayland_client::EventQueueHandle; use wayland_client::EventQueueHandle;
use wayland_client::protocol::wl_keyboard; use wayland_client::protocol::wl_keyboard;
@ -35,7 +37,8 @@ impl wayland_kbd::Handler for KbdHandler {
}; };
let vkcode = key_to_vkey(rawkey, keysym); let vkcode = key_to_vkey(rawkey, keysym);
let mut guard = eviter.lock().unwrap(); 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 // send char event only on key press, not release
if let ElementState::Released = state { return } if let ElementState::Released = state { return }
if let Some(txt) = utf8 { if let Some(txt) = utf8 {

View file

@ -8,6 +8,7 @@ use std::slice::from_raw_parts;
use WindowAttributes; use WindowAttributes;
use events::WindowEvent as Event; use events::WindowEvent as Event;
use events::ModifiersState;
use super::{events, ffi}; use super::{events, ffi};
use super::XConnection; use super::XConnection;
@ -139,6 +140,8 @@ impl XInputEventHandler {
let mut kp_keysym = 0; let mut kp_keysym = 0;
let mut ev_mods = ModifiersState::default();
let written = unsafe { let written = unsafe {
use std::str; use std::str;
@ -148,6 +151,26 @@ impl XInputEventHandler {
mem::transmute(buffer.as_mut_ptr()), mem::transmute(buffer.as_mut_ptr()),
buffer.len() as libc::c_int, &mut kp_keysym, ptr::null_mut()); buffer.len() as libc::c_int, &mut kp_keysym, ptr::null_mut());
{
// Translate x event state to mods
let state = event.state;
if (state & ffi::Mod1Mask) != 0 {
ev_mods.alt = true;
}
if (state & ffi::ShiftMask) != 0 {
ev_mods.shift = true;
}
if (state & ffi::ControlMask) != 0 {
ev_mods.ctrl = true;
}
if (state & ffi::Mod4Mask) != 0 {
ev_mods.logo = true;
}
}
str::from_utf8(&buffer[..count as usize]).unwrap_or("").to_string() str::from_utf8(&buffer[..count as usize]).unwrap_or("").to_string()
}; };
@ -165,7 +188,7 @@ impl XInputEventHandler {
let vkey = events::keycode_to_element(keysym as libc::c_uint); 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, ev_mods));
translated_events translated_events
} }

View file

@ -35,7 +35,7 @@ pub enum WindowEvent {
Focused(bool), Focused(bool),
/// An event from the keyboard has been received. /// An event from the keyboard has been received.
KeyboardInput(ElementState, ScanCode, Option<VirtualKeyCode>), KeyboardInput(ElementState, ScanCode, Option<VirtualKeyCode>, ModifiersState),
/// The cursor has moved on the window. /// The cursor has moved on the window.
/// ///
@ -320,3 +320,20 @@ pub enum VirtualKeyCode {
WebStop, WebStop,
Yen, 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
}

View file

@ -1,6 +1,6 @@
use cocoa::{self, appkit, foundation}; use cocoa::{self, appkit, foundation};
use cocoa::appkit::{NSApplication, NSEvent, NSView, NSWindow}; use cocoa::appkit::{NSApplication, NSEvent, NSView, NSWindow};
use events::{self, ElementState, Event, MouseButton, TouchPhase, WindowEvent}; use events::{self, ElementState, Event, MouseButton, TouchPhase, WindowEvent, ModifiersState};
use super::window::Window; use super::window::Window;
use std; use std;
@ -271,7 +271,7 @@ impl EventsLoop {
let vkey = to_virtual_key_code(NSEvent::keyCode(ns_event)); let vkey = to_virtual_key_code(NSEvent::keyCode(ns_event));
let state = ElementState::Pressed; let state = ElementState::Pressed;
let code = NSEvent::keyCode(ns_event) as u8; let code = NSEvent::keyCode(ns_event) as u8;
let window_event = WindowEvent::KeyboardInput(state, code, vkey); let window_event = WindowEvent::KeyboardInput(state, code, vkey, event_mods(ns_event));
events.push_back(into_event(window_event)); events.push_back(into_event(window_event));
let event = events.pop_front(); let event = events.pop_front();
self.pending_events.lock().unwrap().extend(events.into_iter()); self.pending_events.lock().unwrap().extend(events.into_iter());
@ -283,7 +283,7 @@ impl EventsLoop {
let state = ElementState::Released; let state = ElementState::Released;
let code = NSEvent::keyCode(ns_event) as u8; let code = NSEvent::keyCode(ns_event) as u8;
let window_event = WindowEvent::KeyboardInput(state, code, vkey); let window_event = WindowEvent::KeyboardInput(state, code, vkey, event_mods(ns_event));
Some(into_event(window_event)) Some(into_event(window_event))
}, },
@ -298,13 +298,13 @@ impl EventsLoop {
if !key_pressed && NSEvent::modifierFlags(event).contains(keymask) { if !key_pressed && NSEvent::modifierFlags(event).contains(keymask) {
let state = ElementState::Pressed; let state = ElementState::Pressed;
let code = NSEvent::keyCode(event) as u8; 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), event_mods(event));
Some(window_event) Some(window_event)
} else if key_pressed && !NSEvent::modifierFlags(event).contains(keymask) { } else if key_pressed && !NSEvent::modifierFlags(event).contains(keymask) {
let state = ElementState::Released; let state = ElementState::Released;
let code = NSEvent::keyCode(event) as u8; 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), event_mods(event));
Some(window_event) Some(window_event)
} else { } else {
@ -575,3 +575,15 @@ fn to_virtual_key_code(code: u16) -> Option<events::VirtualKeyCode> {
_ => return None, _ => return None,
}) })
} }
fn event_mods(event: cocoa::base::id) -> ModifiersState {
let flags = unsafe {
NSEvent::modifierFlags(event)
};
ModifiersState {
shift: flags.contains(appkit::NSShiftKeyMask),
ctrl: flags.contains(appkit::NSControlKeyMask),
alt: flags.contains(appkit::NSAlternateKeyMask),
logo: flags.contains(appkit::NSCommandKeyMask),
}
}

View file

@ -8,6 +8,7 @@ use std::os::windows::ffi::OsStringExt;
use CursorState; use CursorState;
use WindowEvent as Event; use WindowEvent as Event;
use events::ModifiersState;
use super::event; use super::event;
use super::WindowState; 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) user32::DefWindowProcW(window, msg, wparam, lparam)
} else { } else {
let (scancode, vkey) = event::vkeycode_to_element(wparam, lparam); let (scancode, vkey) = event::vkeycode_to_element(wparam, lparam);
send_event(window, KeyboardInput(Pressed, scancode, vkey)); send_event(window, KeyboardInput(Pressed, scancode, vkey, event::get_key_mods()));
0 0
} }
}, },
@ -209,7 +210,7 @@ pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT,
use events::WindowEvent::KeyboardInput; use events::WindowEvent::KeyboardInput;
use events::ElementState::Released; use events::ElementState::Released;
let (scancode, vkey) = event::vkeycode_to_element(wparam, lparam); let (scancode, vkey) = event::vkeycode_to_element(wparam, lparam);
send_event(window, KeyboardInput(Released, scancode, vkey)); send_event(window, KeyboardInput(Released, scancode, vkey, event::get_key_mods()));
0 0
}, },

View file

@ -1,10 +1,30 @@
use events::VirtualKeyCode; use events::VirtualKeyCode;
use events::ModifiersState;
use winapi; use winapi;
use user32; use user32;
use ScanCode; use ScanCode;
const MAPVK_VSC_TO_VK_EX: u32 = 3; const MAPVK_VSC_TO_VK_EX: u32 = 3;
pub fn get_key_mods() -> ModifiersState {
let mut mods = ModifiersState::default();
unsafe {
if user32::GetKeyState(winapi::VK_SHIFT) & (1 << 15) == (1 << 15) {
mods.shift = true;
}
if user32::GetKeyState(winapi::VK_CONTROL) & (1 << 15) == (1 << 15) {
mods.ctrl = true;
}
if user32::GetKeyState(winapi::VK_MENU) & (1 << 15) == (1 << 15) {
mods.alt = true;
}
if (user32::GetKeyState(winapi::VK_LWIN) | user32::GetKeyState(winapi::VK_RWIN)) & (1 << 15) == (1 << 15) {
mods.logo = true;
}
}
mods
}
pub fn vkeycode_to_element(wparam: winapi::WPARAM, lparam: winapi::LPARAM) -> (ScanCode, Option<VirtualKeyCode>) { pub fn vkeycode_to_element(wparam: winapi::WPARAM, lparam: winapi::LPARAM) -> (ScanCode, Option<VirtualKeyCode>) {
let scancode = ((lparam >> 16) & 0xff) as u8; let scancode = ((lparam >> 16) & 0xff) as u8;
let extended = (lparam & 0x01000000) != 0; let extended = (lparam & 0x01000000) != 0;