pc_keyboard/layouts/azerty.rs
1//! French keyboard support
2
3use crate::{
4 DecodedKey, HandleControl, KeyCode, KeyboardLayout, Modifiers, PhysicalKeyboard, QUO, SLS,
5};
6
7/// A standard French 102-key (or 105-key including Windows keys) keyboard.
8///
9/// The top row spells `AZERTY`. Has a 2-row high Enter key, with Oem5 next to
10/// the left shift (ISO format).
11///
12/// NB: no "dead key" support for now
13///
14/// These diagrams illustrate the conversion from [`KeyCode`] to Unicode. We
15/// show either a Unicode glyph, or a hex number if the glyph isn't a
16/// printable character. Blank spaces are passed through as
17/// [`DecodedKey::RawKey`].
18///
19/// Run the `print_keyboard` example to re-generate these images.
20///
21/// ## Unmodified
22///
23/// ```text
24/// ┌────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┐
25/// │001b│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
26/// └────┘ └────┴────┴────┴────┘ └────┴────┴────┴────┘ └────┴────┴────┴────┘ └────┴────┴────┘
27///
28/// ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬─────────┐ ┌────┬────┬────┐ ┌────┬────┬────┬────┐
29/// │ ² │ & │ é │ " │ ' │ ( │ - │ è │ _ │ ç │ à │ ) │ = │ 0008 │ │ │ │ │ │ │ / │ * │ - │
30/// ├────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬────────┤ ├────┼────┼────┤ ├────┼────┼────┼────┤
31/// │0009 │ a │ z │ e │ r │ t │ y │ u │ i │ o │ p │ ^ │ $ │ 000a │ │007f│ │ │ │ 7 │ 8 │ 9 │ │
32/// ├─────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┐ │ └────┴────┴────┘ ├────┼────┼────┤ + │
33/// │ │ q │ s │ d │ f │ g │ h │ j │ k │ l │ m │ ù │ * │ │ │ 4 │ 5 │ 6 │ │
34/// ├────┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴────┴───────┤ ┌────┐ ├────┼────┼────┼────┤
35/// │ │ < │ w │ x │ c │ v │ b │ n │ , │ ; │ : │ ! │ │ │ │ │ 1 │ 2 │ 3 │ │
36/// ├────┴┬───┴─┬──┴──┬─┴────┴────┴────┴────┴────┴───┬┴────┼────┴┬──────┬──────┤ ┌────┼────┼────┐ ├────┴────┼────┤000a│
37/// │ │ │ │ 0020 │ │ │ │ │ │ │ │ │ │ 0 │ . │ │
38/// └─────┴─────┴─────┴──────────────────────────────┴─────┴─────┴──────┴──────┘ └────┴────┴────┘ └─────────┴────┴────┘
39/// ```
40///
41/// ## Caps Lock
42///
43/// ```text
44/// ┌────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┐
45/// │001b│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
46/// └────┘ └────┴────┴────┴────┘ └────┴────┴────┴────┘ └────┴────┴────┴────┘ └────┴────┴────┘
47///
48/// ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬─────────┐ ┌────┬────┬────┐ ┌────┬────┬────┬────┐
49/// │ ² │ & │ é │ " │ ' │ ( │ - │ è │ _ │ ç │ à │ ) │ = │ 0008 │ │ │ │ │ │ │ / │ * │ - │
50/// ├────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬────────┤ ├────┼────┼────┤ ├────┼────┼────┼────┤
51/// │0009 │ A │ Z │ E │ R │ T │ Y │ U │ I │ O │ P │ ^ │ $ │ 000a │ │007f│ │ │ │ 7 │ 8 │ 9 │ │
52/// ├─────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┐ │ └────┴────┴────┘ ├────┼────┼────┤ + │
53/// │ │ Q │ S │ D │ F │ G │ H │ J │ K │ L │ M │ ù │ * │ │ │ 4 │ 5 │ 6 │ │
54/// ├────┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴────┴───────┤ ┌────┐ ├────┼────┼────┼────┤
55/// │ │ < │ W │ X │ C │ V │ B │ N │ , │ ; │ : │ ! │ │ │ │ │ 1 │ 2 │ 3 │ │
56/// ├────┴┬───┴─┬──┴──┬─┴────┴────┴────┴────┴────┴───┬┴────┼────┴┬──────┬──────┤ ┌────┼────┼────┐ ├────┴────┼────┤000a│
57/// │ │ │ │ 0020 │ │ │ │ │ │ │ │ │ │ 0 │ . │ │
58/// └─────┴─────┴─────┴──────────────────────────────┴─────┴─────┴──────┴──────┘ └────┴────┴────┘ └─────────┴────┴────┘
59/// ```
60///
61/// ## Shifted
62///
63/// ```text
64/// ┌────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┐
65/// │001b│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
66/// └────┘ └────┴────┴────┴────┘ └────┴────┴────┴────┘ └────┴────┴────┴────┘ └────┴────┴────┘
67///
68/// ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬─────────┐ ┌────┬────┬────┐ ┌────┬────┬────┬────┐
69/// │ ² │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ ° │ + │ 0008 │ │ │ │ │ │ │ / │ * │ - │
70/// ├────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬────────┤ ├────┼────┼────┤ ├────┼────┼────┼────┤
71/// │0009 │ A │ Z │ E │ R │ T │ Y │ U │ I │ O │ P │ ¨ │ £ │ 000a │ │007f│ │ │ │ 7 │ 8 │ 9 │ │
72/// ├─────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┐ │ └────┴────┴────┘ ├────┼────┼────┤ + │
73/// │ │ Q │ S │ D │ F │ G │ H │ J │ K │ L │ M │ % │ µ │ │ │ 4 │ 5 │ 6 │ │
74/// ├────┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴────┴───────┤ ┌────┐ ├────┼────┼────┼────┤
75/// │ │ > │ W │ X │ C │ V │ B │ N │ ? │ . │ / │ § │ │ │ │ │ 1 │ 2 │ 3 │ │
76/// ├────┴┬───┴─┬──┴──┬─┴────┴────┴────┴────┴────┴───┬┴────┼────┴┬──────┬──────┤ ┌────┼────┼────┐ ├────┴────┼────┤000a│
77/// │ │ │ │ 0020 │ │ │ │ │ │ │ │ │ │ 0 │ . │ │
78/// └─────┴─────┴─────┴──────────────────────────────┴─────┴─────┴──────┴──────┘ └────┴────┴────┘ └─────────┴────┴────┘
79/// ```
80///
81/// ## Control
82///
83/// ```text
84/// ┌────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┐
85/// │001b│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
86/// └────┘ └────┴────┴────┴────┘ └────┴────┴────┴────┘ └────┴────┴────┴────┘ └────┴────┴────┘
87///
88/// ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬─────────┐ ┌────┬────┬────┐ ┌────┬────┬────┬────┐
89/// │ ² │ & │ é │ " │ ' │ ( │ - │ è │ _ │ ç │ à │ ) │ = │ 0008 │ │ │ │ │ │ │ / │ * │ - │
90/// ├────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬────────┤ ├────┼────┼────┤ ├────┼────┼────┼────┤
91/// │0009 │0001│001a│0005│0012│0014│0019│0015│0009│000f│0010│ ^ │ $ │ 000a │ │007f│ │ │ │ 7 │ 8 │ 9 │ │
92/// ├─────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┐ │ └────┴────┴────┘ ├────┼────┼────┤ + │
93/// │ │0011│0013│0004│0006│0007│0008│000a│000b│000c│000d│ ù │ * │ │ │ 4 │ 5 │ 6 │ │
94/// ├────┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴────┴───────┤ ┌────┐ ├────┼────┼────┼────┤
95/// │ │ < │0017│0018│0003│0016│0002│000e│ , │ ; │ : │ ! │ │ │ │ │ 1 │ 2 │ 3 │ │
96/// ├────┴┬───┴─┬──┴──┬─┴────┴────┴────┴────┴────┴───┬┴────┼────┴┬──────┬──────┤ ┌────┼────┼────┐ ├────┴────┼────┤000a│
97/// │ │ │ │ 0020 │ │ │ │ │ │ │ │ │ │ 0 │ . │ │
98/// └─────┴─────┴─────┴──────────────────────────────┴─────┴─────┴──────┴──────┘ └────┴────┴────┘ └─────────┴────┴────┘
99/// ```
100///
101/// ## AltGr
102///
103/// ```text
104/// ┌────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┐
105/// │001b│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
106/// └────┘ └────┴────┴────┴────┘ └────┴────┴────┴────┘ └────┴────┴────┴────┘ └────┴────┴────┘
107///
108/// ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬─────────┐ ┌────┬────┬────┐ ┌────┬────┬────┬────┐
109/// │ ² │ & │ ~ │ # │ { │ [ │ | │ ` │ \ │ ^ │ @ │ ] │ } │ 0008 │ │ │ │ │ │ │ / │ * │ - │
110/// ├────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬────────┤ ├────┼────┼────┤ ├────┼────┼────┼────┤
111/// │0009 │ a │ z │ € │ r │ t │ y │ u │ i │ o │ p │ ^ │ ¤ │ 000a │ │007f│ │ │ │ 7 │ 8 │ 9 │ │
112/// ├─────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┐ │ └────┴────┴────┘ ├────┼────┼────┤ + │
113/// │ │ q │ s │ d │ f │ g │ h │ j │ k │ l │ m │ ù │ * │ │ │ 4 │ 5 │ 6 │ │
114/// ├────┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴────┴───────┤ ┌────┐ ├────┼────┼────┼────┤
115/// │ │ < │ w │ x │ c │ v │ b │ n │ , │ ; │ : │ ! │ │ │ │ │ 1 │ 2 │ 3 │ │
116/// ├────┴┬───┴─┬──┴──┬─┴────┴────┴────┴────┴────┴───┬┴────┼────┴┬──────┬──────┤ ┌────┼────┼────┐ ├────┴────┼────┤000a│
117/// │ │ │ │ 0020 │ │ │ │ │ │ │ │ │ │ 0 │ . │ │
118/// └─────┴─────┴─────┴──────────────────────────────┴─────┴─────┴──────┴──────┘ └────┴────┴────┘ └─────────┴────┴────┘
119/// ```
120///
121/// ## Shift AltGr
122///
123/// ```text
124/// ┌────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┐
125/// │001b│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
126/// └────┘ └────┴────┴────┴────┘ └────┴────┴────┴────┘ └────┴────┴────┴────┘ └────┴────┴────┘
127///
128/// ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬─────────┐ ┌────┬────┬────┐ ┌────┬────┬────┬────┐
129/// │ ² │ 1 │ ~ │ # │ { │ [ │ | │ ` │ \ │ ^ │ @ │ ] │ } │ 0008 │ │ │ │ │ │ │ / │ * │ - │
130/// ├────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬────────┤ ├────┼────┼────┤ ├────┼────┼────┼────┤
131/// │0009 │ A │ Z │ € │ R │ T │ Y │ U │ I │ O │ P │ ¨ │ ¤ │ 000a │ │007f│ │ │ │ 7 │ 8 │ 9 │ │
132/// ├─────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┐ │ └────┴────┴────┘ ├────┼────┼────┤ + │
133/// │ │ Q │ S │ D │ F │ G │ H │ J │ K │ L │ M │ % │ µ │ │ │ 4 │ 5 │ 6 │ │
134/// ├────┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴────┴───────┤ ┌────┐ ├────┼────┼────┼────┤
135/// │ │ > │ W │ X │ C │ V │ B │ N │ ? │ . │ / │ § │ │ │ │ │ 1 │ 2 │ 3 │ │
136/// ├────┴┬───┴─┬──┴──┬─┴────┴────┴────┴────┴────┴───┬┴────┼────┴┬──────┬──────┤ ┌────┼────┼────┐ ├────┴────┼────┤000a│
137/// │ │ │ │ 0020 │ │ │ │ │ │ │ │ │ │ 0 │ . │ │
138/// └─────┴─────┴─────┴──────────────────────────────┴─────┴─────┴──────┴──────┘ └────┴────┴────┘ └─────────┴────┴────┘
139/// ```
140pub struct Azerty;
141
142impl KeyboardLayout for Azerty {
143 #[rustfmt::skip]
144 fn map_keycode(
145 &self,
146 keycode: KeyCode,
147 modifiers: &Modifiers,
148 handle_ctrl: HandleControl,
149 ) -> DecodedKey {
150 match keycode {
151 // ========= Row 2 (the numbers) =========
152 KeyCode::Oem8 => DecodedKey::Unicode('²'),
153 KeyCode::Key1 => modifiers.handle_symbol2('&', '1'),
154 KeyCode::Key2 => modifiers.handle_symbol3('é', '2', '~'),
155 KeyCode::Key3 => modifiers.handle_symbol3('"', '3', '#'),
156 KeyCode::Key4 => modifiers.handle_symbol3(QUO, '4', '{'),
157 KeyCode::Key5 => modifiers.handle_symbol3('(', '5', '['),
158 KeyCode::Key6 => modifiers.handle_symbol3('-', '6', '|'),
159 KeyCode::Key7 => modifiers.handle_symbol3('è', '7', '`'),
160 KeyCode::Key8 => modifiers.handle_symbol3('_', '8', SLS),
161 KeyCode::Key9 => modifiers.handle_symbol3('ç', '9', '^'),
162 KeyCode::Key0 => modifiers.handle_symbol3('à', '0', '@'),
163 KeyCode::OemMinus => modifiers.handle_symbol3(')', '°', ']'),
164 KeyCode::OemPlus => modifiers.handle_symbol3('=', '+', '}'),
165 // ========= Row 3 (QWERTY) =========
166 KeyCode::Q => modifiers.handle_ascii_2('A', handle_ctrl),
167 KeyCode::W => modifiers.handle_ascii_2('Z', handle_ctrl),
168 KeyCode::E => modifiers.handle_ascii_3('E', '€', handle_ctrl),
169 KeyCode::Oem4 => modifiers.handle_symbol2('^', '¨'),
170 KeyCode::Oem6 => modifiers.handle_symbol3('$', '£', '¤'),
171 // ========= Row 4 (ASDFG) =========
172 KeyCode::A => modifiers.handle_ascii_2('Q', handle_ctrl),
173 KeyCode::Oem1 => modifiers.handle_ascii_2('M', handle_ctrl),
174 KeyCode::Oem3 => modifiers.handle_symbol2('ù', '%'),
175 KeyCode::Oem7 => modifiers.handle_symbol2('*', 'µ'),
176 // ========= Row 5 (ZXCVB) =========
177 KeyCode::Oem5 => modifiers.handle_symbol2('<', '>'),
178 KeyCode::Z => modifiers.handle_ascii_2('W', handle_ctrl),
179 KeyCode::M => modifiers.handle_symbol2(',', '?'),
180 KeyCode::OemComma => modifiers.handle_symbol2(';', '.'),
181 KeyCode::OemPeriod => modifiers.handle_symbol2(':', '/'),
182 KeyCode::Oem2 => modifiers.handle_symbol2('!', '§'),
183 // ========= Fallback =========
184 e => super::Us104Key.map_keycode(e, modifiers, handle_ctrl),
185 }
186 }
187
188 fn get_physical(&self) -> PhysicalKeyboard {
189 PhysicalKeyboard::Iso
190 }
191}
192
193#[cfg(test)]
194mod test {
195 use super::*;
196 use crate::{KeyCode, KeyEvent, KeyState, PS2Keyboard, ScancodeSet2};
197
198 #[test]
199 fn test_frazert() {
200 let mut k = PS2Keyboard::new(
201 ScancodeSet2::new(),
202 Azerty,
203 HandleControl::MapLettersToUnicode,
204 );
205 assert_eq!(
206 k.process_keyevent(KeyEvent::new(KeyCode::NumpadDivide, KeyState::Down)),
207 Some(DecodedKey::Unicode('/'))
208 );
209 assert_eq!(
210 k.process_keyevent(KeyEvent::new(KeyCode::NumpadMultiply, KeyState::Down)),
211 Some(DecodedKey::Unicode('*'))
212 );
213 assert_eq!(
214 k.process_keyevent(KeyEvent::new(KeyCode::A, KeyState::Down)),
215 Some(DecodedKey::Unicode('q'))
216 );
217 assert_eq!(
218 k.process_keyevent(KeyEvent::new(KeyCode::Key4, KeyState::Down)),
219 Some(DecodedKey::Unicode('\''))
220 );
221 assert_eq!(
222 k.process_keyevent(KeyEvent::new(KeyCode::Oem5, KeyState::Down)),
223 Some(DecodedKey::Unicode('<'))
224 );
225 assert_eq!(
226 k.process_keyevent(KeyEvent::new(KeyCode::Oem7, KeyState::Down)),
227 Some(DecodedKey::Unicode('*'))
228 );
229 assert_eq!(
230 k.process_keyevent(KeyEvent::new(KeyCode::Numpad0, KeyState::Up)),
231 None
232 );
233 assert_eq!(
234 k.process_keyevent(KeyEvent::new(KeyCode::NumpadLock, KeyState::Down)),
235 Some(DecodedKey::RawKey(KeyCode::NumpadLock))
236 );
237 assert_eq!(
238 k.process_keyevent(KeyEvent::new(KeyCode::NumpadLock, KeyState::Up)),
239 None
240 );
241 assert_eq!(
242 k.process_keyevent(KeyEvent::new(KeyCode::Numpad0, KeyState::Down)),
243 Some(DecodedKey::RawKey(KeyCode::Insert))
244 );
245 assert_eq!(
246 k.process_keyevent(KeyEvent::new(KeyCode::Numpad0, KeyState::Up)),
247 None
248 );
249 }
250}