use std::fmt::Display;
use self::keycode::Keycode;
use self::keysym::{Keysym, SYM_NONE};
pub mod keycode;
pub mod keymap;
pub mod keysym;
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
#[repr(u32)]
#[non_exhaustive]
pub enum KeyState {
Shift = 1 << 0,
CapsLock = 1 << 1,
Control = 1 << 2,
Alt = 1 << 3,
NumLock = 1 << 4,
Super = 1 << 6,
Release = 1 << 30,
}
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
pub struct KeyboardEvent {
pub code: Keycode,
pub ksym: Keysym,
pub state: u32,
}
impl KeyboardEvent {
pub const fn builder() -> KeyboardEventBuilder {
KeyboardEventBuilder {
evt: KeyboardEvent {
code: Keycode(0),
ksym: Keysym(0),
state: 0,
},
}
}
pub fn is_invalid(&self) -> bool {
self.code.0 == 0 && self.ksym == SYM_NONE && self.state == 0
}
pub fn is_state_on(&self, m: KeyState) -> bool {
match m {
KeyState::Shift => self.is_flag_on(KeyState::Shift as u32),
KeyState::Control => self.is_flag_on(KeyState::Control as u32),
KeyState::Alt => self.is_flag_on(KeyState::Alt as u32),
KeyState::Super => self.is_flag_on(KeyState::Super as u32),
KeyState::CapsLock => self.is_flag_on(KeyState::CapsLock as u32),
KeyState::NumLock => self.is_flag_on(KeyState::NumLock as u32),
KeyState::Release => self.is_flag_on(KeyState::Release as u32),
}
}
fn is_flag_on(&self, mask: u32) -> bool {
self.state & mask == mask
}
pub fn has_modifiers(&self) -> bool {
self.is_state_on(KeyState::Shift)
|| self.is_state_on(KeyState::Control)
|| self.is_state_on(KeyState::Alt)
|| self.is_state_on(KeyState::Super)
}
}
impl Display for KeyboardEvent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "#KeyboardEvent(")?;
write!(f, ":code {}", self.code.0)?;
write!(f, " :ksym {}", self.ksym.0)?;
if self.ksym.is_unicode() {
write!(f, " :char '{}'", self.ksym.to_unicode())?;
}
if self.state != 0 {
write!(f, " :state '")?;
if self.is_state_on(KeyState::Control) {
write!(f, "c")?;
}
if self.is_state_on(KeyState::Shift) {
write!(f, "s")?;
}
if self.is_state_on(KeyState::Alt) {
write!(f, "a")?;
}
if self.is_state_on(KeyState::Super) {
write!(f, "S")?;
}
if self.is_state_on(KeyState::CapsLock) {
write!(f, "C")?;
}
if self.is_state_on(KeyState::NumLock) {
write!(f, "N")?;
}
if self.is_state_on(KeyState::Release) {
write!(f, "R")?;
}
}
write!(f, ")")?;
Ok(())
}
}
#[derive(Clone, Copy, Debug)]
pub struct KeyboardEventBuilder {
evt: KeyboardEvent,
}
impl KeyboardEventBuilder {
pub const fn code(&mut self, code: Keycode) -> &mut KeyboardEventBuilder {
self.evt.code = code;
self
}
pub const fn ksym(&mut self, key: Keysym) -> &mut KeyboardEventBuilder {
self.evt.ksym = key;
self
}
pub const fn shift(&mut self) -> &mut KeyboardEventBuilder {
self.shift_if(true)
}
pub const fn shift_if(&mut self, shift: bool) -> &mut KeyboardEventBuilder {
if shift {
self.evt.state |= KeyState::Shift as u32;
}
self
}
pub const fn caps_lock(&mut self) -> &mut KeyboardEventBuilder {
self.caps_lock_if(true)
}
pub const fn caps_lock_if(&mut self, caps_lock: bool) -> &mut KeyboardEventBuilder {
if caps_lock {
self.evt.state |= KeyState::CapsLock as u32;
}
self
}
pub const fn control(&mut self) -> &mut KeyboardEventBuilder {
self.control_if(true)
}
pub const fn control_if(&mut self, control: bool) -> &mut KeyboardEventBuilder {
if control {
self.evt.state |= KeyState::Control as u32;
}
self
}
pub const fn alt_if(&mut self, alt: bool) -> &mut KeyboardEventBuilder {
if alt {
self.evt.state |= KeyState::Alt as u32;
}
self
}
pub const fn num_lock_if(&mut self, num_lock: bool) -> &mut KeyboardEventBuilder {
if num_lock {
self.evt.state |= KeyState::NumLock as u32;
}
self
}
pub const fn super_if(&mut self, supa: bool) -> &mut KeyboardEventBuilder {
if supa {
self.evt.state |= KeyState::Super as u32;
}
self
}
pub const fn release(&mut self) -> &mut KeyboardEventBuilder {
self.release_if(true)
}
pub const fn release_if(&mut self, release: bool) -> &mut KeyboardEventBuilder {
if release {
self.evt.state |= KeyState::Release as u32;
}
self
}
pub const fn build(&mut self) -> KeyboardEvent {
self.evt
}
}
#[cfg(test)]
mod tests {
use super::KeyboardEvent;
use super::keycode;
use super::keysym;
use crate::input::KeyState;
#[test]
fn keyboard_event_builder() {
let control_down = true;
let caps_lock = false;
let evt = KeyboardEvent::builder()
.code(keycode::KEY_A)
.ksym(keysym::SYM_LOWER_A)
.shift()
.control_if(control_down)
.caps_lock_if(caps_lock)
.num_lock_if(false)
.alt_if(false)
.super_if(false)
.release_if(false)
.build();
assert_eq!(keycode::KEY_A, evt.code);
assert_eq!(keysym::SYM_LOWER_A, evt.ksym);
assert!(evt.is_state_on(KeyState::Control));
assert!(evt.is_state_on(KeyState::Shift));
assert!(!evt.is_state_on(KeyState::CapsLock));
}
}