Add modifier keys to every keyboard and mouse input (#247)

* Add modifier keys to every keyboard and mouse input

* Fix bad naming convention in Typescript

* Added some tests related to modifier keys
This commit is contained in:
Simon Desloges
2021-07-11 23:46:00 -04:00
committed by Keavon Chambers
parent 1454be24d3
commit bb79bbd0e4
6 changed files with 159 additions and 32 deletions

View File

@@ -1,6 +1,9 @@
use std::usize;
use super::keyboard::{Key, KeyStates};
use super::mouse::{MouseKeys, MouseState, ViewportPosition};
use crate::message_prelude::*;
use bitflags::bitflags;
#[doc(inline)]
pub use document_core::DocumentResponse;
@@ -8,11 +11,21 @@ pub use document_core::DocumentResponse;
#[impl_message(Message, InputPreprocessor)]
#[derive(PartialEq, Clone, Debug)]
pub enum InputPreprocessorMessage {
MouseDown(MouseState),
MouseUp(MouseState),
MouseMove(ViewportPosition),
KeyUp(Key),
KeyDown(Key),
MouseDown(MouseState, ModifierKeys),
MouseUp(MouseState, ModifierKeys),
MouseMove(ViewportPosition, ModifierKeys),
KeyUp(Key, ModifierKeys),
KeyDown(Key, ModifierKeys),
}
bitflags! {
#[derive(Default)]
#[repr(transparent)]
pub struct ModifierKeys: u8 {
const CONTROL = 0b0000_0001;
const SHIFT = 0b0000_0010;
const ALT = 0b0000_0100;
}
}
#[derive(Debug, Default)]
@@ -29,17 +42,26 @@ enum KeyPosition {
impl MessageHandler<InputPreprocessorMessage, ()> for InputPreprocessor {
fn process_action(&mut self, message: InputPreprocessorMessage, _data: (), responses: &mut VecDeque<Message>) {
let response = match message {
InputPreprocessorMessage::MouseMove(pos) => {
InputPreprocessorMessage::MouseMove(pos, modifier_keys) => {
self.handle_modifier_keys(modifier_keys, responses);
self.mouse.position = pos;
InputMapperMessage::PointerMove.into()
}
InputPreprocessorMessage::MouseDown(state) => self.translate_mouse_event(state, KeyPosition::Pressed),
InputPreprocessorMessage::MouseUp(state) => self.translate_mouse_event(state, KeyPosition::Released),
InputPreprocessorMessage::KeyDown(key) => {
InputPreprocessorMessage::MouseDown(state, modifier_keys) => {
self.handle_modifier_keys(modifier_keys, responses);
self.translate_mouse_event(state, KeyPosition::Pressed)
}
InputPreprocessorMessage::MouseUp(state, modifier_keys) => {
self.handle_modifier_keys(modifier_keys, responses);
self.translate_mouse_event(state, KeyPosition::Released)
}
InputPreprocessorMessage::KeyDown(key, modifier_keys) => {
self.handle_modifier_keys(modifier_keys, responses);
self.keyboard.set(key as usize);
InputMapperMessage::KeyDown(key).into()
}
InputPreprocessorMessage::KeyUp(key) => {
InputPreprocessorMessage::KeyUp(key, modifier_keys) => {
self.handle_modifier_keys(modifier_keys, responses);
self.keyboard.unset(key as usize);
InputMapperMessage::KeyUp(key).into()
}
@@ -71,4 +93,89 @@ impl InputPreprocessor {
KeyPosition::Released => InputMapperMessage::KeyUp(key).into(),
}
}
fn handle_modifier_keys(&mut self, modifier_keys: ModifierKeys, responses: &mut VecDeque<Message>) {
self.handle_modifier_key(Key::KeyControl, modifier_keys.contains(ModifierKeys::CONTROL), responses);
self.handle_modifier_key(Key::KeyShift, modifier_keys.contains(ModifierKeys::SHIFT), responses);
self.handle_modifier_key(Key::KeyAlt, modifier_keys.contains(ModifierKeys::ALT), responses);
}
fn handle_modifier_key(&mut self, key: Key, key_is_down: bool, responses: &mut VecDeque<Message>) {
let key_was_down = self.keyboard.get(key as usize);
if key_was_down && !key_is_down {
self.keyboard.unset(key as usize);
responses.push_back(InputMapperMessage::KeyUp(key).into());
} else if !key_was_down && key_is_down {
self.keyboard.set(key as usize);
responses.push_back(InputMapperMessage::KeyDown(key).into());
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn process_action_mouse_move_handle_modifier_keys() {
let mut input_preprocessor = InputPreprocessor::default();
let message = InputPreprocessorMessage::MouseMove(ViewportPosition { x: 4, y: 809 }, ModifierKeys::ALT);
let mut responses = VecDeque::new();
input_preprocessor.process_action(message, (), &mut responses);
assert!(input_preprocessor.keyboard.get(Key::KeyAlt as usize));
assert_eq!(responses.pop_front(), Some(InputMapperMessage::KeyDown(Key::KeyAlt).into()));
}
#[test]
fn process_action_mouse_down_handle_modifier_keys() {
let mut input_preprocessor = InputPreprocessor::default();
let message = InputPreprocessorMessage::MouseDown(MouseState::new(), ModifierKeys::CONTROL);
let mut responses = VecDeque::new();
input_preprocessor.process_action(message, (), &mut responses);
assert!(input_preprocessor.keyboard.get(Key::KeyControl as usize));
assert_eq!(responses.pop_front(), Some(InputMapperMessage::KeyDown(Key::KeyControl).into()));
}
#[test]
fn process_action_mouse_up_handle_modifier_keys() {
let mut input_preprocessor = InputPreprocessor::default();
let message = InputPreprocessorMessage::MouseUp(MouseState::new(), ModifierKeys::SHIFT);
let mut responses = VecDeque::new();
input_preprocessor.process_action(message, (), &mut responses);
assert!(input_preprocessor.keyboard.get(Key::KeyShift as usize));
assert_eq!(responses.pop_front(), Some(InputMapperMessage::KeyDown(Key::KeyShift).into()));
}
#[test]
fn process_action_key_down_handle_modifier_keys() {
let mut input_preprocessor = InputPreprocessor::default();
input_preprocessor.keyboard.set(Key::KeyControl as usize);
let message = InputPreprocessorMessage::KeyDown(Key::KeyA, ModifierKeys::empty());
let mut responses = VecDeque::new();
input_preprocessor.process_action(message, (), &mut responses);
assert!(!input_preprocessor.keyboard.get(Key::KeyControl as usize));
assert_eq!(responses.pop_front(), Some(InputMapperMessage::KeyUp(Key::KeyControl).into()));
}
#[test]
fn process_action_key_up_handle_modifier_keys() {
let mut input_preprocessor = InputPreprocessor::default();
let message = InputPreprocessorMessage::KeyUp(Key::KeyS, ModifierKeys::CONTROL | ModifierKeys::SHIFT);
let mut responses = VecDeque::new();
input_preprocessor.process_action(message, (), &mut responses);
assert!(input_preprocessor.keyboard.get(Key::KeyControl as usize));
assert!(input_preprocessor.keyboard.get(Key::KeyShift as usize));
assert!(responses.contains(&InputMapperMessage::KeyDown(Key::KeyControl).into()));
assert!(responses.contains(&InputMapperMessage::KeyDown(Key::KeyControl).into()));
}
}

View File

@@ -102,6 +102,10 @@ impl<const LENGTH: usize> BitVector<LENGTH> {
let (offset, bit) = Self::convert_index(bitvector_index);
self.0[offset] ^= bit;
}
pub fn get(&mut self, bitvector_index: usize) -> bool {
let (offset, bit) = Self::convert_index(bitvector_index);
(self.0[offset] & bit) != 0
}
pub fn is_empty(&self) -> bool {
let mut result = 0;
for storage in self.0.iter() {

View File

@@ -5,5 +5,5 @@ pub mod mouse;
pub use {
input_mapper::{InputMapper, InputMapperMessage, InputMapperMessageDiscriminant},
input_preprocessor::{InputPreprocessor, InputPreprocessorMessage, InputPreprocessorMessageDiscriminant},
input_preprocessor::{InputPreprocessor, InputPreprocessorMessage, InputPreprocessorMessageDiscriminant, ModifierKeys},
};

View File

@@ -1,7 +1,7 @@
use crate::{
input::{
mouse::{MouseKeys, MouseState, ViewportPosition},
InputPreprocessorMessage,
InputPreprocessorMessage, ModifierKeys,
},
message_prelude::{Message, ToolMessage},
tool::ToolType,
@@ -51,15 +51,15 @@ impl EditorTestUtils for Editor {
}
fn move_mouse(&mut self, x: u32, y: u32) {
self.input(InputPreprocessorMessage::MouseMove(ViewportPosition { x, y }));
self.input(InputPreprocessorMessage::MouseMove(ViewportPosition { x, y }, ModifierKeys::default()));
}
fn mousedown(&mut self, state: MouseState) {
self.input(InputPreprocessorMessage::MouseDown(state));
self.input(InputPreprocessorMessage::MouseDown(state, ModifierKeys::default()));
}
fn mouseup(&mut self, state: MouseState) {
self.handle_message(InputPreprocessorMessage::MouseUp(state)).unwrap()
self.handle_message(InputPreprocessorMessage::MouseUp(state, ModifierKeys::default())).unwrap()
}
fn lmb_mousedown(&mut self, x: u32, y: u32) {