use std::{
fmt::{Debug, Display},
str::FromStr,
};
pub use self::{
dc26::DaiChien26,
et::Et,
et26::Et26,
ginyieh::GinYieh,
hsu::Hsu,
ibm::Ibm,
pinyin::{Pinyin, PinyinVariant},
standard::Standard,
};
use crate::{input::KeyboardEvent, zhuyin::Syllable};
mod dc26;
mod et;
mod et26;
mod ginyieh;
mod hsu;
mod ibm;
mod pinyin;
mod standard;
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C)]
pub enum KeyboardLayoutCompat {
Default = 0,
Hsu,
Ibm,
GinYieh,
Et,
Et26,
Dvorak,
DvorakHsu,
DachenCp26,
HanyuPinyin,
ThlPinyin,
Mps2Pinyin,
Carpalx,
ColemakDhAnsi,
ColemakDhOrth,
Workman,
Colemak,
}
#[derive(Debug)]
pub struct ParseKeyboardLayoutError;
impl Display for ParseKeyboardLayoutError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Unable to parse keyboard layout")
}
}
impl FromStr for KeyboardLayoutCompat {
type Err = ParseKeyboardLayoutError;
fn from_str(kb_str: &str) -> Result<Self, Self::Err> {
let layout = match kb_str {
"KB_DEFAULT" => Self::Default,
"KB_HSU" => Self::Hsu,
"KB_IBM" => Self::Ibm,
"KB_GIN_YIEH" => Self::GinYieh,
"KB_ET" => Self::Et,
"KB_ET26" => Self::Et26,
"KB_DVORAK" => Self::Dvorak,
"KB_DVORAK_HSU" => Self::DvorakHsu,
"KB_DACHEN_CP26" => Self::DachenCp26,
"KB_HANYU_PINYIN" => Self::HanyuPinyin,
"KB_THL_PINYIN" => Self::ThlPinyin,
"KB_MPS2_PINYIN" => Self::Mps2Pinyin,
"KB_CARPALX" => Self::Carpalx,
"KB_COLEMAK" => Self::Colemak,
"KB_COLEMAK_DH_ANSI" => Self::ColemakDhAnsi,
"KB_COLEMAK_DH_ORTH" => Self::ColemakDhOrth,
"KB_WORKMAN" => Self::Workman,
_ => return Err(ParseKeyboardLayoutError),
};
Ok(layout)
}
}
impl Display for KeyboardLayoutCompat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
KeyboardLayoutCompat::Default => f.write_str("KB_DEFAULT"),
KeyboardLayoutCompat::Hsu => f.write_str("KB_HSU"),
KeyboardLayoutCompat::Ibm => f.write_str("KB_IBM"),
KeyboardLayoutCompat::GinYieh => f.write_str("KB_GIN_YIEH"),
KeyboardLayoutCompat::Et => f.write_str("KB_ET"),
KeyboardLayoutCompat::Et26 => f.write_str("KB_ET26"),
KeyboardLayoutCompat::Dvorak => f.write_str("KB_DVORAK"),
KeyboardLayoutCompat::DvorakHsu => f.write_str("KB_DVORAK_HSU"),
KeyboardLayoutCompat::DachenCp26 => f.write_str("KB_DACHEN_CP26"),
KeyboardLayoutCompat::HanyuPinyin => f.write_str("KB_HANYU_PINYIN"),
KeyboardLayoutCompat::ThlPinyin => f.write_str("KB_THL_PINYIN"),
KeyboardLayoutCompat::Mps2Pinyin => f.write_str("KB_MPS2_PINYIN"),
KeyboardLayoutCompat::Carpalx => f.write_str("KB_CARPALX"),
KeyboardLayoutCompat::Colemak => f.write_str("KB_COLEMAK"),
KeyboardLayoutCompat::ColemakDhAnsi => f.write_str("KB_COLEMAK_DH_ANSI"),
KeyboardLayoutCompat::ColemakDhOrth => f.write_str("KB_COLEMAK_DH_ORTH"),
KeyboardLayoutCompat::Workman => f.write_str("KB_WORKMAN"),
}
}
}
impl TryFrom<u8> for KeyboardLayoutCompat {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
Ok(match value {
0 => Self::Default,
1 => Self::Hsu,
2 => Self::Ibm,
3 => Self::GinYieh,
4 => Self::Et,
5 => Self::Et26,
6 => Self::Dvorak,
7 => Self::DvorakHsu,
8 => Self::DachenCp26,
9 => Self::HanyuPinyin,
10 => Self::ThlPinyin,
11 => Self::Mps2Pinyin,
12 => Self::Carpalx,
13 => Self::ColemakDhAnsi,
14 => Self::ColemakDhOrth,
15 => Self::Workman,
16 => Self::Colemak,
_ => return Err(()),
})
}
}
#[derive(Debug, PartialEq)]
pub enum KeyBehavior {
Ignore,
Absorb,
Commit,
KeyError,
Error,
NoWord,
OpenSymbolTable,
Fuzzy(Syllable),
}
pub trait SyllableEditor: Debug {
fn key_press(&mut self, key: KeyboardEvent) -> KeyBehavior;
fn fuzzy_key_press(&mut self, key: KeyboardEvent) -> KeyBehavior {
if self.is_empty() {
return self.key_press(key);
}
let mut clone = self.clone();
clone.clear();
clone.key_press(key);
let current_syl = self.read();
let new_syl = clone.read();
if current_syl.has_initial() && new_syl.has_initial()
|| current_syl.has_medial() && (new_syl.has_initial() || new_syl.has_medial())
|| current_syl.has_rime()
&& (new_syl.has_initial() || new_syl.has_medial() || new_syl.has_rime())
{
let ret = KeyBehavior::Fuzzy(current_syl);
self.clear();
self.key_press(key);
return ret;
}
self.key_press(key)
}
fn remove_last(&mut self);
fn clear(&mut self);
fn is_empty(&self) -> bool;
fn read(&self) -> Syllable;
fn key_seq(&self) -> Option<String> {
None
}
fn alt_syllables(&self, syl: Syllable) -> &[Syllable] {
let _ = syl;
&[]
}
fn clone(&self) -> Box<dyn SyllableEditor>;
}