use std::fmt;
use std::fmt::Formatter;
use std::fmt::{Debug, Display};
use serde::de::Error;
use serde::{Deserialize, Deserializer};
use xkbcommon::xkb;
use xkbcommon::xkb::{keysym_from_name, keysym_get_name, keysyms, Keysym};
use crate::error::CskkError;
#[allow(unused_imports)]
use std::ops::BitAndAssign;
use std::str::FromStr;
bitflags! {
pub(crate) struct SkkKeyModifier: u32 {
const NONE = 0;
const SHIFT = 1;
const CAPS_LOCK = 1 << 1;
const CONTROL = 1 << 2;
const MOD1 = 1 << 3;
const ALT = 1 << 3; const MOD2 = 1 << 4;
const NUM_LOCK = 1 << 4; const MOD3 = 1 << 5;
const HYPER = 1 << 5; const MOD4 = 1 << 6;
const SUPER = 1 << 6; const MOD5 = 1 << 7;
const MOUSE_PRESSED = 1 << 8;
const L_SHIFT = 1 << 22;
const R_SHIFT = 1 << 23;
const USLEEP = 1 << 24;
const SUPER2 = 1 << 26;
const HYPER2 = 1 << 27;
const META = 1 << 28;
const RELEASE = 1 << 30;
const REPEAT = 1 << 31;
const NON_DUMMY_MASK = Self::SHIFT.bits | Self::CAPS_LOCK.bits | Self::CONTROL.bits | Self::ALT.bits
| Self::NUM_LOCK.bits | Self::HYPER.bits | Self::SUPER.bits | Self::MOUSE_PRESSED.bits | Self::SUPER2.bits | Self::HYPER2.bits
| Self::META.bits | Self::REPEAT.bits;
}
}
pub type KeyEventSeq = Vec<CskkKeyEvent>;
#[derive(Clone, Hash, PartialEq, Eq)]
pub struct CskkKeyEvent {
symbol: xkb::Keysym,
modifiers: SkkKeyModifier,
}
impl CskkKeyEvent {
#[cfg(test)]
pub(crate) fn from_keysym_strict(keysym: xkb::Keysym, modifier: SkkKeyModifier) -> Self {
Self {
symbol: keysym,
modifiers: modifier,
}
}
#[cfg(feature = "capi")]
pub(crate) fn from_fcitx_keyevent(keysym: u32, raw_modifier: u32, is_release: bool) -> Self {
let mut modifiers: SkkKeyModifier = SkkKeyModifier::from_bits_truncate(raw_modifier);
modifiers.bitand_assign(SkkKeyModifier::NON_DUMMY_MASK);
if is_release {
modifiers.set(SkkKeyModifier::RELEASE, true);
}
Self {
symbol: keysym,
modifiers,
}
}
pub fn from_keysym_with_flags(
keysym: Keysym,
ctrl_mod: bool,
shift_mod: bool,
alt_mod: bool,
) -> Self {
let mut modifiers = SkkKeyModifier::NONE;
modifiers.set(SkkKeyModifier::CONTROL, ctrl_mod);
modifiers.set(SkkKeyModifier::SHIFT, shift_mod);
modifiers.set(SkkKeyModifier::ALT, alt_mod);
Self {
symbol: keysym,
modifiers,
}
}
pub(crate) fn keysyms_from_str(string: &str) -> Vec<Keysym> {
let mut result = vec![];
let words = string.split(' ');
for word in words {
let word = word.trim();
let word_keysym = keysym_from_name(word, xkb::KEYSYM_NO_FLAGS);
if keysyms::KEY_NoSymbol == word_keysym {
for char in word.chars() {
let char_keysym = keysym_from_name(&char.to_string(), xkb::KEYSYM_NO_FLAGS);
if keysyms::KEY_NoSymbol != char_keysym {
result.push(char_keysym);
}
}
} else {
result.push(word_keysym);
}
}
result
}
pub(crate) fn is_ascii_inputtable(&self) -> bool {
xkb::keysyms::KEY_space <= self.symbol && self.symbol <= xkb::keysyms::KEY_asciitilde
}
pub(crate) fn is_upper(&self) -> bool {
xkb::keysyms::KEY_A <= self.symbol && self.symbol <= xkb::keysyms::KEY_Z
}
pub(crate) fn to_lower(&self) -> Self {
let mut retval = self.clone();
if retval.is_upper() {
retval.symbol += 0x0020;
}
retval
}
pub(crate) fn is_modifierless_input(&self) -> bool {
self.modifiers.difference(SkkKeyModifier::SHIFT).is_empty()
}
pub fn from_string_representation(key: &str) -> Result<CskkKeyEvent, CskkError> {
Self::from_str(key)
}
pub(crate) fn get_symbol_char(&self) -> Option<char> {
xkb::keysym_to_utf8(self.symbol).chars().next()
}
pub(crate) fn get_modifier(&self) -> SkkKeyModifier {
self.modifiers
}
pub(crate) fn get_modifier_mut(&mut self) -> &mut SkkKeyModifier {
&mut self.modifiers
}
pub(crate) fn get_symbol(&self) -> xkb::Keysym {
self.symbol
}
pub fn deserialize_seq(from: &str) -> Result<KeyEventSeq, CskkError> {
CskkKeyEvent::deserialize_seq_inner(from, Vec::new())
}
fn deserialize_seq_inner(
keys: &str,
mut current: Vec<CskkKeyEvent>,
) -> Result<KeyEventSeq, CskkError> {
let keys = keys.trim();
if keys.is_empty() {
return Ok(current);
}
match CskkKeyEvent::next_tok(keys) {
Some(tok) => {
let left = &keys[tok.len()..];
match CskkKeyEvent::from_string_representation(tok) {
Ok(keyevent) => {
current.push(keyevent);
CskkKeyEvent::deserialize_seq_inner(left, current)
}
Err(e) => Err(e),
}
}
_ => Err(CskkError::Error(format!("Syntax error. keys: {}", keys))),
}
}
fn next_tok(keys: &str) -> Option<&str> {
if keys.starts_with('(') {
let len = keys.find(')');
len.map(|x| &keys[0..=x])
} else {
let len = keys.find(' ');
match len {
Some(x) => Some(&keys[0..x]),
_ => Some(keys),
}
}
}
}
impl FromStr for CskkKeyEvent {
type Err = CskkError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut modifier: SkkKeyModifier = SkkKeyModifier::NONE;
let mut keysym: xkb::Keysym = keysyms::KEY_VoidSymbol;
let key = s.trim();
if key.starts_with('(') && key.ends_with(')') {
let words = key.trim_start_matches('(').trim_end_matches(')').split(' ');
for word in words {
match word {
"control" => {
modifier.set(SkkKeyModifier::CONTROL, true);
}
"meta" => {
modifier.set(SkkKeyModifier::META, true);
}
"alt" => {
modifier.set(SkkKeyModifier::MOD1, true);
}
"lshift" => {
modifier.set(SkkKeyModifier::L_SHIFT, true);
modifier.set(SkkKeyModifier::SHIFT, true);
}
"rshift" => {
modifier.set(SkkKeyModifier::R_SHIFT, true);
modifier.set(SkkKeyModifier::SHIFT, true);
}
"shift" => {
modifier.set(SkkKeyModifier::SHIFT, true);
}
_ => {
keysym = keysym_from_name(word, xkb::KEYSYM_NO_FLAGS);
}
}
}
} else {
let keyname: &str = if key.len() > 2 {
match &key[0..2] {
"C-" => {
modifier.set(SkkKeyModifier::CONTROL, true);
&key[2..]
}
"M-" => {
modifier.set(SkkKeyModifier::META, true);
&key[2..]
}
"A-" => {
modifier.set(SkkKeyModifier::MOD1, true);
&key[2..]
}
"G-" => {
modifier.set(SkkKeyModifier::MOD5, true);
&key[2..]
}
_ => key,
}
} else {
key
};
keysym = keysym_from_name(keyname, xkb::KEYSYM_NO_FLAGS);
}
if keysym == xkb::keysyms::KEY_VoidSymbol {
Err(CskkError::ParseError("No str checked".to_owned()))
} else if keysym == xkb::keysyms::KEY_NoSymbol {
Err(CskkError::ParseError(format!("Not a key symbol: {}", s)))
} else {
Ok(CskkKeyEvent {
modifiers: modifier,
symbol: keysym,
})
}
}
}
impl Display for CskkKeyEvent {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
write!(
formatter,
"{}",
xkb::keysym_to_utf8(self.symbol).trim_end_matches('\u{0}')
)
}
}
impl Debug for CskkKeyEvent {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let name = keysym_get_name(self.symbol);
f.debug_struct("CskkKeyEvent")
.field("symbol", &self.symbol)
.field("key_name", &name)
.field("modifiers", &self.modifiers)
.finish()
}
}
impl<'de> Deserialize<'de> for CskkKeyEvent {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s: &str = Deserialize::deserialize(deserializer)?;
CskkKeyEvent::from_str(s).map_err(D::Error::custom)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn keyevent_from_str() {
let a = CskkKeyEvent::from_string_representation("a").unwrap();
assert_eq!(a.symbol, keysyms::KEY_a, "equals small a");
assert_eq!(a.modifiers, SkkKeyModifier::NONE, "No modifier for a");
let spacea = CskkKeyEvent::from_string_representation(" a").unwrap();
assert_eq!(spacea.symbol, keysyms::KEY_a, "equals small a");
assert_eq!(spacea.modifiers, SkkKeyModifier::NONE, "No modifier for a");
let b = CskkKeyEvent::from_string_representation("B").unwrap();
assert_eq!(b.symbol, keysyms::KEY_B, "equals large B");
assert_eq!(b.modifiers, SkkKeyModifier::NONE, "No modifier for B");
let control_b = CskkKeyEvent::from_string_representation("(control b)").unwrap();
let control_modifier: SkkKeyModifier = SkkKeyModifier::CONTROL;
assert_eq!(control_b.symbol, keysyms::KEY_b, "equals small b");
assert_eq!(
control_b.modifiers, control_modifier,
"long modifier control"
);
let not_u = CskkKeyEvent::from_string_representation("LATIN SMALL LETTER U WITH ACUTE");
assert!(not_u.is_err());
let u = CskkKeyEvent::from_string_representation("uacute").unwrap();
assert_eq!(u.symbol, keysyms::KEY_uacute, "latin small u acute");
let short_ctrl_a = CskkKeyEvent::from_string_representation("C-a").unwrap();
assert_eq!(short_ctrl_a.symbol, keysyms::KEY_a, "C-a works");
assert_eq!(short_ctrl_a.modifiers, control_modifier, "C-a works");
let meta_left = CskkKeyEvent::from_string_representation("M-Left").unwrap();
let meta_modifier: SkkKeyModifier = SkkKeyModifier::META;
assert_eq!(meta_left.symbol, keysyms::KEY_Left);
assert_eq!(meta_left.modifiers, meta_modifier);
let space = CskkKeyEvent::from_string_representation("space").unwrap();
assert_eq!(space.symbol, keysyms::KEY_space);
let enter = CskkKeyEvent::from_string_representation("Return").unwrap();
assert_eq!(enter.symbol, keysyms::KEY_Return);
let period = CskkKeyEvent::from_string_representation("period").unwrap();
assert_eq!(period.symbol, keysyms::KEY_period);
}
#[test]
fn keyevent_to_string() {
let a = CskkKeyEvent::from_string_representation("a").unwrap();
assert_eq!("a", a.to_string());
}
#[test]
fn deserialize_seq() {
let result = CskkKeyEvent::deserialize_seq("a b c").unwrap();
assert_eq!(
result.get(0).unwrap(),
&CskkKeyEvent::from_string_representation("a").unwrap()
);
assert_eq!(
result.get(1).unwrap(),
&CskkKeyEvent::from_string_representation("b").unwrap()
);
assert_eq!(
result.get(2).unwrap(),
&CskkKeyEvent::from_string_representation("c").unwrap()
);
}
#[test]
fn from_keysym() {
let modifier = SkkKeyModifier::L_SHIFT;
let result = CskkKeyEvent::from_keysym_strict(keysyms::KEY_s, modifier);
assert_eq!(result.symbol, keysyms::KEY_s);
assert_eq!(result.modifiers, modifier);
}
#[test]
fn get_symbol_char() {
let key_event = CskkKeyEvent::from_keysym_strict(keysyms::KEY_0, SkkKeyModifier::NONE);
assert_eq!('0', key_event.get_symbol_char().unwrap());
let key_event = CskkKeyEvent::from_keysym_strict(keysyms::KEY_C, SkkKeyModifier::NONE);
assert_eq!('C', key_event.get_symbol_char().unwrap());
let key_event =
CskkKeyEvent::from_keysym_strict(keysyms::KEY_BackSpace, SkkKeyModifier::NONE);
assert_eq!('\u{8}', key_event.get_symbol_char().unwrap());
}
#[test]
fn get_symbol_char_no_display() {
let key_event = CskkKeyEvent::from_keysym_strict(keysyms::KEY_Home, SkkKeyModifier::NONE);
assert_eq!(None, key_event.get_symbol_char());
}
#[test]
fn keysyms_from_string() {
assert_eq!(
vec![keysyms::KEY_space],
CskkKeyEvent::keysyms_from_str("space 無視")
);
assert_eq!(
vec![keysyms::KEY_l, keysyms::KEY_k, keysyms::KEY_Shift_L],
CskkKeyEvent::keysyms_from_str("lk Shift_L")
);
assert_eq!(
vec![keysyms::KEY_a, keysyms::KEY_b],
CskkKeyEvent::keysyms_from_str("ab")
);
assert_eq!(vec![keysyms::KEY_at], CskkKeyEvent::keysyms_from_str("at"));
assert_eq!(
vec![keysyms::KEY_question],
CskkKeyEvent::keysyms_from_str("question")
);
}
#[test]
fn is_modifierless() {
let key_event = CskkKeyEvent::from_str("C-c").unwrap();
assert!(!key_event.is_modifierless_input())
}
}