Skip to main content

pfx_input/
layout.rs

1#[cfg(windows)]
2mod windows;
3
4use std::collections::BTreeMap;
5
6use crate::device::Key;
7
8#[cfg(windows)]
9pub use windows::WindowsLayout;
10
11pub trait LayoutSource {
12    fn layout(&mut self) -> u64;
13
14    fn label(&mut self, key: Key) -> Option<String>;
15}
16
17#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
18pub struct Us;
19
20impl LayoutSource for Us {
21    fn layout(&mut self) -> u64 {
22        0
23    }
24
25    fn label(&mut self, _key: Key) -> Option<String> {
26        None
27    }
28}
29
30#[derive(Clone, Debug, Default, PartialEq, Eq)]
31pub struct KeyLabels {
32    layout: Option<u64>,
33    labels: BTreeMap<Key, String>,
34    names: BTreeMap<Key, String>,
35}
36
37impl KeyLabels {
38    pub fn new() -> Self {
39        Self::default()
40    }
41
42    pub fn label(&self, key: Key) -> &str {
43        self.names
44            .get(&key)
45            .or_else(|| self.labels.get(&key))
46            .map_or_else(|| key.label(), String::as_str)
47    }
48
49    pub fn layout(&self) -> Option<u64> {
50        self.layout
51    }
52
53    pub fn refresh(&mut self, source: &mut (impl LayoutSource + ?Sized)) -> bool {
54        let layout = source.layout();
55        if self.layout == Some(layout) {
56            return false;
57        }
58        self.layout = Some(layout);
59        let labels: BTreeMap<Key, String> = Key::ALL
60            .into_iter()
61            .filter(|key| key.follows_layout())
62            .filter_map(|key| {
63                let label = cap_label(&source.label(key)?)?;
64                (label != key.label()).then_some((key, label))
65            })
66            .collect();
67        let changed = labels != self.labels;
68        self.labels = labels;
69        changed
70    }
71
72    pub fn learn(&mut self, key: Key, text: &str) -> bool {
73        if !key.follows_layout() {
74            return false;
75        }
76        let Some(label) = cap_label(text) else {
77            return false;
78        };
79        let known = self.labels.get(&key).map(String::as_str);
80        if known.unwrap_or(key.label()) == label {
81            return false;
82        }
83        if known.is_some() {
84            self.labels.clear();
85            self.layout = None;
86        }
87        if label != key.label() {
88            self.labels.insert(key, label);
89        }
90        true
91    }
92
93    pub fn rename(&mut self, key: Key, name: &str) {
94        match cap_label(name) {
95            Some(name) => self.names.insert(key, name),
96            None => self.names.remove(&key),
97        };
98    }
99
100    pub fn forget(&mut self) {
101        self.layout = None;
102        self.labels.clear();
103    }
104}
105
106pub fn cap_label(text: &str) -> Option<String> {
107    let label: String = text
108        .trim()
109        .chars()
110        .filter(|c| !c.is_control())
111        .map(|c| {
112            let mut upper = c.to_uppercase();
113            match (upper.next(), upper.next()) {
114                (Some(single), None) => single,
115                _ => c,
116            }
117        })
118        .collect();
119    (!label.is_empty()).then_some(label)
120}
121
122pub fn scancode(key: Key) -> Option<u16> {
123    Some(match key {
124        Key::Escape => 0x01,
125        Key::Digit1 => 0x02,
126        Key::Digit2 => 0x03,
127        Key::Digit3 => 0x04,
128        Key::Digit4 => 0x05,
129        Key::Digit5 => 0x06,
130        Key::Digit6 => 0x07,
131        Key::Digit7 => 0x08,
132        Key::Digit8 => 0x09,
133        Key::Digit9 => 0x0a,
134        Key::Digit0 => 0x0b,
135        Key::Minus => 0x0c,
136        Key::Equal => 0x0d,
137        Key::Backspace => 0x0e,
138        Key::Tab => 0x0f,
139        Key::Q => 0x10,
140        Key::W => 0x11,
141        Key::E => 0x12,
142        Key::R => 0x13,
143        Key::T => 0x14,
144        Key::Y => 0x15,
145        Key::U => 0x16,
146        Key::I => 0x17,
147        Key::O => 0x18,
148        Key::P => 0x19,
149        Key::BracketLeft => 0x1a,
150        Key::BracketRight => 0x1b,
151        Key::Enter => 0x1c,
152        Key::ControlLeft => 0x1d,
153        Key::A => 0x1e,
154        Key::S => 0x1f,
155        Key::D => 0x20,
156        Key::F => 0x21,
157        Key::G => 0x22,
158        Key::H => 0x23,
159        Key::J => 0x24,
160        Key::K => 0x25,
161        Key::L => 0x26,
162        Key::Semicolon => 0x27,
163        Key::Quote => 0x28,
164        Key::Backquote => 0x29,
165        Key::ShiftLeft => 0x2a,
166        Key::Backslash => 0x2b,
167        Key::Z => 0x2c,
168        Key::X => 0x2d,
169        Key::C => 0x2e,
170        Key::V => 0x2f,
171        Key::B => 0x30,
172        Key::N => 0x31,
173        Key::M => 0x32,
174        Key::Comma => 0x33,
175        Key::Period => 0x34,
176        Key::Slash => 0x35,
177        Key::ShiftRight => 0x36,
178        Key::AltLeft => 0x38,
179        Key::Space => 0x39,
180        Key::CapsLock => 0x3a,
181        _ => return None,
182    })
183}