use bitflags::bitflags;
#[cfg(feature = "serialize")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Eq, PartialEq, Clone, PartialOrd)]
pub enum Event<UserEvent>
where
UserEvent: Eq + PartialEq + Clone,
{
Keyboard(KeyEvent),
Mouse(MouseEvent),
WindowResize(u16, u16),
FocusGained,
FocusLost,
Paste(String),
Tick,
None,
User(UserEvent),
}
impl<UserEvent> Event<UserEvent>
where
UserEvent: Eq + PartialEq + Clone,
{
pub fn as_keyboard(&self) -> Option<&KeyEvent> {
if let Event::Keyboard(k) = self {
Some(k)
} else {
None
}
}
pub fn as_mouse(&self) -> Option<&MouseEvent> {
if let Event::Mouse(m) = self {
Some(m)
} else {
None
}
}
pub(crate) fn as_window_resize(&self) -> bool {
matches!(self, Self::WindowResize(_, _))
}
pub(crate) fn as_tick(&self) -> bool {
matches!(self, Self::Tick)
}
pub fn as_user(&self) -> Option<&UserEvent> {
if let Event::User(u) = self {
Some(u)
} else {
None
}
}
}
#[derive(Debug, Eq, PartialEq, Copy, Clone, PartialOrd)]
pub enum NoUserEvent {}
#[derive(Debug, Eq, PartialEq, Copy, Clone, PartialOrd, Hash)]
#[cfg_attr(
feature = "serialize",
derive(Deserialize, Serialize),
serde(tag = "type")
)]
pub struct KeyEvent {
pub code: Key,
pub modifiers: KeyModifiers,
}
#[derive(Debug, Eq, PartialEq, Copy, Clone, PartialOrd, Hash)]
#[cfg_attr(
feature = "serialize",
derive(Deserialize, Serialize),
serde(tag = "type", content = "args")
)]
pub enum Key {
Backspace,
Enter,
Left,
Right,
Up,
Down,
Home,
End,
PageUp,
PageDown,
Tab,
BackTab,
Delete,
Insert,
Function(u8),
Char(char),
Null,
CapsLock,
ScrollLock,
NumLock,
PrintScreen,
Pause,
Menu,
KeypadBegin,
Media(MediaKeyCode),
Esc,
ShiftLeft,
AltLeft,
CtrlLeft,
ShiftRight,
AltRight,
CtrlRight,
ShiftUp,
AltUp,
CtrlUp,
ShiftDown,
AltDown,
CtrlDown,
CtrlHome,
CtrlEnd,
}
#[derive(Clone, Copy, Hash, Eq, PartialEq, Debug, PartialOrd, Ord)]
#[cfg_attr(feature = "serialize", derive(Deserialize, Serialize))]
pub struct KeyModifiers(u8);
bitflags! {
impl KeyModifiers: u8 {
const NONE = 0b0000_0000;
const SHIFT = 0b0000_0001;
const CONTROL = 0b0000_0010;
const ALT = 0b0000_0100;
}
}
impl KeyEvent {
pub fn new(code: Key, modifiers: KeyModifiers) -> Self {
Self { code, modifiers }
}
}
impl From<Key> for KeyEvent {
fn from(k: Key) -> Self {
Self::new(k, KeyModifiers::NONE)
}
}
#[derive(Debug, Eq, PartialEq, Copy, Clone, PartialOrd, Hash)]
#[cfg_attr(
feature = "serialize",
derive(Deserialize, Serialize),
serde(tag = "type", content = "args")
)]
pub enum MediaKeyCode {
Play,
Pause,
PlayPause,
Reverse,
Stop,
FastForward,
Rewind,
TrackNext,
TrackPrevious,
Record,
LowerVolume,
RaiseVolume,
MuteVolume,
}
#[derive(Debug, Eq, PartialEq, Copy, Clone, PartialOrd, Hash)]
#[cfg_attr(
feature = "serialize",
derive(Deserialize, Serialize),
serde(tag = "type")
)]
pub struct MouseEvent {
pub kind: MouseEventKind,
pub modifiers: KeyModifiers,
pub column: u16,
pub row: u16,
}
#[derive(Debug, Eq, PartialEq, Copy, Clone, PartialOrd, Hash)]
#[cfg_attr(
feature = "serialize",
derive(Deserialize, Serialize),
serde(tag = "type", content = "args")
)]
pub enum MouseEventKind {
Down(MouseButton),
Up(MouseButton),
Drag(MouseButton),
Moved,
ScrollDown,
ScrollUp,
ScrollLeft,
ScrollRight,
}
#[derive(Debug, Eq, PartialEq, Copy, Clone, PartialOrd, Hash)]
#[cfg_attr(
feature = "serialize",
derive(Deserialize, Serialize),
serde(tag = "type", content = "args")
)]
pub enum MouseButton {
Left,
Right,
Middle,
}
#[cfg(test)]
mod test {
use pretty_assertions::assert_eq;
use super::*;
use crate::mock::MockEvent;
#[test]
fn new_key_event() {
let k = KeyEvent::new(Key::Down, KeyModifiers::CONTROL);
assert_eq!(k.code, Key::Down);
assert_eq!(k.modifiers, KeyModifiers::CONTROL);
}
#[test]
fn key_event_from_key() {
let k = KeyEvent::from(Key::Up);
assert_eq!(k.code, Key::Up);
assert_eq!(k.modifiers, KeyModifiers::NONE);
}
#[test]
fn check_events() {
let e: Event<MockEvent> = Event::Keyboard(KeyEvent::new(Key::Down, KeyModifiers::CONTROL));
assert!(e.as_keyboard().is_some());
assert_eq!(e.as_window_resize(), false);
assert_eq!(e.as_tick(), false);
assert_eq!(e.as_mouse().is_some(), false);
assert!(e.as_user().is_none());
let e: Event<MockEvent> = Event::WindowResize(0, 24);
assert!(e.as_window_resize());
assert!(e.as_keyboard().is_none());
let e: Event<MockEvent> = Event::Tick;
assert!(e.as_tick());
let e: Event<MockEvent> = Event::User(MockEvent::Bar);
assert_eq!(e.as_user().unwrap(), &MockEvent::Bar);
let e: Event<MockEvent> = Event::Mouse(MouseEvent {
kind: MouseEventKind::Moved,
modifiers: KeyModifiers::NONE,
column: 0,
row: 0,
});
assert!(e.as_mouse().is_some());
assert_eq!(e.as_keyboard().is_some(), false);
assert_eq!(e.as_tick(), false);
assert_eq!(e.as_window_resize(), false);
}
#[cfg(feature = "serialize")]
use std::fs::File;
#[cfg(feature = "serialize")]
use std::io::{Read, Write};
#[cfg(feature = "serialize")]
use serde::de::DeserializeOwned;
#[cfg(feature = "serialize")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "serialize")]
use tempfile::NamedTempFile;
#[cfg(feature = "serialize")]
fn deserialize<R, S>(mut readable: R) -> S
where
R: Read,
S: DeserializeOwned + Sized + std::fmt::Debug,
{
let mut data: String = String::new();
if let Err(err) = readable.read_to_string(&mut data) {
panic!("Error: {}", err);
}
match toml::de::from_str(data.as_str()) {
Ok(deserialized) => deserialized,
Err(err) => panic!("Error: {}", err),
}
}
#[cfg(feature = "serialize")]
fn serialize<S, W>(serializable: &S, mut writable: W)
where
S: Serialize + Sized,
W: Write,
{
let data: String = match toml::ser::to_string(serializable) {
Ok(dt) => dt,
Err(err) => {
panic!("Error: {}", err);
}
};
if let Err(err) = writable.write_all(data.as_bytes()) {
panic!("Error: {}", err)
}
}
#[cfg(feature = "serialize")]
#[derive(Debug, PartialEq, Deserialize, Serialize)]
struct KeyBindings {
pub quit: KeyEvent,
pub open: KeyEvent,
}
#[cfg(feature = "serialize")]
impl KeyBindings {
pub fn new(quit: KeyEvent, open: KeyEvent) -> Self {
Self { quit, open }
}
}
#[test]
#[cfg(feature = "serialize")]
fn should_serialize_key_bindings() {
let temp = NamedTempFile::new().expect("Failed to open tempfile");
let keys = KeyBindings::new(
KeyEvent::from(Key::Esc),
KeyEvent::new(Key::Char('o'), KeyModifiers::CONTROL),
);
let mut config = File::create(temp.path()).expect("Failed to open file for write");
serialize(&keys, &mut config);
let mut readable = File::open(temp.path()).expect("Failed to open file for read");
let r_keys: KeyBindings = deserialize(&mut readable);
assert_eq!(keys, r_keys);
}
}