pc-keyboard 0.9.0

PS/2 keyboard interface library.
Documentation
//! United Kingdom keyboard support

use crate::{
    DecodedKey, HandleControl, KeyCode, KeyboardLayout, Modifiers, PhysicalKeyboard, QUO, SLS,
};

/// A standard United Kingdom 102-key (or 105-key including Windows keys) keyboard.
///
/// Has a 2-row high Enter key, with Oem5 next to the left shift (ISO format).
///
/// Based on US 101/104 key, with minor changes.
///
/// These diagrams illustrate the conversion from [`KeyCode`] to Unicode. We
/// show either a Unicode glyph, or a hex number if the glyph isn't a
/// printable character. Blank spaces are passed through as
/// [`DecodedKey::RawKey`].
///
/// Run the `print_keyboard` example to re-generate these images.
///
/// ## Unmodified
///
/// ```text
/// ┌────┐  ┌────┬────┬────┬────┐  ┌────┬────┬────┬────┐  ┌────┬────┬────┬────┐   ┌────┬────┬────┐
/// │001b│  │    │    │    │    │  │    │    │    │    │  │    │    │    │    │   │    │    │    │
/// └────┘  └────┴────┴────┴────┘  └────┴────┴────┴────┘  └────┴────┴────┴────┘   └────┴────┴────┘
///
/// ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬─────────┐  ┌────┬────┬────┐  ┌────┬────┬────┬────┐
/// │ `  │ 1  │ 2  │ 3  │ 4  │ 5  │ 6  │ 7  │ 8  │ 9  │ 0  │ -  │ =  │   0008  │  │    │    │    │  │    │ /  │ *  │ -  │
/// ├────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬────────┤  ├────┼────┼────┤  ├────┼────┼────┼────┤
/// │0009 │ q  │ w  │ e  │ r  │ t  │ y  │ u  │ i  │ o  │ p  │ [  │ ]  │  000a  │  │007f│    │    │  │ 7  │ 8  │ 9  │    │
/// ├─────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┐       │  └────┴────┴────┘  ├────┼────┼────┤ +  │
/// │      │ a  │ s  │ d  │ f  │ g  │ h  │ j  │ k  │ l  │ ;  │ '  │ #  │       │                    │ 4  │ 5  │ 6  │    │
/// ├────┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴────┴───────┤       ┌────┐       ├────┼────┼────┼────┤
/// │    │ \  │ z  │ x  │ c  │ v  │ b  │ n  │ m  │ ,  │ .  │ /  │              │       │    │       │ 1  │ 2  │ 3  │    │
/// ├────┴┬───┴─┬──┴──┬─┴────┴────┴────┴────┴────┴───┬┴────┼────┴┬──────┬──────┤  ┌────┼────┼────┐  ├────┴────┼────┤000a│
/// │     │     │     │             0020             │     │     │      │      │  │    │    │    │  │ 0       │ .  │    │
/// └─────┴─────┴─────┴──────────────────────────────┴─────┴─────┴──────┴──────┘  └────┴────┴────┘  └─────────┴────┴────┘
/// ```
///
/// ## Caps Lock
///
/// ```text
/// ┌────┐  ┌────┬────┬────┬────┐  ┌────┬────┬────┬────┐  ┌────┬────┬────┬────┐   ┌────┬────┬────┐
/// │001b│  │    │    │    │    │  │    │    │    │    │  │    │    │    │    │   │    │    │    │
/// └────┘  └────┴────┴────┴────┘  └────┴────┴────┴────┘  └────┴────┴────┴────┘   └────┴────┴────┘
///
/// ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬─────────┐  ┌────┬────┬────┐  ┌────┬────┬────┬────┐
/// │ `  │ 1  │ 2  │ 3  │ 4  │ 5  │ 6  │ 7  │ 8  │ 9  │ 0  │ -  │ =  │   0008  │  │    │    │    │  │    │ /  │ *  │ -  │
/// ├────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬────────┤  ├────┼────┼────┤  ├────┼────┼────┼────┤
/// │0009 │ Q  │ W  │ E  │ R  │ T  │ Y  │ U  │ I  │ O  │ P  │ [  │ ]  │  000a  │  │007f│    │    │  │ 7  │ 8  │ 9  │    │
/// ├─────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┐       │  └────┴────┴────┘  ├────┼────┼────┤ +  │
/// │      │ A  │ S  │ D  │ F  │ G  │ H  │ J  │ K  │ L  │ ;  │ '  │ #  │       │                    │ 4  │ 5  │ 6  │    │
/// ├────┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴────┴───────┤       ┌────┐       ├────┼────┼────┼────┤
/// │    │ \  │ Z  │ X  │ C  │ V  │ B  │ N  │ M  │ ,  │ .  │ /  │              │       │    │       │ 1  │ 2  │ 3  │    │
/// ├────┴┬───┴─┬──┴──┬─┴────┴────┴────┴────┴────┴───┬┴────┼────┴┬──────┬──────┤  ┌────┼────┼────┐  ├────┴────┼────┤000a│
/// │     │     │     │             0020             │     │     │      │      │  │    │    │    │  │ 0       │ .  │    │
/// └─────┴─────┴─────┴──────────────────────────────┴─────┴─────┴──────┴──────┘  └────┴────┴────┘  └─────────┴────┴────┘
/// ```
///
/// ## Shifted
///
/// ```text
/// ┌────┐  ┌────┬────┬────┬────┐  ┌────┬────┬────┬────┐  ┌────┬────┬────┬────┐   ┌────┬────┬────┐
/// │001b│  │    │    │    │    │  │    │    │    │    │  │    │    │    │    │   │    │    │    │
/// └────┘  └────┴────┴────┴────┘  └────┴────┴────┴────┘  └────┴────┴────┴────┘   └────┴────┴────┘
///
/// ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬─────────┐  ┌────┬────┬────┐  ┌────┬────┬────┬────┐
/// │ ¬  │ !  │ "  │ £  │ $  │ %  │ ^  │ &  │ *  │ (  │ )  │ _  │ +  │   0008  │  │    │    │    │  │    │ /  │ *  │ -  │
/// ├────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬────────┤  ├────┼────┼────┤  ├────┼────┼────┼────┤
/// │0009 │ Q  │ W  │ E  │ R  │ T  │ Y  │ U  │ I  │ O  │ P  │ {  │ }  │  000a  │  │007f│    │    │  │ 7  │ 8  │ 9  │    │
/// ├─────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┐       │  └────┴────┴────┘  ├────┼────┼────┤ +  │
/// │      │ A  │ S  │ D  │ F  │ G  │ H  │ J  │ K  │ L  │ :  │ @  │ ~  │       │                    │ 4  │ 5  │ 6  │    │
/// ├────┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴────┴───────┤       ┌────┐       ├────┼────┼────┼────┤
/// │    │ |  │ Z  │ X  │ C  │ V  │ B  │ N  │ M  │ <  │ >  │ ?  │              │       │    │       │ 1  │ 2  │ 3  │    │
/// ├────┴┬───┴─┬──┴──┬─┴────┴────┴────┴────┴────┴───┬┴────┼────┴┬──────┬──────┤  ┌────┼────┼────┐  ├────┴────┼────┤000a│
/// │     │     │     │             0020             │     │     │      │      │  │    │    │    │  │ 0       │ .  │    │
/// └─────┴─────┴─────┴──────────────────────────────┴─────┴─────┴──────┴──────┘  └────┴────┴────┘  └─────────┴────┴────┘
/// ```
///
/// ## Control
///
/// ```text
/// ┌────┐  ┌────┬────┬────┬────┐  ┌────┬────┬────┬────┐  ┌────┬────┬────┬────┐   ┌────┬────┬────┐
/// │001b│  │    │    │    │    │  │    │    │    │    │  │    │    │    │    │   │    │    │    │
/// └────┘  └────┴────┴────┴────┘  └────┴────┴────┴────┘  └────┴────┴────┴────┘   └────┴────┴────┘
///
/// ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬─────────┐  ┌────┬────┬────┐  ┌────┬────┬────┬────┐
/// │ `  │ 1  │ 2  │ 3  │ 4  │ 5  │ 6  │ 7  │ 8  │ 9  │ 0  │ -  │ =  │   0008  │  │    │    │    │  │    │ /  │ *  │ -  │
/// ├────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬────────┤  ├────┼────┼────┤  ├────┼────┼────┼────┤
/// │0009 │0011│0017│0005│0012│0014│0019│0015│0009│000f│0010│ [  │ ]  │  000a  │  │007f│    │    │  │ 7  │ 8  │ 9  │    │
/// ├─────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┐       │  └────┴────┴────┘  ├────┼────┼────┤ +  │
/// │      │0001│0013│0004│0006│0007│0008│000a│000b│000c│ ;  │ '  │ #  │       │                    │ 4  │ 5  │ 6  │    │
/// ├────┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴────┴───────┤       ┌────┐       ├────┼────┼────┼────┤
/// │    │ \  │001a│0018│0003│0016│0002│000e│000d│ ,  │ .  │ /  │              │       │    │       │ 1  │ 2  │ 3  │    │
/// ├────┴┬───┴─┬──┴──┬─┴────┴────┴────┴────┴────┴───┬┴────┼────┴┬──────┬──────┤  ┌────┼────┼────┐  ├────┴────┼────┤000a│
/// │     │     │     │             0020             │     │     │      │      │  │    │    │    │  │ 0       │ .  │    │
/// └─────┴─────┴─────┴──────────────────────────────┴─────┴─────┴──────┴──────┘  └────┴────┴────┘  └─────────┴────┴────┘
/// ```
///
/// ## AltGr
///
/// ```text
/// ┌────┐  ┌────┬────┬────┬────┐  ┌────┬────┬────┬────┐  ┌────┬────┬────┬────┐   ┌────┬────┬────┐
/// │001b│  │    │    │    │    │  │    │    │    │    │  │    │    │    │    │   │    │    │    │
/// └────┘  └────┴────┴────┴────┘  └────┴────┴────┴────┘  └────┴────┴────┴────┘   └────┴────┴────┘
///
/// ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬─────────┐  ┌────┬────┬────┐  ┌────┬────┬────┬────┐
/// │ ¦  │ 1  │ 2  │ 3  │ €  │ 5  │ 6  │ 7  │ 8  │ 9  │ 0  │ -  │ =  │   0008  │  │    │    │    │  │    │ /  │ *  │ -  │
/// ├────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬────────┤  ├────┼────┼────┤  ├────┼────┼────┼────┤
/// │0009 │ q  │ w  │ é  │ r  │ t  │ y  │ ú  │ í  │ ó  │ p  │ [  │ ]  │  000a  │  │007f│    │    │  │ 7  │ 8  │ 9  │    │
/// ├─────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┐       │  └────┴────┴────┘  ├────┼────┼────┤ +  │
/// │      │ á  │ s  │ d  │ f  │ g  │ h  │ j  │ k  │ l  │ ;  │ '  │ #  │       │                    │ 4  │ 5  │ 6  │    │
/// ├────┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴────┴───────┤       ┌────┐       ├────┼────┼────┼────┤
/// │    │ \  │ z  │ x  │ c  │ v  │ b  │ n  │ m  │ ,  │ .  │ /  │              │       │    │       │ 1  │ 2  │ 3  │    │
/// ├────┴┬───┴─┬──┴──┬─┴────┴────┴────┴────┴────┴───┬┴────┼────┴┬──────┬──────┤  ┌────┼────┼────┐  ├────┴────┼────┤000a│
/// │     │     │     │             0020             │     │     │      │      │  │    │    │    │  │ 0       │ .  │    │
/// └─────┴─────┴─────┴──────────────────────────────┴─────┴─────┴──────┴──────┘  └────┴────┴────┘  └─────────┴────┴────┘
/// ```
///
/// ## Shift AltGr
///
/// ```text
/// ┌────┐  ┌────┬────┬────┬────┐  ┌────┬────┬────┬────┐  ┌────┬────┬────┬────┐   ┌────┬────┬────┐
/// │001b│  │    │    │    │    │  │    │    │    │    │  │    │    │    │    │   │    │    │    │
/// └────┘  └────┴────┴────┴────┘  └────┴────┴────┴────┘  └────┴────┴────┴────┘   └────┴────┴────┘
///
/// ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬─────────┐  ┌────┬────┬────┐  ┌────┬────┬────┬────┐
/// │ ¦  │ !  │ "  │ £  │ €  │ %  │ ^  │ &  │ *  │ (  │ )  │ _  │ +  │   0008  │  │    │    │    │  │    │ /  │ *  │ -  │
/// ├────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬────────┤  ├────┼────┼────┤  ├────┼────┼────┼────┤
/// │0009 │ Q  │ W  │ É  │ R  │ T  │ Y  │ Ú  │ Í  │ Ó  │ P  │ {  │ }  │  000a  │  │007f│    │    │  │ 7  │ 8  │ 9  │    │
/// ├─────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┐       │  └────┴────┴────┘  ├────┼────┼────┤ +  │
/// │      │ Á  │ S  │ D  │ F  │ G  │ H  │ J  │ K  │ L  │ :  │ @  │ ~  │       │                    │ 4  │ 5  │ 6  │    │
/// ├────┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴────┴───────┤       ┌────┐       ├────┼────┼────┼────┤
/// │    │ |  │ Z  │ X  │ C  │ V  │ B  │ N  │ M  │ <  │ >  │ ?  │              │       │    │       │ 1  │ 2  │ 3  │    │
/// ├────┴┬───┴─┬──┴──┬─┴────┴────┴────┴────┴────┴───┬┴────┼────┴┬──────┬──────┤  ┌────┼────┼────┐  ├────┴────┼────┤000a│
/// │     │     │     │             0020             │     │     │      │      │  │    │    │    │  │ 0       │ .  │    │
/// └─────┴─────┴─────┴──────────────────────────────┴─────┴─────┴──────┴──────┘  └────┴────┴────┘  └─────────┴────┴────┘
/// ```
pub struct Uk105Key;

