Skip to content

Commit 93820bb

Browse files
authored
Split up the Keyboard type. (#31)
1 parent 549d49e commit 93820bb

17 files changed

+689
-213
lines changed

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ keywords = ["arm", "cortex-m", "template", "video", "menu"]
77
categories = ["embedded", "no-std"]
88
license = "MIT OR Apache-2.0"
99
repository = "https://github.com/rust-embedded-community/pc-keyboard.git"
10+
edition = "2021"
1011

1112
[dependencies]

README.md

+36-26
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,45 @@ output directly).
66

77
## Supports:
88

9-
- Scancode Set 1 and 2
10-
- Dvorak 104-key layout
11-
- US 104-key layout
12-
- UK 105-key layout
13-
- JIS 109-key layout
14-
- Azerty full layout
9+
- Scancode Set 1 (from the i8042 PC keyboard controller)
10+
- Scancode Set 2 (direct from the AT or PS/2 interface keyboard)
11+
- Several keyboard layouts:
12+
13+
| Name | No. Keys | Description | Link |
14+
| ---------------------------------------------------- | -------- | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------- |
15+
| [`Us104`](./src/layouts/us104.rs) | 101/104 | North American standard English | [Wikipedia](https://en.wikipedia.org/wiki/QWERTY#United_States) |
16+
| [`Uk105`](./src/layouts/uk105.rs) | 102/105 | United Kingdom standard English | [Wikipedia](https://en.wikipedia.org/wiki/QWERTY#United_Kingdom) |
17+
| [`Azerty`](./src/layouts/azerty.rs) | 102/105 | Typically used in French locales | [Wikipedia](https://en.wikipedia.org/wiki/AZERTY) |
18+
| [`De104`](./src/layouts/de104.rs) | 102/105 | German layout | [Wikipedia](https://en.wikipedia.org/wiki/QWERTZ) |
19+
| [`Jis109`](./src/layouts/jis109.rs) | 106/109 | JIS 109-key layout (Latin chars only) | [Wikipedia](https://en.wikipedia.org/wiki/Japanese_input_method#Japanese_keyboards) |
20+
| [`Colemak`](./src/layouts/colemak.rs) | 101/104 | A keyboard layout designed to make typing more efficient and comfortable | [Wikipedia](https://en.wikipedia.org/wiki/Colemak) |
21+
| [`Dvorak104Key`](./src/layouts/dvorak104.rs) | 101/104 | The more 'ergonomic' alternative to QWERTY | [Wikipedia](https://en.wikipedia.org/wiki/Dvorak_keyboard_layout) |
22+
| [`DVP104Key`](./src/layouts/dvorak_programmer104.rs) | 101/104 | Dvorak for Programmers | [Wikipedia](https://en.wikipedia.org/wiki/Dvorak_keyboard_layout#Programmer_Dvorak) |
23+
24+
101/104 keys is ANSI layout (wide Enter key) and 102/105 keys is ISO layout
25+
(tall Enter key). The difference between 101 and 104 (and between 102 and
26+
105) comes from the two Windows keys and the Menu key that were added when
27+
Windows 95 came out. JIS keyboards have extra keys, added by making the
28+
space-bar and backspace keys shorter.
29+
1530

1631
## Usage
1732

18-
```rust
19-
extern crate pc_keyboard;
20-
21-
use pc_keyboard::{Keyboard, layouts, ScancodeSet2, HandleControl};
22-
23-
fn main() {
24-
let mut kb: Keyboard<layouts::Us104Key, ScancodeSet2> = Keyboard::new(HandleControl::MapLettersToUnicode);
25-
match kb.add_byte(0x20) {
26-
Ok(Some(event)) => {
27-
println!("Event {:?}", event);
28-
}
29-
Ok(None) => {
30-
println!("Need more data");
31-
}
32-
Err(e) => {
33-
println!("Error decoding: {:?}", e);
34-
}
35-
}
36-
}
37-
```
33+
There are three basic steps to handling keyboard input. Your application may bypass some of these.
34+
35+
* `Ps2Decoder` - converts 11-bit PS/2 words into bytes, removing the start/stop
36+
bits and checking the parity bits. Only needed if you talk to the PS/2
37+
keyboard over GPIO pins and not required if you talk to the i8042 PC keyboard
38+
controller.
39+
* `ScancodeSet` - converts from Scancode Set 1 (i8042 PC keyboard controller) or
40+
Scancode Set 2 (raw PS/2 keyboard output) into a symbolic `KeyCode` and an
41+
up/down `KeyState`.
42+
* `EventDecoder` - converts symbolic `KeyCode` and `KeyState` into a Unicode
43+
characters (where possible) according to the currently selected `KeyboardLayout`.
44+
45+
There is also `Keyboard` which combines the above three functions into a single object.
46+
47+
See the [`examples`](./examples) folder for more details.
3848

3949
## [Documentation](https://docs.rs/crate/pc-keyboard)
4050

examples/decoder.rs

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
use pc_keyboard::Ps2Decoder;
2+
3+
fn main() {
4+
let mut decoder = Ps2Decoder::new();
5+
6+
// If you get all 11 bits as one `u16`
7+
match decoder.add_word(0x0402) {
8+
Ok(byte) => println!("Word 0x0402 is byte 0x{:02x}", byte),
9+
Err(e) => println!("Word 0x0402 failed to decode: {:?}", e),
10+
}
11+
12+
// If you get a bit at a time
13+
for bit in [
14+
false, true, false, false, false, false, false, false, false, false, true,
15+
] {
16+
match decoder.add_bit(bit) {
17+
Ok(None) => println!("Added {}, not enough bits yet!", bit as u8),
18+
Ok(Some(byte)) => println!("Added {}, got byte 0x{byte:02x}", bit as u8),
19+
Err(e) => println!("Failed to decode: {e:?}"),
20+
}
21+
}
22+
23+
// Flipped a random bit, so we get a parity error
24+
for bit in [
25+
false, true, false, false, false, false, true, false, false, false, true,
26+
] {
27+
match decoder.add_bit(bit) {
28+
Ok(None) => println!("Added {}, not enough bits yet!", bit as u8),
29+
Ok(Some(byte)) => println!("Added {}, got byte 0x{byte:02x}", bit as u8),
30+
Err(e) => println!("Failed to decode: {e:?}"),
31+
}
32+
}
33+
}

examples/layout.rs

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use pc_keyboard::{
2+
layouts::{AnyLayout, Uk105Key},
3+
DecodedKey, EventDecoder, KeyCode, KeyEvent, KeyState,
4+
};
5+
6+
fn main() {
7+
let mut decoder = EventDecoder::new(
8+
AnyLayout::Uk105Key(Uk105Key),
9+
pc_keyboard::HandleControl::Ignore,
10+
);
11+
12+
// User presses 'A' on their UK keyboard, gets a lower-case 'a'.
13+
let decoded_key = decoder.process_keyevent(KeyEvent {
14+
code: KeyCode::A,
15+
state: KeyState::Down,
16+
});
17+
assert_eq!(Some(DecodedKey::Unicode('a')), decoded_key);
18+
println!("Got {:?}", decoded_key);
19+
20+
// User releases 'A' on their UK keyboard
21+
let decoded_key = decoder.process_keyevent(KeyEvent {
22+
code: KeyCode::A,
23+
state: KeyState::Up,
24+
});
25+
assert_eq!(None, decoded_key);
26+
27+
// User presses 'Shift' on their UK keyboard
28+
let decoded_key = decoder.process_keyevent(KeyEvent {
29+
code: KeyCode::LShift,
30+
state: KeyState::Down,
31+
});
32+
assert_eq!(None, decoded_key);
33+
34+
// User presses 'A' on their UK keyboard, now gets a Capital A
35+
let decoded_key = decoder.process_keyevent(KeyEvent {
36+
code: KeyCode::A,
37+
state: KeyState::Down,
38+
});
39+
assert_eq!(Some(DecodedKey::Unicode('A')), decoded_key);
40+
println!("Got {:?}", decoded_key);
41+
42+
// User releases 'A' on their UK keyboard
43+
let decoded_key = decoder.process_keyevent(KeyEvent {
44+
code: KeyCode::A,
45+
state: KeyState::Up,
46+
});
47+
assert_eq!(None, decoded_key);
48+
49+
// User releases 'Shift' on their UK keyboard
50+
let decoded_key = decoder.process_keyevent(KeyEvent {
51+
code: KeyCode::LShift,
52+
state: KeyState::Up,
53+
});
54+
assert_eq!(None, decoded_key);
55+
}

examples/scancodes.rs

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
use pc_keyboard::{KeyEvent, ScancodeSet, ScancodeSet1, ScancodeSet2};
2+
3+
fn main() {
4+
let mut s = ScancodeSet1::new();
5+
// [ 0x01 ] means "Pressed Escape" in Set 1
6+
match s.advance_state(0x01) {
7+
Ok(Some(KeyEvent { code, state })) => {
8+
println!("Scancode Set 1 0x01 is KeyCode '{code:?}' KeyState '{state:?}'");
9+
}
10+
Ok(None) => {
11+
println!("This is wrong, we didn't think that was a complete sequence");
12+
}
13+
Err(e) => {
14+
println!("There was an error: {e:?}");
15+
}
16+
}
17+
// [ 0x81 ] means "Released Escape" in Set 1
18+
match s.advance_state(0x81) {
19+
Ok(Some(KeyEvent { code, state })) => {
20+
println!("Scancode Set 1 0x81 is KeyCode '{code:?}' KeyState '{state:?}'");
21+
}
22+
Ok(None) => {
23+
println!("This is wrong, we didn't think that was a complete sequence");
24+
}
25+
Err(e) => {
26+
println!("There was an error: {e:?}");
27+
}
28+
}
29+
30+
let mut s = ScancodeSet2::new();
31+
// [ 0x01 ] means "Pressed F9" in Set 2
32+
match s.advance_state(0x01) {
33+
Ok(Some(KeyEvent { code, state })) => {
34+
println!("Scancode Set 2 0x01 is KeyCode '{code:?}' KeyState '{state:?}'");
35+
}
36+
Ok(None) => {
37+
println!("This is wrong, we didn't think that was a complete sequence");
38+
}
39+
Err(e) => {
40+
println!("There was an error: {e:?}");
41+
}
42+
}
43+
// [ 0xF0, 0x01 ] means "Released F9" in Set 2
44+
assert_eq!(Ok(None), s.advance_state(0xF0));
45+
match s.advance_state(0x01) {
46+
Ok(Some(KeyEvent { code, state })) => {
47+
println!("Scancode Set 2 0xF0 0x01 is KeyCode '{code:?}' KeyState '{state:?}'");
48+
}
49+
Ok(None) => {
50+
println!("This is wrong, we didn't think that was a complete sequence");
51+
}
52+
Err(e) => {
53+
println!("There was an error: {e:?}");
54+
}
55+
}
56+
}

src/layouts/azerty.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
1+
//! French keyboard support
2+
13
use crate::{DecodedKey, HandleControl, KeyCode, KeyboardLayout, Modifiers};
24

5+
/// A standard French 102-key (or 105-key including Windows keys) keyboard.
6+
///
7+
/// The top row spells `AZERTY`.
8+
///
9+
/// Has a 2-row high Enter key, with Oem5 next to the left shift (ISO format).
310
pub struct Azerty;
411

512
impl KeyboardLayout for Azerty {
613
fn map_keycode(
14+
&self,
715
keycode: KeyCode,
816
modifiers: &Modifiers,
917
handle_ctrl: HandleControl,
@@ -514,7 +522,11 @@ mod test {
514522

515523
#[test]
516524
fn test_frazert() {
517-
let mut k = Keyboard::<Azerty, ScancodeSet2>::new(HandleControl::MapLettersToUnicode);
525+
let mut k = Keyboard::new(
526+
ScancodeSet2::new(),
527+
Azerty,
528+
HandleControl::MapLettersToUnicode,
529+
);
518530
assert_eq!(
519531
k.process_keyevent(KeyEvent::new(KeyCode::NumpadDivide, KeyState::Down)),
520532
Some(DecodedKey::Unicode('/'))

src/layouts/colemak.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
//! A Colemak 101-key (or 104-key including Windows keys) keyboard.
2-
//! Has a 1-row high Enter key, with Backslash above.
1+
//! The Colemak keyboard support
32
43
use crate::{DecodedKey, HandleControl, KeyCode, KeyboardLayout, Modifiers};
54

5+
/// A Colemak 101-key (or 104-key including Windows keys) keyboard.
6+
///
7+
/// Has a 1-row high Enter key, with Oem7 above (ANSI layout).
68
pub struct Colemak;
79

810
impl KeyboardLayout for Colemak {
911
fn map_keycode(
12+
&self,
1013
keycode: KeyCode,
1114
modifiers: &Modifiers,
1215
handle_ctrl: HandleControl,

src/layouts/de104.rs renamed to src/layouts/de105.rs

+14-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1-
use crate::{DecodedKey, HandleControl, KeyCode, KeyboardLayout, Modifiers};
1+
//! German keyboard support
22
3-
pub use super::us104::Us104Key;
3+
use crate::{DecodedKey, HandleControl, KeyCode, KeyboardLayout, Modifiers};
44

5-
pub struct De104Key;
5+
/// A standard German 102-key (or 105-key including Windows keys) keyboard.
6+
///
7+
/// The top row spells `QWERTZ`.
8+
///
9+
/// Has a 2-row high Enter key, with Oem5 next to the left shift (ISO format).
10+
pub struct De105Key;
611

7-
impl KeyboardLayout for De104Key {
12+
impl KeyboardLayout for De105Key {
813
fn map_keycode(
14+
&self,
915
keycode: KeyCode,
1016
modifiers: &Modifiers,
1117
handle_ctrl: HandleControl,
@@ -214,8 +220,10 @@ impl KeyboardLayout for De104Key {
214220
DecodedKey::Unicode('<')
215221
}
216222
}
217-
218-
e => <super::Us104Key as KeyboardLayout>::map_keycode(e, modifiers, handle_ctrl),
223+
e => {
224+
let us = super::Us104Key;
225+
us.map_keycode(e, modifiers, handle_ctrl)
226+
}
219227
}
220228
}
221229
}

src/layouts/dvorak104.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
//! A Dvorak 101-key (or 104-key including Windows keys) keyboard.
2-
//! Has a 1-row high Enter key, with Backslash above.
1+
//! Dvorak keyboard support
32
43
use crate::{DecodedKey, HandleControl, KeyCode, KeyboardLayout, Modifiers};
54

6-
pub use super::us104::Us104Key;
7-
5+
/// A Dvorak 101-key (or 104-key including Windows keys) keyboard.
6+
///
7+
/// Has a 1-row high Enter key, with Oem7 above (ANSI layout).
88
pub struct Dvorak104Key;
99

1010
impl KeyboardLayout for Dvorak104Key {
1111
fn map_keycode(
12+
&self,
1213
keycode: KeyCode,
1314
modifiers: &Modifiers,
1415
handle_ctrl: HandleControl,
@@ -294,7 +295,10 @@ impl KeyboardLayout for Dvorak104Key {
294295
DecodedKey::Unicode('z')
295296
}
296297
}
297-
e => <super::Us104Key as KeyboardLayout>::map_keycode(e, modifiers, handle_ctrl),
298+
e => {
299+
let us = super::Us104Key;
300+
us.map_keycode(e, modifiers, handle_ctrl)
301+
}
298302
}
299303
}
300304
}

src/layouts/dvorak_programmer104.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
//! A Dvorak Programmer 101-key (or 104-key including Windows keys) keyboard.
2-
//! Has a 1-row high Enter key, with Backslash above.
1+
//! Dvorak Programmer keyboard support
32
43
use crate::{DecodedKey, HandleControl, KeyCode, KeyboardLayout, Modifiers};
54

5+
/// A Dvorak Programmer 101-key (or 104-key including Windows keys) keyboard.
6+
///
7+
/// Has a 1-row high Enter key, with Oem7 above (ANSI layout).
68
pub struct DVP104Key;
79

810
impl KeyboardLayout for DVP104Key {
911
fn map_keycode(
12+
&self,
1013
keycode: KeyCode,
1114
modifiers: &Modifiers,
1215
handle_ctrl: HandleControl,

src/layouts/jis109.rs

+10-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
/// A standard Japan 106-key (or 109-key including Windows keys) keyboard.
2-
/// Has a 2-row high Enter key, with Backslash above.
3-
use crate::{DecodedKey, HandleControl, KeyCode, KeyboardLayout, Modifiers};
1+
//! JIS keyboard support
42
5-
pub use super::us104::Us104Key;
3+
use crate::{DecodedKey, HandleControl, KeyCode, KeyboardLayout, Modifiers};
64

5+
/// A standard Japan 106-key (or 109-key including Windows keys) keyboard.
6+
///
7+
/// Has a small space bar, to fit in extra keys.
78
pub struct Jis109Key;
89

910
impl KeyboardLayout for Jis109Key {
1011
fn map_keycode(
12+
&self,
1113
keycode: KeyCode,
1214
modifiers: &Modifiers,
1315
handle_ctrl: HandleControl,
@@ -140,7 +142,10 @@ impl KeyboardLayout for Jis109Key {
140142
DecodedKey::Unicode('^')
141143
}
142144
}
143-
e => <Us104Key as KeyboardLayout>::map_keycode(e, modifiers, handle_ctrl),
145+
e => {
146+
let us = super::Us104Key;
147+
us.map_keycode(e, modifiers, handle_ctrl)
148+
}
144149
}
145150
}
146151
}

0 commit comments

Comments
 (0)