blob: d75f9cdd044b612ad97065b3354b7950c94494e8 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! # Old-style keymaps definitions.
//!
//! The keymaps defined in this module are statically defined and compiled in.
//! This is useful during the transition towards a more configurable keymap
//! support.
use crate::{LockStateChecker, ModifierChecker};
use fidl_fuchsia_ui_input3::{LockState, Modifiers};
use lazy_static::lazy_static;
lazy_static! {
/// Standard [qwerty] keymap.
///
/// The value of this array at index `u`, where `u` is the usage, can be:
///
/// * `None` if the key maps to no `char` (Esc key)
/// * `Some((c, None))` if the key maps to `c`, but does not map to any `char` when shift is pressed
/// * `Some((c, Some(cs)))` if the key maps to `c` when shift is not pressed and to `cs` when it is
/// pressed
///
/// [qwerty]: https://en.wikipedia.org/wiki/Keyboard_layout#QWERTY-based_Latin-script_keyboard_layouts
pub(crate) static ref QWERTY_MAP: Vec<Option<KeyLevels>> = vec![
// 0x00
None,
None,
None,
None,
// HID_USAGE_KEY_A
Some(('a', Some('A'), true).into()),
Some(('b', Some('B'), true).into()),
Some(('c', Some('C'), true).into()),
Some(('d', Some('D'), true).into()),
// 0x08
Some(('e', Some('E'), true).into()),
Some(('f', Some('F'), true).into()),
Some(('g', Some('G'), true).into()),
Some(('h', Some('H'), true).into()),
// 0x0c
Some(('i', Some('I'), true).into()),
Some(('j', Some('J'), true).into()),
Some(('k', Some('K'), true).into()),
Some(('l', Some('L'), true).into()),
// 0x10
Some(('m', Some('M'), true).into()),
Some(('n', Some('N'), true).into()),
Some(('o', Some('O'), true).into()),
Some(('p', Some('P'), true).into()),
// 0x14
Some(('q', Some('Q'), true).into()),
Some(('r', Some('R'), true).into()),
Some(('s', Some('S'), true).into()),
Some(('t', Some('T'), true).into()),
// 0x18
Some(('u', Some('U'), true).into()),
Some(('v', Some('V'), true).into()),
Some(('w', Some('W'), true).into()),
Some(('x', Some('X'), true).into()),
// 0x1c
Some(('y', Some('Y'), true).into()),
Some(('z', Some('Z'), true).into()),
Some(('1', Some('!')).into()),
Some(('2', Some('@')).into()),
// 0x20
Some(('3', Some('#')).into()),
Some(('4', Some('$')).into()),
Some(('5', Some('%')).into()),
Some(('6', Some('^')).into()),
// 0x24
Some(('7', Some('&')).into()),
Some(('8', Some('*')).into()),
Some(('9', Some('(')).into()),
Some(('0', Some(')')).into()),
// 0x28
None,
None,
None,
None,
// 0x2c
Some((' ', Some(' ')).into()),
Some(('-', Some('_')).into()),
Some(('=', Some('+')).into()),
Some(('[', Some('{')).into()),
// 0x30
Some((']', Some('}')).into()),
Some(('\\', Some('|')).into()),
None,
Some((';', Some(':')).into()),
// 0x34
Some(('\'', Some('"')).into()),
Some(('`', Some('~')).into()),
Some((',', Some('<')).into()),
Some(('.', Some('>')).into()),
// 0x38
Some(('/', Some('?')).into()),
None,
None,
None,
// 0x3c
None,
None,
None,
None,
// 0x40
None,
None,
None,
None,
// 0x44
None,
None,
None,
None,
// 0x48
None,
None,
None,
None,
// 0x4c
None,
None,
None,
None,
// 0x50
None,
None,
None,
None,
// 0x54
Some(('/', None).into()),
Some(('*', None).into()),
Some(('-', None).into()),
Some(('+', None).into()),
// 0x58
None,
Some(('1', None).into()),
Some(('2', None).into()),
Some(('3', None).into()),
// 0x5c
Some(('4', None).into()),
Some(('5', None).into()),
Some(('6', None).into()),
Some(('7', None).into()),
// 0x60
Some(('8', None).into()),
Some(('9', None).into()),
Some(('0', None).into()),
Some(('.', None).into()),
];
/// Standard [dvorak] keymap.
///
/// [dvorak]: https://en.wikipedia.org/wiki/Dvorak_keyboard_layout
pub(crate) static ref DVORAK_MAP: Vec<Option<KeyLevels>> = vec![
// 0x00
None,
None,
None,
None,
// HID_USAGE_KEY_A
Some(('a', Some('A'), true).into()),
Some(('x', Some('X'), true).into()),
Some(('j', Some('J'), true).into()),
Some(('e', Some('E'), true).into()),
// 0x08
Some(('.', Some('>')).into()),
Some(('u', Some('U'), true).into()),
Some(('i', Some('I'), true).into()),
Some(('d', Some('D'), true).into()),
// 0x0c
Some(('c', Some('C'), true).into()),
Some(('h', Some('H'), true).into()),
Some(('t', Some('T'), true).into()),
Some(('n', Some('N'), true).into()),
// 0x10
Some(('m', Some('M'), true).into()),
Some(('b', Some('B'), true).into()),
Some(('r', Some('R'), true).into()),
Some(('l', Some('L'), true).into()),
// 0x14
Some(('\'', Some('"')).into()),
Some(('p', Some('P'), true).into()),
Some(('o', Some('O'), true).into()),
Some(('y', Some('Y'), true).into()),
// 0x18
Some(('g', Some('G'), true).into()),
Some(('k', Some('K'), true).into()),
Some((',', Some('<')).into()),
Some(('q', Some('Q'), true).into()),
// 0x1c
Some(('f', Some('F'), true).into()),
Some((';', Some(':')).into()),
Some(('1', Some('!')).into()),
Some(('2', Some('@')).into()),
// 0x20
Some(('3', Some('#')).into()),
Some(('4', Some('$')).into()),
Some(('5', Some('%')).into()),
Some(('6', Some('^')).into()),
// 0x24
Some(('7', Some('&')).into()),
Some(('8', Some('*')).into()),
Some(('9', Some('(')).into()),
Some(('0', Some(')')).into()),
// 0x28
None,
None,
None,
None,
// 0x2c
Some((' ', Some(' ')).into()),
Some(('[', Some('{')).into()),
Some((']', Some('}')).into()),
Some(('/', Some('?')).into()),
// 0x30
Some(('=', Some('+')).into()),
Some(('\\', Some('|')).into()),
None,
Some(('s', Some('S'), true).into()),
// 0x34
Some(('-', Some('_')).into()),
Some(('`', Some('~')).into()),
Some(('w', Some('W'), true).into()),
Some(('v', Some('V'), true).into()),
// 0x38
Some(('z', Some('Z'), true).into()),
None,
None,
None,
// 0x3c
None,
None,
None,
None,
// 0x40
None,
None,
None,
None,
// 0x44
None,
None,
None,
None,
// 0x48
None,
None,
None,
None,
// 0x4c
None,
None,
None,
None,
// 0x50
None,
None,
None,
None,
// 0x54
Some(('/', None).into()),
Some(('*', None).into()),
Some(('-', None).into()),
Some(('+', None).into()),
// 0x58
None,
Some(('1', None).into()),
Some(('2', None).into()),
Some(('3', None).into()),
// 0x5c
Some(('4', None).into()),
Some(('5', None).into()),
Some(('6', None).into()),
Some(('7', None).into()),
// 0x60
Some(('8', None).into()),
Some(('9', None).into()),
Some(('0', None).into()),
Some(('.', None).into()),
];
/// TODO(75723): This map is incomplete, and is here only temporarily for
/// kicks.
pub(crate) static ref FR_AZERTY_MAP: Vec<Option<KeyLevels>> = vec![
// 0x00
None,
None,
None,
None,
// HID_USAGE_KEY_A
Some(('q', Some('Q'), true).into()),
Some(('b', Some('B'), true).into()),
Some(('c', Some('C'), true).into()),
Some(('d', Some('D'), true).into()),
// 0x08
Some(('e', Some('E'), true).into()),
Some(('f', Some('F'), true).into()),
Some(('g', Some('G'), true).into()),
Some(('h', Some('H'), true).into()),
// 0x0c
Some(('i', Some('I'), true).into()),
Some(('j', Some('J'), true).into()),
Some(('k', Some('K'), true).into()),
Some(('l', Some('L'), true).into()),
// 0x10
Some((',', Some('?')).into()),
Some(('n', Some('N'), true).into()),
Some(('o', Some('O'), true).into()),
Some(('p', Some('P'), true).into()),
// 0x14
Some(('a', Some('A'), true).into()),
Some(('r', Some('R'), true).into()),
Some(('s', Some('S'), true).into()),
Some(('t', Some('T'), true).into()),
// 0x18
Some(('u', Some('U'), true).into()),
Some(('v', Some('V'), true).into()),
Some(('z', Some('Z'), true).into()),
Some(('x', Some('X'), true).into()),
// 0x1c
Some(('y', Some('Y'), true).into()),
Some(('w', Some('W'), true).into()),
Some(('&', Some('1')).into()),
Some(('é', Some('2')).into()),
// 0x20
Some(('"', Some('3')).into()),
Some(('\'', Some('4')).into()),
Some(('(', Some('5')).into()),
Some(('-', Some('6')).into()),
// 0x24
Some(('è', Some('7')).into()),
Some(('—', Some('8')).into()),
Some(('ç', Some('9')).into()),
Some(('à', Some('0')).into()),
// 0x28
None,
None,
None,
None,
// 0x2c
Some((' ', Some(' ')).into()),
Some((')', Some('°')).into()),
Some(('=', Some('+')).into()),
Some(('\u{0302}', Some('\u{0308}')).into()), // Unicode combining characters circumflex and dieresis.
// 0x30
Some(('$', Some('£')).into()),
Some(('\\', Some('|')).into()), // Not present on French Azerty?
None,
Some(('m', Some('M'), true).into()),
// 0x34
Some(('\'', Some('"')).into()),
Some(('²', None).into()),
Some((';', Some('.')).into()),
Some((':', Some('/')).into()),
// 0x38
Some(('!', Some('§')).into()),
None,
None,
None,
// 0x3c
None,
None,
None,
None,
// 0x40
None,
None,
None,
None,
// 0x44
None,
None,
None,
None,
// 0x48
None,
None,
None,
None,
// 0x4c
None,
None,
None,
None,
// 0x50
None,
None,
None,
None,
// 0x54
Some(('/', None).into()),
Some(('*', None).into()),
Some(('-', None).into()),
Some(('+', None).into()),
// 0x58
None,
Some(('1', None).into()),
Some(('2', None).into()),
Some(('3', None).into()),
// 0x5c
Some(('4', None).into()),
Some(('5', None).into()),
Some(('6', None).into()),
Some(('7', None).into()),
// 0x60
Some(('8', None).into()),
Some(('9', None).into()),
Some(('0', None).into()),
Some(('.', None).into()),
];
/// Standard [colemak] keymap.
///
/// [colemak]: https://en.wikipedia.org/wiki/Keyboard_layout#Colemak
pub(crate) static ref COLEMAK_MAP: Vec<Option<KeyLevels>> = vec![
// 0x00
None,
None,
None,
None,
// HID_USAGE_KEY_A
Some(('a', Some('A'), true).into()),
Some(('b', Some('B'), true).into()),
Some(('c', Some('C'), true).into()),
Some(('s', Some('S'), true).into()),
// 0x08
Some(('f', Some('F'), true).into()),
Some(('t', Some('T'), true).into()),
Some(('d', Some('D'), true).into()),
Some(('h', Some('H'), true).into()),
// 0x0c
Some(('u', Some('U'), true).into()),
Some(('n', Some('N'), true).into()),
Some(('e', Some('E'), true).into()),
Some(('i', Some('I'), true).into()),
// 0x10
Some(('m', Some('M'), true).into()),
Some(('k', Some('K'), true).into()),
Some(('y', Some('Y'), true).into()),
Some((';', Some(':')).into()),
// 0x14
Some(('q', Some('Q'), true).into()),
Some(('p', Some('P'), true).into()),
Some(('r', Some('R'), true).into()),
Some(('g', Some('G'), true).into()),
// 0x18
Some(('l', Some('L'), true).into()),
Some(('v', Some('V'), true).into()),
Some(('w', Some('W'), true).into()),
Some(('x', Some('X'), true).into()),
// 0x1c
Some(('j', Some('J'), true).into()),
Some(('z', Some('Z'), true).into()),
Some(('1', Some('!')).into()),
Some(('2', Some('@')).into()),
// 0x20
Some(('3', Some('#')).into()),
Some(('4', Some('$')).into()),
Some(('5', Some('%')).into()),
Some(('6', Some('^')).into()),
// 0x24
Some(('7', Some('&')).into()),
Some(('8', Some('*')).into()),
Some(('9', Some('(')).into()),
Some(('0', Some(')')).into()),
// 0x28
None,
None,
None,
None,
// 0x2c
Some((' ', Some(' ')).into()),
Some(('-', Some('_')).into()),
Some(('=', Some('+')).into()),
Some(('[', Some('{')).into()),
// 0x30
Some((']', Some('}')).into()),
Some(('\\', Some('|')).into()),
None,
Some(('o', Some('O'), true).into()),
// 0x34
Some(('\'', Some('"')).into()),
Some(('`', Some('~')).into()),
Some((',', Some('<')).into()),
Some(('.', Some('>')).into()),
// 0x38
Some(('/', Some('?')).into()),
None,
None,
None,
// 0x3c
None,
None,
None,
None,
// 0x40
None,
None,
None,
None,
// 0x44
None,
None,
None,
None,
// 0x48
None,
None,
None,
None,
// 0x4c
None,
None,
None,
None,
// 0x50
None,
None,
None,
None,
// 0x54
Some(('/', None).into()),
Some(('*', None).into()),
Some(('-', None).into()),
Some(('+', None).into()),
// 0x58
None,
Some(('1', None).into()),
Some(('2', None).into()),
Some(('3', None).into()),
// 0x5c
Some(('4', None).into()),
Some(('5', None).into()),
Some(('6', None).into()),
Some(('7', None).into()),
// 0x60
Some(('8', None).into()),
Some(('9', None).into()),
Some(('0', None).into()),
Some(('.', None).into()),
];
}
/// Levels corresponding to each defined key.
pub struct KeyLevels {
/// The base, unshifted character.
pub(crate) ch: char,
/// The shifted character, if present
pub(crate) shift_ch: Option<char>,
/// Is it a letter? Letters are affected by Caps Lock, while other keys
/// are not.
is_letter: bool,
}
impl From<(char, Option<char>)> for KeyLevels {
fn from(s: (char, Option<char>)) -> Self {
KeyLevels { ch: s.0, shift_ch: s.1, is_letter: false }
}
}
impl From<(char, Option<char>, bool)> for KeyLevels {
fn from(s: (char, Option<char>, bool)) -> Self {
KeyLevels { ch: s.0, shift_ch: s.1, is_letter: s.2 }
}
}
impl KeyLevels {
pub fn get_key(&self, m: &impl ModifierChecker, l: &impl LockStateChecker) -> Option<char> {
if (l.test(LockState::CAPS_LOCK) && self.is_letter) || m.test(Modifiers::SHIFT) {
return self.shift_ch;
}
Some(self.ch)
}
}