impl KeyboardLayout for Uk105Key {
    #[rustfmt::skip]
    fn map_keycode(
        &self,
        keycode: KeyCode,
        modifiers: &Modifiers,
        handle_ctrl: HandleControl,
    ) -> DecodedKey {
        match keycode {
            KeyCode::Key2 => modifiers.handle_symbol2('2', '"'),
            KeyCode::Key3 => modifiers.handle_symbol2('3', '£'),
            KeyCode::Key4 => modifiers.handle_symbol3('4', '$', ''),
            KeyCode::Oem3 => modifiers.handle_symbol2(QUO, '@'),
            KeyCode::Oem5 => modifiers.handle_symbol2(SLS, '|'),
            KeyCode::Oem7 => modifiers.handle_symbol2('#', '~'),
            KeyCode::Oem8 => modifiers.handle_symbol3('`', '¬', '¦'),
            KeyCode::E    => modifiers.handle_ascii_4('E', 'é', 'É', handle_ctrl),
            KeyCode::U    => modifiers.handle_ascii_4('U', 'ú', 'Ú', handle_ctrl),
            KeyCode::I    => modifiers.handle_ascii_4('I', 'í', 'Í', handle_ctrl),
            KeyCode::O    => modifiers.handle_ascii_4('O', 'ó', 'Ó', handle_ctrl),
            KeyCode::A    => modifiers.handle_ascii_4('A', 'á', 'Á', handle_ctrl),
            e => super::Us104Key.map_keycode(e, modifiers, handle_ctrl),
        }
    }

