pub(crate) mod filter;
pub(crate) mod read;
pub(crate) mod source;
#[cfg(feature = "event-stream")]
pub(crate) mod stream;
pub(crate) mod sys;
pub(crate) mod timeout;
#[cfg(feature = "derive-more")]
use derive_more::derive::IsVariant;
#[cfg(feature = "event-stream")]
pub use stream::EventStream;
use crate::event::{
filter::{EventFilter, Filter},
read::InternalEventReader,
timeout::PollTimeout,
};
use crate::{csi, Command};
use parking_lot::{MappedMutexGuard, Mutex, MutexGuard};
use std::fmt::{self, Display};
use std::time::Duration;
use bitflags::bitflags;
use std::hash::{Hash, Hasher};
static INTERNAL_EVENT_READER: Mutex<Option<InternalEventReader>> = parking_lot::const_mutex(None);
pub(crate) fn lock_internal_event_reader() -> MappedMutexGuard<'static, InternalEventReader> {
MutexGuard::map(INTERNAL_EVENT_READER.lock(), |reader| {
reader.get_or_insert_with(InternalEventReader::default)
})
}
fn try_lock_internal_event_reader_for(
duration: Duration,
) -> Option<MappedMutexGuard<'static, InternalEventReader>> {
Some(MutexGuard::map(
INTERNAL_EVENT_READER.try_lock_for(duration)?,
|reader| reader.get_or_insert_with(InternalEventReader::default),
))
}
pub fn poll(timeout: Duration) -> std::io::Result<bool> {
poll_internal(Some(timeout), &EventFilter)
}
pub fn read() -> std::io::Result<Event> {
match read_internal(&EventFilter)? {
InternalEvent::Event(event) => Ok(event),
#[cfg(unix)]
_ => unreachable!(),
}
}
pub(crate) fn poll_internal<F>(timeout: Option<Duration>, filter: &F) -> std::io::Result<bool>
where
F: Filter,
{
let (mut reader, timeout) = if let Some(timeout) = timeout {
let poll_timeout = PollTimeout::new(Some(timeout));
if let Some(reader) = try_lock_internal_event_reader_for(timeout) {
(reader, poll_timeout.leftover())
} else {
return Ok(false);
}
} else {
(lock_internal_event_reader(), None)
};
reader.poll(timeout, filter)
}
pub(crate) fn read_internal<F>(filter: &F) -> std::io::Result<InternalEvent>
where
F: Filter,
{
let mut reader = lock_internal_event_reader();
reader.read(filter)
}
bitflags! {
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(transparent))]
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
pub struct KeyboardEnhancementFlags: u8 {
const DISAMBIGUATE_ESCAPE_CODES = 0b0000_0001;
const REPORT_EVENT_TYPES = 0b0000_0010;
const REPORT_ALTERNATE_KEYS = 0b0000_0100;
const REPORT_ALL_KEYS_AS_ESCAPE_CODES = 0b0000_1000;
}
}
#[cfg(feature = "events")]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EnableMouseCapture;
#[cfg(feature = "events")]
impl Command for EnableMouseCapture {
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
f.write_str(concat!(
csi!("?1000h"),
csi!("?1002h"),
csi!("?1003h"),
csi!("?1015h"),
csi!("?1006h"),
))
}
#[cfg(windows)]
fn execute_winapi(&self) -> std::io::Result<()> {
sys::windows::enable_mouse_capture()
}
#[cfg(windows)]
fn is_ansi_code_supported(&self) -> bool {
false
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DisableMouseCapture;
impl Command for DisableMouseCapture {
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
f.write_str(concat!(
csi!("?1006l"),
csi!("?1015l"),
csi!("?1003l"),
csi!("?1002l"),
csi!("?1000l"),
))
}
#[cfg(windows)]
fn execute_winapi(&self) -> std::io::Result<()> {
sys::windows::disable_mouse_capture()
}
#[cfg(windows)]
fn is_ansi_code_supported(&self) -> bool {
false
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EnableFocusChange;
impl Command for EnableFocusChange {
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
f.write_str(csi!("?1004h"))
}
#[cfg(windows)]
fn execute_winapi(&self) -> std::io::Result<()> {
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DisableFocusChange;
impl Command for DisableFocusChange {
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
f.write_str(csi!("?1004l"))
}
#[cfg(windows)]
fn execute_winapi(&self) -> std::io::Result<()> {
Ok(())
}
}
#[cfg(feature = "bracketed-paste")]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EnableBracketedPaste;
#[cfg(feature = "bracketed-paste")]
impl Command for EnableBracketedPaste {
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
f.write_str(csi!("?2004h"))
}
#[cfg(windows)]
fn execute_winapi(&self) -> std::io::Result<()> {
Err(std::io::Error::new(
std::io::ErrorKind::Unsupported,
"Bracketed paste not implemented in the legacy Windows API.",
))
}
}
#[cfg(feature = "bracketed-paste")]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DisableBracketedPaste;
#[cfg(feature = "bracketed-paste")]
impl Command for DisableBracketedPaste {
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
f.write_str(csi!("?2004l"))
}
#[cfg(windows)]
fn execute_winapi(&self) -> std::io::Result<()> {
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PushKeyboardEnhancementFlags(pub KeyboardEnhancementFlags);
impl Command for PushKeyboardEnhancementFlags {
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
write!(f, "{}{}u", csi!(">"), self.0.bits())
}
#[cfg(windows)]
fn execute_winapi(&self) -> std::io::Result<()> {
use std::io;
Err(io::Error::new(
io::ErrorKind::Unsupported,
"Keyboard progressive enhancement not implemented for the legacy Windows API.",
))
}
#[cfg(windows)]
fn is_ansi_code_supported(&self) -> bool {
false
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PopKeyboardEnhancementFlags;
impl Command for PopKeyboardEnhancementFlags {
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
f.write_str(csi!("<1u"))
}
#[cfg(windows)]
fn execute_winapi(&self) -> std::io::Result<()> {
use std::io;
Err(io::Error::new(
io::ErrorKind::Unsupported,
"Keyboard progressive enhancement not implemented for the legacy Windows API.",
))
}
#[cfg(windows)]
fn is_ansi_code_supported(&self) -> bool {
false
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "derive-more", derive(IsVariant))]
#[cfg_attr(not(feature = "bracketed-paste"), derive(Copy))]
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Hash)]
pub enum Event {
FocusGained,
FocusLost,
Key(KeyEvent),
Mouse(MouseEvent),
#[cfg(feature = "bracketed-paste")]
Paste(String),
Resize(u16, u16),
}
impl Event {
#[inline]
pub fn is_key_press(&self) -> bool {
matches!(
self,
Event::Key(KeyEvent {
kind: KeyEventKind::Press,
..
})
)
}
#[inline]
pub fn is_key_release(&self) -> bool {
matches!(
self,
Event::Key(KeyEvent {
kind: KeyEventKind::Release,
..
})
)
}
#[inline]
pub fn is_key_repeat(&self) -> bool {
matches!(
self,
Event::Key(KeyEvent {
kind: KeyEventKind::Repeat,
..
})
)
}
#[inline]
pub fn as_key_event(&self) -> Option<KeyEvent> {
match self {
Event::Key(event) => Some(*event),
_ => None,
}
}
#[inline]
pub fn as_key_press_event(&self) -> Option<KeyEvent> {
match self {
Event::Key(event) if self.is_key_press() => Some(*event),
_ => None,
}
}
#[inline]
pub fn as_key_release_event(&self) -> Option<KeyEvent> {
match self {
Event::Key(event) if self.is_key_release() => Some(*event),
_ => None,
}
}
#[inline]
pub fn as_key_repeat_event(&self) -> Option<KeyEvent> {
match self {
Event::Key(event) if self.is_key_repeat() => Some(*event),
_ => None,
}
}
#[inline]
pub fn as_mouse_event(&self) -> Option<MouseEvent> {
match self {
Event::Mouse(event) => Some(*event),
_ => None,
}
}
#[cfg(feature = "bracketed-paste")]
#[inline]
pub fn as_paste_event(&self) -> Option<&str> {
match self {
Event::Paste(paste) => Some(paste),
_ => None,
}
}
#[inline]
pub fn as_resize_event(&self) -> Option<(u16, u16)> {
match self {
Event::Resize(columns, rows) => Some((*columns, *rows)),
_ => None,
}
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
pub struct MouseEvent {
pub kind: MouseEventKind,
pub column: u16,
pub row: u16,
pub modifiers: KeyModifiers,
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "derive-more", derive(IsVariant))]
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
pub enum MouseEventKind {
Down(MouseButton),
Up(MouseButton),
Drag(MouseButton),
Moved,
ScrollDown,
ScrollUp,
ScrollLeft,
ScrollRight,
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "derive-more", derive(IsVariant))]
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
pub enum MouseButton {
Left,
Right,
Middle,
}
bitflags! {
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(transparent))]
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
pub struct KeyModifiers: u8 {
const SHIFT = 0b0000_0001;
const CONTROL = 0b0000_0010;
const ALT = 0b0000_0100;
const SUPER = 0b0000_1000;
const HYPER = 0b0001_0000;
const META = 0b0010_0000;
const NONE = 0b0000_0000;
}
}
impl Display for KeyModifiers {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut first = true;
for modifier in self.iter() {
if !first {
f.write_str("+")?;
}
first = false;
match modifier {
KeyModifiers::SHIFT => f.write_str("Shift")?,
#[cfg(unix)]
KeyModifiers::CONTROL => f.write_str("Control")?,
#[cfg(windows)]
KeyModifiers::CONTROL => f.write_str("Ctrl")?,
#[cfg(target_os = "macos")]
KeyModifiers::ALT => f.write_str("Option")?,
#[cfg(not(target_os = "macos"))]
KeyModifiers::ALT => f.write_str("Alt")?,
#[cfg(target_os = "macos")]
KeyModifiers::SUPER => f.write_str("Command")?,
#[cfg(target_os = "windows")]
KeyModifiers::SUPER => f.write_str("Windows")?,
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
KeyModifiers::SUPER => f.write_str("Super")?,
KeyModifiers::HYPER => f.write_str("Hyper")?,
KeyModifiers::META => f.write_str("Meta")?,
_ => unreachable!(),
}
}
Ok(())
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "derive-more", derive(IsVariant))]
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
pub enum KeyEventKind {
Press,
Repeat,
Release,
}
bitflags! {
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(transparent))]
pub struct KeyEventState: u8 {
const KEYPAD = 0b0000_0001;
const CAPS_LOCK = 0b0000_0010;
const NUM_LOCK = 0b0000_0100;
const NONE = 0b0000_0000;
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, PartialOrd, Clone, Copy)]
pub struct KeyEvent {
pub code: KeyCode,
pub modifiers: KeyModifiers,
pub kind: KeyEventKind,
pub state: KeyEventState,
}
impl KeyEvent {
pub const fn new(code: KeyCode, modifiers: KeyModifiers) -> KeyEvent {
KeyEvent {
code,
modifiers,
kind: KeyEventKind::Press,
state: KeyEventState::empty(),
}
}
pub const fn new_with_kind(
code: KeyCode,
modifiers: KeyModifiers,
kind: KeyEventKind,
) -> KeyEvent {
KeyEvent {
code,
modifiers,
kind,
state: KeyEventState::empty(),
}
}
pub const fn new_with_kind_and_state(
code: KeyCode,
modifiers: KeyModifiers,
kind: KeyEventKind,
state: KeyEventState,
) -> KeyEvent {
KeyEvent {
code,
modifiers,
kind,
state,
}
}
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
}
pub fn is_press(&self) -> bool {
matches!(self.kind, KeyEventKind::Press)
}
pub fn is_release(&self) -> bool {
matches!(self.kind, KeyEventKind::Release)
}
pub fn is_repeat(&self) -> bool {
matches!(self.kind, KeyEventKind::Repeat)
}
}
impl From<KeyCode> for KeyEvent {
fn from(code: KeyCode) -> Self {
KeyEvent {
code,
modifiers: KeyModifiers::empty(),
kind: KeyEventKind::Press,
state: KeyEventState::empty(),
}
}
}
impl PartialEq for KeyEvent {
fn eq(&self, other: &KeyEvent) -> bool {
let KeyEvent {
code: lhs_code,
modifiers: lhs_modifiers,
kind: lhs_kind,
state: lhs_state,
} = self.normalize_case();
let KeyEvent {
code: rhs_code,
modifiers: rhs_modifiers,
kind: rhs_kind,
state: rhs_state,
} = other.normalize_case();
(lhs_code == rhs_code)
&& (lhs_modifiers == rhs_modifiers)
&& (lhs_kind == rhs_kind)
&& (lhs_state == rhs_state)
}
}
impl Eq for KeyEvent {}
impl Hash for KeyEvent {
fn hash<H: Hasher>(&self, hash_state: &mut H) {
let KeyEvent {
code,
modifiers,
kind,
state,
} = self.normalize_case();
code.hash(hash_state);
modifiers.hash(hash_state);
kind.hash(hash_state);
state.hash(hash_state);
}
}
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum MediaKeyCode {
Play,
Pause,
PlayPause,
Reverse,
Stop,
FastForward,
Rewind,
TrackNext,
TrackPrevious,
Record,
LowerVolume,
RaiseVolume,
MuteVolume,
}
impl Display for MediaKeyCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MediaKeyCode::Play => write!(f, "Play"),
MediaKeyCode::Pause => write!(f, "Pause"),
MediaKeyCode::PlayPause => write!(f, "Play/Pause"),
MediaKeyCode::Reverse => write!(f, "Reverse"),
MediaKeyCode::Stop => write!(f, "Stop"),
MediaKeyCode::FastForward => write!(f, "Fast Forward"),
MediaKeyCode::Rewind => write!(f, "Rewind"),
MediaKeyCode::TrackNext => write!(f, "Next Track"),
MediaKeyCode::TrackPrevious => write!(f, "Previous Track"),
MediaKeyCode::Record => write!(f, "Record"),
MediaKeyCode::LowerVolume => write!(f, "Lower Volume"),
MediaKeyCode::RaiseVolume => write!(f, "Raise Volume"),
MediaKeyCode::MuteVolume => write!(f, "Mute Volume"),
}
}
}
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ModifierKeyCode {
LeftShift,
LeftControl,
LeftAlt,
LeftSuper,
LeftHyper,
LeftMeta,
RightShift,
RightControl,
RightAlt,
RightSuper,
RightHyper,
RightMeta,
IsoLevel3Shift,
IsoLevel5Shift,
}
impl Display for ModifierKeyCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ModifierKeyCode::LeftShift => write!(f, "Left Shift"),
ModifierKeyCode::LeftHyper => write!(f, "Left Hyper"),
ModifierKeyCode::LeftMeta => write!(f, "Left Meta"),
ModifierKeyCode::RightShift => write!(f, "Right Shift"),
ModifierKeyCode::RightHyper => write!(f, "Right Hyper"),
ModifierKeyCode::RightMeta => write!(f, "Right Meta"),
ModifierKeyCode::IsoLevel3Shift => write!(f, "Iso Level 3 Shift"),
ModifierKeyCode::IsoLevel5Shift => write!(f, "Iso Level 5 Shift"),
#[cfg(target_os = "macos")]
ModifierKeyCode::LeftControl => write!(f, "Left Control"),
#[cfg(not(target_os = "macos"))]
ModifierKeyCode::LeftControl => write!(f, "Left Ctrl"),
#[cfg(target_os = "macos")]
ModifierKeyCode::LeftAlt => write!(f, "Left Option"),
#[cfg(not(target_os = "macos"))]
ModifierKeyCode::LeftAlt => write!(f, "Left Alt"),
#[cfg(target_os = "macos")]
ModifierKeyCode::LeftSuper => write!(f, "Left Command"),
#[cfg(target_os = "windows")]
ModifierKeyCode::LeftSuper => write!(f, "Left Windows"),
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
ModifierKeyCode::LeftSuper => write!(f, "Left Super"),
#[cfg(target_os = "macos")]
ModifierKeyCode::RightControl => write!(f, "Right Control"),
#[cfg(not(target_os = "macos"))]
ModifierKeyCode::RightControl => write!(f, "Right Ctrl"),
#[cfg(target_os = "macos")]
ModifierKeyCode::RightAlt => write!(f, "Right Option"),
#[cfg(not(target_os = "macos"))]
ModifierKeyCode::RightAlt => write!(f, "Right Alt"),
#[cfg(target_os = "macos")]
ModifierKeyCode::RightSuper => write!(f, "Right Command"),
#[cfg(target_os = "windows")]
ModifierKeyCode::RightSuper => write!(f, "Right Windows"),
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
ModifierKeyCode::RightSuper => write!(f, "Right Super"),
}
}
}
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
#[cfg_attr(feature = "derive-more", derive(IsVariant))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum KeyCode {
Backspace,
Enter,
Left,
Right,
Up,
Down,
Home,
End,
PageUp,
PageDown,
Tab,
BackTab,
Delete,
Insert,
#[cfg_attr(feature = "derive-more", is_variant(ignore))]
F(u8),
#[cfg_attr(feature = "derive-more", is_variant(ignore))]
Char(char),
Null,
Esc,
CapsLock,
ScrollLock,
NumLock,
PrintScreen,
Pause,
Menu,
KeypadBegin,
#[cfg_attr(feature = "derive-more", is_variant(ignore))]
Media(MediaKeyCode),
#[cfg_attr(feature = "derive-more", is_variant(ignore))]
Modifier(ModifierKeyCode),
}
impl KeyCode {
pub fn is_function_key(&self, n: u8) -> bool {
matches!(self, KeyCode::F(m) if *m == n)
}
pub fn is_char(&self, c: char) -> bool {
matches!(self, KeyCode::Char(m) if *m == c)
}
pub fn as_char(&self) -> Option<char> {
match self {
KeyCode::Char(c) => Some(*c),
_ => None,
}
}
pub fn is_media_key(&self, media: MediaKeyCode) -> bool {
matches!(self, KeyCode::Media(m) if *m == media)
}
pub fn is_modifier(&self, modifier: ModifierKeyCode) -> bool {
matches!(self, KeyCode::Modifier(m) if *m == modifier)
}
}
impl Display for KeyCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
#[cfg(target_os = "macos")]
KeyCode::Backspace => write!(f, "Delete"),
#[cfg(target_os = "macos")]
KeyCode::Delete => write!(f, "Fwd Del"),
#[cfg(not(target_os = "macos"))]
KeyCode::Backspace => write!(f, "Backspace"),
#[cfg(not(target_os = "macos"))]
KeyCode::Delete => write!(f, "Del"),
#[cfg(target_os = "macos")]
KeyCode::Enter => write!(f, "Return"),
#[cfg(not(target_os = "macos"))]
KeyCode::Enter => write!(f, "Enter"),
KeyCode::Left => write!(f, "Left"),
KeyCode::Right => write!(f, "Right"),
KeyCode::Up => write!(f, "Up"),
KeyCode::Down => write!(f, "Down"),
KeyCode::Home => write!(f, "Home"),
KeyCode::End => write!(f, "End"),
KeyCode::PageUp => write!(f, "Page Up"),
KeyCode::PageDown => write!(f, "Page Down"),
KeyCode::Tab => write!(f, "Tab"),
KeyCode::BackTab => write!(f, "Back Tab"),
KeyCode::Insert => write!(f, "Insert"),
KeyCode::F(n) => write!(f, "F{}", n),
KeyCode::Char(c) => match c {
' ' => write!(f, "Space"),
c => write!(f, "{}", c),
},
KeyCode::Null => write!(f, "Null"),
KeyCode::Esc => write!(f, "Esc"),
KeyCode::CapsLock => write!(f, "Caps Lock"),
KeyCode::ScrollLock => write!(f, "Scroll Lock"),
KeyCode::NumLock => write!(f, "Num Lock"),
KeyCode::PrintScreen => write!(f, "Print Screen"),
KeyCode::Pause => write!(f, "Pause"),
KeyCode::Menu => write!(f, "Menu"),
KeyCode::KeypadBegin => write!(f, "Begin"),
KeyCode::Media(media) => write!(f, "{}", media),
KeyCode::Modifier(modifier) => write!(f, "{}", modifier),
}
}
}
#[derive(Debug, PartialOrd, PartialEq, Hash, Clone, Eq)]
pub(crate) enum InternalEvent {
Event(Event),
#[cfg(unix)]
CursorPosition(u16, u16),
#[cfg(unix)]
KeyboardEnhancementFlags(KeyboardEnhancementFlags),
#[cfg(unix)]
PrimaryDeviceAttributes,
}
#[cfg(test)]
mod tests {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use super::*;
use KeyCode::*;
use MediaKeyCode::*;
use ModifierKeyCode::*;
#[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);
}
#[test]
fn keycode_display() {
#[cfg(target_os = "macos")]
{
assert_eq!(format!("{}", Backspace), "Delete");
assert_eq!(format!("{}", Delete), "Fwd Del");
assert_eq!(format!("{}", Enter), "Return");
}
#[cfg(not(target_os = "macos"))]
{
assert_eq!(format!("{}", Backspace), "Backspace");
assert_eq!(format!("{}", Delete), "Del");
assert_eq!(format!("{}", Enter), "Enter");
}
assert_eq!(format!("{}", Left), "Left");
assert_eq!(format!("{}", Right), "Right");
assert_eq!(format!("{}", Up), "Up");
assert_eq!(format!("{}", Down), "Down");
assert_eq!(format!("{}", Home), "Home");
assert_eq!(format!("{}", End), "End");
assert_eq!(format!("{}", PageUp), "Page Up");
assert_eq!(format!("{}", PageDown), "Page Down");
assert_eq!(format!("{}", Tab), "Tab");
assert_eq!(format!("{}", BackTab), "Back Tab");
assert_eq!(format!("{}", Insert), "Insert");
assert_eq!(format!("{}", F(1)), "F1");
assert_eq!(format!("{}", Char('a')), "a");
assert_eq!(format!("{}", Null), "Null");
assert_eq!(format!("{}", Esc), "Esc");
assert_eq!(format!("{}", CapsLock), "Caps Lock");
assert_eq!(format!("{}", ScrollLock), "Scroll Lock");
assert_eq!(format!("{}", NumLock), "Num Lock");
assert_eq!(format!("{}", PrintScreen), "Print Screen");
assert_eq!(format!("{}", KeyCode::Pause), "Pause");
assert_eq!(format!("{}", Menu), "Menu");
assert_eq!(format!("{}", KeypadBegin), "Begin");
}
#[test]
fn media_keycode_display() {
assert_eq!(format!("{}", Media(Play)), "Play");
assert_eq!(format!("{}", Media(MediaKeyCode::Pause)), "Pause");
assert_eq!(format!("{}", Media(PlayPause)), "Play/Pause");
assert_eq!(format!("{}", Media(Reverse)), "Reverse");
assert_eq!(format!("{}", Media(Stop)), "Stop");
assert_eq!(format!("{}", Media(FastForward)), "Fast Forward");
assert_eq!(format!("{}", Media(Rewind)), "Rewind");
assert_eq!(format!("{}", Media(TrackNext)), "Next Track");
assert_eq!(format!("{}", Media(TrackPrevious)), "Previous Track");
assert_eq!(format!("{}", Media(Record)), "Record");
assert_eq!(format!("{}", Media(LowerVolume)), "Lower Volume");
assert_eq!(format!("{}", Media(RaiseVolume)), "Raise Volume");
assert_eq!(format!("{}", Media(MuteVolume)), "Mute Volume");
}
#[test]
fn modifier_keycode_display() {
assert_eq!(format!("{}", Modifier(LeftShift)), "Left Shift");
assert_eq!(format!("{}", Modifier(LeftHyper)), "Left Hyper");
assert_eq!(format!("{}", Modifier(LeftMeta)), "Left Meta");
assert_eq!(format!("{}", Modifier(RightShift)), "Right Shift");
assert_eq!(format!("{}", Modifier(RightHyper)), "Right Hyper");
assert_eq!(format!("{}", Modifier(RightMeta)), "Right Meta");
assert_eq!(format!("{}", Modifier(IsoLevel3Shift)), "Iso Level 3 Shift");
assert_eq!(format!("{}", Modifier(IsoLevel5Shift)), "Iso Level 5 Shift");
}
#[cfg(target_os = "macos")]
#[test]
fn modifier_keycode_display_macos() {
assert_eq!(format!("{}", Modifier(LeftControl)), "Left Control");
assert_eq!(format!("{}", Modifier(LeftAlt)), "Left Option");
assert_eq!(format!("{}", Modifier(LeftSuper)), "Left Command");
assert_eq!(format!("{}", Modifier(RightControl)), "Right Control");
assert_eq!(format!("{}", Modifier(RightAlt)), "Right Option");
assert_eq!(format!("{}", Modifier(RightSuper)), "Right Command");
}
#[cfg(target_os = "windows")]
#[test]
fn modifier_keycode_display_windows() {
assert_eq!(format!("{}", Modifier(LeftControl)), "Left Ctrl");
assert_eq!(format!("{}", Modifier(LeftAlt)), "Left Alt");
assert_eq!(format!("{}", Modifier(LeftSuper)), "Left Windows");
assert_eq!(format!("{}", Modifier(RightControl)), "Right Ctrl");
assert_eq!(format!("{}", Modifier(RightAlt)), "Right Alt");
assert_eq!(format!("{}", Modifier(RightSuper)), "Right Windows");
}
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
#[test]
fn modifier_keycode_display_other() {
assert_eq!(format!("{}", Modifier(LeftControl)), "Left Ctrl");
assert_eq!(format!("{}", Modifier(LeftAlt)), "Left Alt");
assert_eq!(format!("{}", Modifier(LeftSuper)), "Left Super");
assert_eq!(format!("{}", Modifier(RightControl)), "Right Ctrl");
assert_eq!(format!("{}", Modifier(RightAlt)), "Right Alt");
assert_eq!(format!("{}", Modifier(RightSuper)), "Right Super");
}
#[test]
fn key_modifiers_display() {
let modifiers = KeyModifiers::SHIFT | KeyModifiers::CONTROL | KeyModifiers::ALT;
#[cfg(target_os = "macos")]
assert_eq!(modifiers.to_string(), "Shift+Control+Option");
#[cfg(target_os = "windows")]
assert_eq!(modifiers.to_string(), "Shift+Ctrl+Alt");
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
assert_eq!(modifiers.to_string(), "Shift+Control+Alt");
}
const ESC_PRESSED: KeyEvent =
KeyEvent::new_with_kind(KeyCode::Esc, KeyModifiers::empty(), KeyEventKind::Press);
const ESC_RELEASED: KeyEvent =
KeyEvent::new_with_kind(KeyCode::Esc, KeyModifiers::empty(), KeyEventKind::Release);
const ESC_REPEAT: KeyEvent =
KeyEvent::new_with_kind(KeyCode::Esc, KeyModifiers::empty(), KeyEventKind::Repeat);
const MOUSE_CLICK: MouseEvent = MouseEvent {
kind: MouseEventKind::Down(MouseButton::Left),
column: 1,
row: 1,
modifiers: KeyModifiers::empty(),
};
#[cfg(feature = "derive-more")]
#[test]
fn event_is() {
let event = Event::FocusGained;
assert!(event.is_focus_gained());
assert!(event.is_focus_gained());
assert!(!event.is_key());
let event = Event::FocusLost;
assert!(event.is_focus_lost());
assert!(!event.is_focus_gained());
assert!(!event.is_key());
let event = Event::Resize(1, 1);
assert!(event.is_resize());
assert!(!event.is_key());
let event = Event::Key(ESC_PRESSED);
assert!(event.is_key());
assert!(event.is_key_press());
assert!(!event.is_key_release());
assert!(!event.is_key_repeat());
assert!(!event.is_focus_gained());
let event = Event::Key(ESC_RELEASED);
assert!(event.is_key());
assert!(!event.is_key_press());
assert!(event.is_key_release());
assert!(!event.is_key_repeat());
assert!(!event.is_focus_gained());
let event = Event::Key(ESC_REPEAT);
assert!(event.is_key());
assert!(!event.is_key_press());
assert!(!event.is_key_release());
assert!(event.is_key_repeat());
assert!(!event.is_focus_gained());
let event = Event::Mouse(MOUSE_CLICK);
assert!(event.is_mouse());
assert!(!event.is_key());
#[cfg(feature = "bracketed-paste")]
{
let event = Event::Paste("".to_string());
assert!(event.is_paste());
assert!(!event.is_key());
}
}
#[test]
fn event_as() {
let event = Event::FocusGained;
assert_eq!(event.as_key_event(), None);
let event = Event::Key(ESC_PRESSED);
assert_eq!(event.as_key_event(), Some(ESC_PRESSED));
assert_eq!(event.as_key_press_event(), Some(ESC_PRESSED));
assert_eq!(event.as_key_release_event(), None);
assert_eq!(event.as_key_repeat_event(), None);
assert_eq!(event.as_resize_event(), None);
let event = Event::Key(ESC_RELEASED);
assert_eq!(event.as_key_event(), Some(ESC_RELEASED));
assert_eq!(event.as_key_release_event(), Some(ESC_RELEASED));
assert_eq!(event.as_key_press_event(), None);
assert_eq!(event.as_key_repeat_event(), None);
assert_eq!(event.as_resize_event(), None);
let event = Event::Key(ESC_REPEAT);
assert_eq!(event.as_key_event(), Some(ESC_REPEAT));
assert_eq!(event.as_key_repeat_event(), Some(ESC_REPEAT));
assert_eq!(event.as_key_press_event(), None);
assert_eq!(event.as_key_release_event(), None);
assert_eq!(event.as_resize_event(), None);
let event = Event::Resize(1, 1);
assert_eq!(event.as_resize_event(), Some((1, 1)));
assert_eq!(event.as_key_event(), None);
let event = Event::Mouse(MOUSE_CLICK);
assert_eq!(event.as_mouse_event(), Some(MOUSE_CLICK));
assert_eq!(event.as_key_event(), None);
#[cfg(feature = "bracketed-paste")]
{
let event = Event::Paste("".to_string());
assert_eq!(event.as_paste_event(), Some(""));
assert_eq!(event.as_key_event(), None);
}
}
}