KeyEvent case normalizing equality (#541)

This commit is contained in:
Necrosovereign 2021-04-13 08:49:04 +02:00 committed by GitHub
parent 58f580eaad
commit 92f62ba86f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -73,6 +73,7 @@
//! them (`event-*`). //! them (`event-*`).
use std::fmt; use std::fmt;
use std::hash::{Hash, Hasher};
use std::time::Duration; use std::time::Duration;
use bitflags::bitflags; use bitflags::bitflags;
@ -385,7 +386,7 @@ bitflags! {
/// Represents a key event. /// Represents a key event.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)] #[derive(Debug, PartialOrd, Clone, Copy)]
pub struct KeyEvent { pub struct KeyEvent {
/// The key itself. /// The key itself.
pub code: KeyCode, pub code: KeyCode,
@ -397,6 +398,23 @@ impl KeyEvent {
pub fn new(code: KeyCode, modifiers: KeyModifiers) -> KeyEvent { pub fn new(code: KeyCode, modifiers: KeyModifiers) -> KeyEvent {
KeyEvent { code, modifiers } KeyEvent { code, modifiers }
} }
// modifies the KeyEvent,
// so that KeyModifiers::SHIFT is present iff
// an uppercase char is present.
fn normalize_case(mut self) -> KeyEvent {
let c = match self.code {
KeyCode::Char(c) => c,
_ => return self,
};
if c.is_ascii_uppercase() {
self.modifiers.insert(KeyModifiers::SHIFT);
} else if self.modifiers.contains(KeyModifiers::SHIFT) {
self.code = KeyCode::Char(c.to_ascii_uppercase())
}
self
}
} }
impl From<KeyCode> for KeyEvent { impl From<KeyCode> for KeyEvent {
@ -408,6 +426,30 @@ impl From<KeyCode> for KeyEvent {
} }
} }
impl PartialEq for KeyEvent {
fn eq(&self, other: &KeyEvent) -> bool {
let KeyEvent {
code: lhs_code,
modifiers: lhs_modifiers,
} = self.normalize_case();
let KeyEvent {
code: rhs_code,
modifiers: rhs_modifiers,
} = other.normalize_case();
(lhs_code == rhs_code) && (lhs_modifiers == rhs_modifiers)
}
}
impl Eq for KeyEvent {}
impl Hash for KeyEvent {
fn hash<H: Hasher>(&self, state: &mut H) {
let KeyEvent { code, modifiers } = self.normalize_case();
code.hash(state);
modifiers.hash(state);
}
}
/// Represents a key. /// Represents a key.
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)] #[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@ -466,3 +508,41 @@ pub(crate) enum InternalEvent {
#[cfg(unix)] #[cfg(unix)]
CursorPosition(u16, u16), CursorPosition(u16, u16),
} }
#[cfg(test)]
mod tests {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use super::{KeyCode, KeyEvent, KeyModifiers};
#[test]
fn test_equality() {
let lowercase_d_with_shift = KeyEvent::new(KeyCode::Char('d'), KeyModifiers::SHIFT);
let uppercase_d_with_shift = KeyEvent::new(KeyCode::Char('D'), KeyModifiers::SHIFT);
let uppercase_d = KeyEvent::new(KeyCode::Char('D'), KeyModifiers::NONE);
assert_eq!(lowercase_d_with_shift, uppercase_d_with_shift);
assert_eq!(uppercase_d, uppercase_d_with_shift);
}
#[test]
fn test_hash() {
let lowercase_d_with_shift_hash = {
let mut hasher = DefaultHasher::new();
KeyEvent::new(KeyCode::Char('d'), KeyModifiers::SHIFT).hash(&mut hasher);
hasher.finish()
};
let uppercase_d_with_shift_hash = {
let mut hasher = DefaultHasher::new();
KeyEvent::new(KeyCode::Char('D'), KeyModifiers::SHIFT).hash(&mut hasher);
hasher.finish()
};
let uppercase_d_hash = {
let mut hasher = DefaultHasher::new();
KeyEvent::new(KeyCode::Char('D'), KeyModifiers::NONE).hash(&mut hasher);
hasher.finish()
};
assert_eq!(lowercase_d_with_shift_hash, uppercase_d_with_shift_hash);
assert_eq!(uppercase_d_hash, uppercase_d_with_shift_hash);
}
}