use crate::{
core::{data_types::Point, manager::WindowManager, xconnection::Xid},
PenroseError, Result,
};
#[cfg(feature = "keysyms")]
use penrose_keysyms::XKeySym;
use std::{collections::HashMap, convert::TryFrom};
use strum::EnumIter;
pub type KeyEventHandler<X> = Box<dyn FnMut(&mut WindowManager<X>) -> Result<()>>;
pub type MouseEventHandler<X> = Box<dyn FnMut(&mut WindowManager<X>, &MouseEvent) -> Result<()>>;
pub type KeyBindings<X> = HashMap<KeyCode, KeyEventHandler<X>>;
pub type MouseBindings<X> = HashMap<(MouseEventKind, MouseState), MouseEventHandler<X>>;
pub(crate) type CodeMap = HashMap<String, u8>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum KeyPress {
Utf8(String),
Return,
Escape,
Tab,
Backspace,
Delete,
PageUp,
PageDown,
Up,
Down,
Left,
Right,
}
#[cfg(feature = "keysyms")]
impl TryFrom<XKeySym> for KeyPress {
type Error = PenroseError;
fn try_from(s: XKeySym) -> std::result::Result<KeyPress, PenroseError> {
Ok(match s {
XKeySym::XK_Return | XKeySym::XK_KP_Enter | XKeySym::XK_ISO_Enter => KeyPress::Return,
XKeySym::XK_Escape => KeyPress::Escape,
XKeySym::XK_Tab | XKeySym::XK_ISO_Left_Tab | XKeySym::XK_KP_Tab => KeyPress::Tab,
XKeySym::XK_BackSpace => KeyPress::Backspace,
XKeySym::XK_Delete | XKeySym::XK_KP_Delete => KeyPress::Delete,
XKeySym::XK_Page_Up | XKeySym::XK_KP_Page_Up => KeyPress::PageUp,
XKeySym::XK_Page_Down | XKeySym::XK_KP_Page_Down => KeyPress::PageDown,
XKeySym::XK_Up | XKeySym::XK_KP_Up => KeyPress::Up,
XKeySym::XK_Down | XKeySym::XK_KP_Down => KeyPress::Down,
XKeySym::XK_Left | XKeySym::XK_KP_Left => KeyPress::Left,
XKeySym::XK_Right | XKeySym::XK_KP_Right => KeyPress::Right,
s => KeyPress::Utf8(s.as_utf8_string()?),
})
}
}
pub type KeyCodeMask = u16;
pub type KeyCodeValue = u8;
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct KeyCode {
pub mask: KeyCodeMask,
pub code: KeyCodeValue,
}
impl KeyCode {
pub fn ignoring_modifier(&self, mask: KeyCodeMask) -> KeyCode {
KeyCode {
mask: self.mask & !mask,
code: self.code,
}
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum MouseButton {
Left,
Middle,
Right,
ScrollUp,
ScrollDown,
}
impl From<MouseButton> for u8 {
fn from(b: MouseButton) -> u8 {
match b {
MouseButton::Left => 1,
MouseButton::Middle => 2,
MouseButton::Right => 3,
MouseButton::ScrollUp => 4,
MouseButton::ScrollDown => 5,
}
}
}
#[derive(Debug, EnumIter, PartialEq, Eq, Hash, Clone, Copy, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum ModifierKey {
Ctrl,
Alt,
Shift,
Meta,
}
impl TryFrom<&str> for ModifierKey {
type Error = PenroseError;
fn try_from(s: &str) -> Result<Self> {
match s {
"C" => Ok(Self::Ctrl),
"A" => Ok(Self::Alt),
"S" => Ok(Self::Shift),
"M" => Ok(Self::Meta),
_ => Err(PenroseError::UnknownModifier(s.into())),
}
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MouseState {
pub button: MouseButton,
pub modifiers: Vec<ModifierKey>,
}
impl MouseState {
pub fn new(button: MouseButton, mut modifiers: Vec<ModifierKey>) -> Self {
modifiers.sort();
Self { button, modifiers }
}
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum MouseEventKind {
Press,
Release,
Motion,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MouseEvent {
pub id: Xid,
pub rpt: Point,
pub wpt: Point,
pub state: MouseState,
pub kind: MouseEventKind,
}
impl MouseEvent {
pub fn new(
id: Xid,
rx: i16,
ry: i16,
ex: i16,
ey: i16,
state: MouseState,
kind: MouseEventKind,
) -> Self {
MouseEvent {
id,
rpt: Point::new(rx as u32, ry as u32),
wpt: Point::new(ex as u32, ey as u32),
state,
kind,
}
}
}