    fn get_physical(&self) -> PhysicalKeyboard {
        PhysicalKeyboard::Iso
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::{
        EventDecoder, HandleControl, PS2Keyboard, ScancodeSet, ScancodeSet1, ScancodeSet2,
    };

    #[test]
    fn layout() {
        // Codes taken from https://kbdlayout.info/kbduk/overview+scancodes?arrangement=ISO105
        let mut s = ScancodeSet1::new();
        let mut dec = EventDecoder::new(Uk105Key, HandleControl::Ignore);
        let data = [
            (0x29, '`'),
            (0x02, '1'),
            (0x03, '2'),
            (0x04, '3'),
            (0x05, '4'),
            (0x06, '5'),
            (0x07, '6'),
            (0x08, '7'),
            (0x09, '8'),
            (0x0a, '9'),
            (0x0b, '0'),
            (0x0c, '-'),
            (0x0d, '='),
            (0x0f, '\t'),
            (0x10, 'q'),
            (0x11, 'w'),
            (0x12, 'e'),
            (0x13, 'r'),
            (0x14, 't'),
            (0x15, 'y'),
            (0x16, 'u'),
            (0x17, 'i'),
            (0x18, 'o'),
            (0x19, 'p'),
            (0x1a, '['),
            (0x1b, ']'),
            (0x1e, 'a'),
            (0x1f, 's'),
            (0x20, 'd'),
            (0x21, 'f'),
            (0x22, 'g'),
            (0x23, 'h'),
            (0x24, 'j'),
            (0x25, 'k'),
            (0x26, 'l'),
            (0x27, ';'),
            (0x28, '\''),
            (0x2B, '#'),
            (0x1c, '\n'),
            (0x56, '\\'),
            (0x2c, 'z'),
            (0x2d, 'x'),
            (0x2e, 'c'),
            (0x2f, 'v'),
            (0x30, 'b'),
            (0x31, 'n'),
            (0x32, 'm'),
            (0x33, ','),
            (0x34, '.'),
            (0x35, '/'),
        ];
        for (code, unicode) in data {
            let ev = s.advance_state(code).unwrap().unwrap();
            assert_eq!(Some(DecodedKey::Unicode(unicode)), dec.process_keyevent(ev));
        }
    }

    #[test]
    fn test_hash() {
        let mut k = PS2Keyboard::new(
            ScancodeSet2::new(),
            Uk105Key,
            HandleControl::MapLettersToUnicode,
        );
        // As seen on a UK 105 key Dell PS/2 keyboard when pressing `~#`
        let ev = k.add_byte(0x5D).unwrap().unwrap();
        let decoded_key = k.process_keyevent(ev);
        assert_eq!(decoded_key, Some(DecodedKey::Unicode('#')));
    }

    #[test]
    fn test_backslash() {
        let mut k = PS2Keyboard::new(
            ScancodeSet2::new(),
            Uk105Key,
            HandleControl::MapLettersToUnicode,
        );
        // As seen on a UK 105 key Dell PS/2 keyboard when pressing `|\`
        let ev = k.add_byte(0x61).unwrap().unwrap();
        let decoded_key = k.process_keyevent(ev);
        assert_eq!(decoded_key, Some(DecodedKey::Unicode('\\')));
    }

    #[test]
    fn test_tilde() {
        let mut k = PS2Keyboard::new(
            ScancodeSet2::new(),
            Uk105Key,
            HandleControl::MapLettersToUnicode,
        );
        // As seen on a UK 105 key Dell PS/2 keyboard when pressing Shift and `~#`
        let ev = k.add_byte(0x12).unwrap().unwrap();
        let _ = k.process_keyevent(ev);
        let ev = k.add_byte(0x5D).unwrap().unwrap();
        let decoded_key = k.process_keyevent(ev);
        assert_eq!(decoded_key, Some(DecodedKey::Unicode('~')));
    }

    #[test]
    fn test_pipe() {
        let mut k = PS2Keyboard::new(
            ScancodeSet2::new(),
            Uk105Key,
            HandleControl::MapLettersToUnicode,
        );
        // As seen on a UK 105 key Dell PS/2 keyboard when pressing Shift and `|\`
        let ev = k.add_byte(0x12).unwrap().unwrap();
        let _ = k.process_keyevent(ev);
        let ev = k.add_byte(0x61).unwrap().unwrap();
        let decoded_key = k.process_keyevent(ev);
        assert_eq!(decoded_key, Some(DecodedKey::Unicode('|')));
    }
}