Skip to main content

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}