Skip to content

Commit

Permalink
Rework KeyState interface
Browse files Browse the repository at this point in the history
  • Loading branch information
breqdev committed Nov 23, 2023
1 parent 4e03205 commit acccffb
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 117 deletions.
70 changes: 44 additions & 26 deletions src/keyboard/commodore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ impl KeyAdapter<KeySymbol, C64Keys> for C64SymbolAdapter {
})
}

if mapped.pressed().is_empty() {
if mapped.is_empty() {
// If no non-shifted keys were pressed, check for shifted keys.
for symbol in state.pressed() {
use KeySymbol::*;
Expand Down Expand Up @@ -286,7 +286,7 @@ impl KeyAdapter<KeySymbol, C64Keys> for C64SymbolAdapter {
}

// If we added keys, make sure shift is pressed
if !mapped.pressed().is_empty() {
if !mapped.is_empty() {
mapped.press(C64Keys::LShift);
}
}
Expand Down Expand Up @@ -327,8 +327,13 @@ mod tests {
let mapped = C64KeyboardAdapter::map(&positions);

assert_eq!(
&vec![C64Keys::Q, C64Keys::Digit2, C64Keys::Comma, C64Keys::Return],
mapped.pressed()
vec![
&C64Keys::Q,
&C64Keys::Digit2,
&C64Keys::Comma,
&C64Keys::Return
],
mapped.pressed().collect::<Vec<_>>()
);

positions.press(KeyPosition::LShift);
Expand All @@ -337,8 +342,13 @@ mod tests {
let mapped = C64KeyboardAdapter::map(&positions);

assert_eq!(
&vec![C64Keys::Q, C64Keys::Digit2, C64Keys::Comma, C64Keys::LShift],
mapped.pressed()
vec![
&C64Keys::Q,
&C64Keys::Digit2,
&C64Keys::Comma,
&C64Keys::LShift
],
mapped.pressed().collect::<Vec<_>>()
);
}

Expand All @@ -354,8 +364,13 @@ mod tests {
let mapped = C64SymbolAdapter::map(&symbols);

assert_eq!(
&vec![C64Keys::Q, C64Keys::Digit2, C64Keys::Comma, C64Keys::Return],
mapped.pressed()
vec![
&C64Keys::Q,
&C64Keys::Digit2,
&C64Keys::Comma,
&C64Keys::Return
],
mapped.pressed().collect::<Vec<_>>()
);
}

Expand All @@ -370,13 +385,13 @@ mod tests {
let mapped = C64SymbolAdapter::map(&symbols);

assert_eq!(
&vec![
C64Keys::Digit1,
C64Keys::Comma,
C64Keys::Period,
C64Keys::LShift
vec![
&C64Keys::Digit1,
&C64Keys::Comma,
&C64Keys::Period,
&C64Keys::LShift
],
mapped.pressed()
mapped.pressed().collect::<Vec<_>>()
);
}

Expand All @@ -392,7 +407,10 @@ mod tests {
let mapped = C64SymbolAdapter::map(&symbols);

// Do a "best effort" mapping, dropping the shifted keys
assert_eq!(&vec![C64Keys::Digit1, C64Keys::Return], mapped.pressed());
assert_eq!(
vec![&C64Keys::Digit1, &C64Keys::Return],
mapped.pressed().collect::<Vec<_>>()
);
}

#[test]
Expand All @@ -401,32 +419,32 @@ mod tests {

state.press(KeySymbol::DownArrow);
assert_eq!(
&vec![C64Keys::CursorUpDown],
C64SymbolAdapter::map(&state).pressed()
vec![&C64Keys::CursorUpDown],
C64SymbolAdapter::map(&state).pressed().collect::<Vec<_>>()
);

state.release(KeySymbol::DownArrow);
state.press(KeySymbol::UpArrow);
assert_eq!(
&vec![C64Keys::CursorUpDown, C64Keys::LShift],
C64SymbolAdapter::map(&state).pressed()
vec![&C64Keys::CursorUpDown, &C64Keys::LShift],
C64SymbolAdapter::map(&state).pressed().collect::<Vec<_>>()
);

state.press(KeySymbol::LeftArrow);
assert_eq!(
&vec![
C64Keys::CursorUpDown,
C64Keys::CursorLeftRight,
C64Keys::LShift
vec![
&C64Keys::CursorUpDown,
&C64Keys::CursorLeftRight,
&C64Keys::LShift
],
C64SymbolAdapter::map(&state).pressed()
C64SymbolAdapter::map(&state).pressed().collect::<Vec<_>>()
);

// map the right arrow, but give up on the rest
state.press(KeySymbol::RightArrow);
assert_eq!(
&vec![C64Keys::CursorLeftRight],
C64SymbolAdapter::map(&state).pressed()
vec![&C64Keys::CursorLeftRight],
C64SymbolAdapter::map(&state).pressed().collect::<Vec<_>>()
);
}
}
22 changes: 16 additions & 6 deletions src/keyboard/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ pub use virtualkey::VirtualKey;
/// A set of keys that are currently pressed.
/// Parameter `T` is the type of the key symbols.
#[derive(Default, Debug, Clone, PartialEq)]
pub struct KeyState<T: PartialEq> {
pub struct KeyState<T: PartialEq + Clone> {
pressed: Vec<T>,
}

impl<T: PartialEq> KeyState<T> {
impl<T: PartialEq + Clone> KeyState<T> {
/// Creates a new, empty key state.
pub fn new() -> Self {
Self {
Expand All @@ -42,17 +42,27 @@ impl<T: PartialEq> KeyState<T> {
}

/// Return the set of pressed keys.
pub fn pressed(&self) -> &Vec<T> {
&self.pressed
pub fn pressed(&self) -> impl Iterator<Item = &T> {
self.pressed.iter()
}

/// Returns true if the given key is currently pressed.
pub fn is_pressed(&self, symbol: T) -> bool {
self.pressed.contains(&symbol)
}

/// Returns true if the set of keys is empty.
pub fn is_empty(&self) -> bool {
self.pressed.is_empty()
}

/// Returns the most recent key pressed.
pub fn get_one_key(&self) -> Option<T> {
self.pressed.last().cloned()
}
}

impl<T: PartialEq> BitOr<KeyState<T>> for KeyState<T> {
impl<T: PartialEq + Clone> BitOr<KeyState<T>> for KeyState<T> {
type Output = KeyState<T>;

fn bitor(self, rhs: Self) -> Self::Output {
Expand All @@ -70,7 +80,7 @@ impl<T: PartialEq> BitOr<KeyState<T>> for KeyState<T> {
/// Mappings can be symbolic (preserve symbols across the mapping, and rewrite
/// modifier keys as needed) or physical (maintain a one-to-one mapping from
/// physical keys to physical keys).
pub trait KeyAdapter<F: PartialEq, T: PartialEq> {
pub trait KeyAdapter<F: PartialEq + Clone, T: PartialEq + Clone> {
/// Map the current state of the keyboard with symbols of type `F` to an
/// equivalent keyboard state with symbols of type `T`.
fn map(state: &KeyState<F>) -> KeyState<T>;
Expand Down
123 changes: 63 additions & 60 deletions src/keyboard/symbols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,13 +338,13 @@ mod tests {

let symbols = SymbolAdapter::map(&positions);
assert_eq!(
&vec![
KeySymbol::Char('b'),
KeySymbol::Char('m'),
KeySymbol::Char('c'),
vec![
&KeySymbol::Char('b'),
&KeySymbol::Char('m'),
&KeySymbol::Char('c'),
],
symbols.pressed()
);
symbols.pressed().collect::<Vec<_>>()
)
}

#[test]
Expand All @@ -357,12 +357,12 @@ mod tests {

let symbols = SymbolAdapter::map(&positions);
assert_eq!(
&vec![
KeySymbol::Char('B'),
KeySymbol::Char('M'),
KeySymbol::Char('C'),
vec![
&KeySymbol::Char('B'),
&KeySymbol::Char('M'),
&KeySymbol::Char('C'),
],
symbols.pressed()
symbols.pressed().collect::<Vec<_>>()
);
}

Expand All @@ -375,24 +375,24 @@ mod tests {

let symbols = SymbolAdapter::map(&positions);
assert_eq!(
&vec![
KeySymbol::Char('1'),
KeySymbol::Char('2'),
KeySymbol::Char('3'),
vec![
&KeySymbol::Char('1'),
&KeySymbol::Char('2'),
&KeySymbol::Char('3'),
],
symbols.pressed()
symbols.pressed().collect::<Vec<_>>()
);

positions.press(KeyPosition::LShift);

let symbols = SymbolAdapter::map(&positions);
assert_eq!(
&vec![
KeySymbol::Char('!'),
KeySymbol::Char('@'),
KeySymbol::Char('#'),
vec![
&KeySymbol::Char('!'),
&KeySymbol::Char('@'),
&KeySymbol::Char('#'),
],
symbols.pressed()
symbols.pressed().collect::<Vec<_>>()
);
}

Expand All @@ -405,12 +405,12 @@ mod tests {

let symbols = SymbolAdapter::map(&positions);
assert_eq!(
&vec![
KeySymbol::Return,
KeySymbol::Backspace,
KeySymbol::Char(' '),
vec![
&KeySymbol::Return,
&KeySymbol::Backspace,
&KeySymbol::Char(' '),
],
symbols.pressed()
symbols.pressed().collect::<Vec<_>>()
);
}

Expand Down Expand Up @@ -441,43 +441,43 @@ mod tests {
let symbols = SymbolAdapter::map(&positions);

assert_eq!(
&vec![
KeySymbol::Char('q'),
KeySymbol::Char('a'),
KeySymbol::Char('b'),
KeySymbol::Char('6'),
KeySymbol::Char('7'),
KeySymbol::Char('8'),
KeySymbol::Char('-'),
KeySymbol::Char('\\'),
KeySymbol::Char(';'),
KeySymbol::Char(','),
KeySymbol::Return,
KeySymbol::LAlt,
vec![
&KeySymbol::Char('q'),
&KeySymbol::Char('a'),
&KeySymbol::Char('b'),
&KeySymbol::Char('6'),
&KeySymbol::Char('7'),
&KeySymbol::Char('8'),
&KeySymbol::Char('-'),
&KeySymbol::Char('\\'),
&KeySymbol::Char(';'),
&KeySymbol::Char(','),
&KeySymbol::Return,
&KeySymbol::LAlt,
],
symbols.pressed()
symbols.pressed().collect::<Vec<_>>()
);

positions.press(KeyPosition::LShift);

let symbols = SymbolAdapter::map(&positions);

assert_eq!(
&vec![
KeySymbol::Char('Q'),
KeySymbol::Char('A'),
KeySymbol::Char('B'),
KeySymbol::Char('^'),
KeySymbol::Char('&'),
KeySymbol::Char('*'),
KeySymbol::Char('_'),
KeySymbol::Char('|'),
KeySymbol::Char(':'),
KeySymbol::Char('<'),
KeySymbol::Return,
KeySymbol::LAlt,
vec![
&KeySymbol::Char('Q'),
&KeySymbol::Char('A'),
&KeySymbol::Char('B'),
&KeySymbol::Char('^'),
&KeySymbol::Char('&'),
&KeySymbol::Char('*'),
&KeySymbol::Char('_'),
&KeySymbol::Char('|'),
&KeySymbol::Char(':'),
&KeySymbol::Char('<'),
&KeySymbol::Return,
&KeySymbol::LAlt,
],
symbols.pressed()
symbols.pressed().collect::<Vec<_>>()
);
}

Expand All @@ -501,12 +501,12 @@ mod tests {
let symbols = SymbolAdapter::map(&positions);

assert_eq!(
&vec![
KeySymbol::Char('b'),
KeySymbol::Char('m'),
KeySymbol::Char('c'),
vec![
&KeySymbol::Char('b'),
&KeySymbol::Char('m'),
&KeySymbol::Char('c'),
],
symbols.pressed()
symbols.pressed().collect::<Vec<_>>()
);
}

Expand All @@ -519,6 +519,9 @@ mod tests {

let symbols = SymbolAdapter::map(&positions);

assert_eq!(&vec![KeySymbol::Interrupt], symbols.pressed());
assert_eq!(
vec![&KeySymbol::Interrupt],
symbols.pressed().collect::<Vec<_>>()
);
}
}
Loading

0 comments on commit acccffb

Please sign in to comment.