Map USB keyboards using us layout

This commit is contained in:
Jeremy Soller
2022-04-11 20:28:44 -06:00
parent 8e1f91137e
commit 220e13c2d6
2 changed files with 647 additions and 17 deletions
+478
View File
@@ -0,0 +1,478 @@
pub mod us {
static US: [[char; 2]; 58] = [
['\0', '\0'],
['\x1B', '\x1B'],
['1', '!'],
['2', '@'],
['3', '#'],
['4', '$'],
['5', '%'],
['6', '^'],
['7', '&'],
['8', '*'],
['9', '('],
['0', ')'],
['-', '_'],
['=', '+'],
['\x7F', '\x7F'],
['\t', '\t'],
['q', 'Q'],
['w', 'W'],
['e', 'E'],
['r', 'R'],
['t', 'T'],
['y', 'Y'],
['u', 'U'],
['i', 'I'],
['o', 'O'],
['p', 'P'],
['[', '{'],
[']', '}'],
['\n', '\n'],
['\0', '\0'],
['a', 'A'],
['s', 'S'],
['d', 'D'],
['f', 'F'],
['g', 'G'],
['h', 'H'],
['j', 'J'],
['k', 'K'],
['l', 'L'],
[';', ':'],
['\'', '"'],
['`', '~'],
['\0', '\0'],
['\\', '|'],
['z', 'Z'],
['x', 'X'],
['c', 'C'],
['v', 'V'],
['b', 'B'],
['n', 'N'],
['m', 'M'],
[',', '<'],
['.', '>'],
['/', '?'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
[' ', ' ']
];
pub fn get_char(scancode: u8, shift: bool) -> char {
if let Some(c) = US.get(scancode as usize) {
if shift {
c[1]
} else {
c[0]
}
} else {
'\0'
}
}
}
pub mod gb {
static GB: [[char; 2]; 87] = [
['\0', '\0'],
['\x1B', '\x1B'],
['1', '!'],
['2', '"'],
['3', '£'],
['4', '$'],
['5', '%'],
['6', '^'],
['7', '&'],
['8', '*'],
['9', '('],
['0', ')'],
['-', '_'],
['=', '+'],
['\x7F', '\x7F'],
['\t', '\t'],
['q', 'Q'],
['w', 'W'],
['e', 'E'],
['r', 'R'],
['t', 'T'],
['y', 'Y'],
['u', 'U'],
['i', 'I'],
['o', 'O'],
['p', 'P'],
['[', '{'],
[']', '}'],
['\n', '\n'],
['\0', '\0'],
['a', 'A'],
['s', 'S'],
['d', 'D'],
['f', 'F'],
['g', 'G'],
['h', 'H'],
['j', 'J'],
['k', 'K'],
['l', 'L'],
[';', ':'],
['\'', '@'],
['`', '¬'],
['\0', '\0'],
['#', '~'],
['z', 'Z'],
['x', 'X'],
['c', 'C'],
['v', 'V'],
['b', 'B'],
['n', 'N'],
['m', 'M'],
[',', '<'],
['.', '>'],
['/', '?'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
[' ', ' '],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
['\\', '|'],
];
pub fn get_char(scancode: u8, shift: bool) -> char {
if let Some(c) = GB.get(scancode as usize) {
if shift {
c[1]
} else {
c[0]
}
} else {
'\0'
}
}
}
pub mod dvorak {
static DVORAK: [[char; 2]; 58] = [
['\0', '\0'],
['\x1B', '\x1B'],
['1', '!'],
['2', '@'],
['3', '#'],
['4', '$'],
['5', '%'],
['6', '^'],
['7', '&'],
['8', '*'],
['9', '('],
['0', ')'],
['[', '{'],
[']', '}'],
['\x7F', '\x7F'],
['\t', '\t'],
['\'', '"'],
[',', '<'],
['.', '>'],
['p', 'P'],
['y', 'Y'],
['f', 'F'],
['g', 'G'],
['c', 'C'],
['r', 'R'],
['l', 'L'],
['/', '?'],
['=', '+'],
['\n', '\n'],
['\0', '\0'],
['a', 'A'],
['o', 'O'],
['e', 'E'],
['u', 'U'],
['i', 'I'],
['d', 'D'],
['h', 'H'],
['t', 'T'],
['n', 'N'],
['s', 'S'],
['-', '_'],
['`', '~'],
['\0', '\0'],
['\\', '|'],
[';', ':'],
['q', 'Q'],
['j', 'J'],
['k', 'K'],
['x', 'X'],
['b', 'B'],
['m', 'M'],
['w', 'W'],
['v', 'V'],
['z', 'Z'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
[' ', ' ']
];
pub fn get_char(scancode: u8, shift: bool) -> char {
if let Some(c) = DVORAK.get(scancode as usize) {
if shift {
c[1]
} else {
c[0]
}
} else {
'\0'
}
}
}
pub mod azerty {
static AZERTY: [[char; 2]; 58] = [
['\0', '\0'],
['\x1B', '\x1B'],
['&', '1'],
['é', '2'],
['"', '3'],
['\'', '4'],
['(', '5'],
['|', '6'],
['è', '7'],
['_', '8'],
['ç', '9'],
['à', '0'],
[')', '°'],
['=', '+'],
['\x7F', '\x7F'],
['\t', '\t'],
['a', 'A'],
['z', 'Z'],
['e', 'E'],
['r', 'R'],
['t', 'T'],
['y', 'Y'],
['u', 'U'],
['i', 'I'],
['o', 'O'],
['p', 'P'],
['^', '¨'],
['$', '£'],
['\n', '\n'],
['\0', '\0'],
['q', 'Q'],
['s', 'S'],
['d', 'D'],
['f', 'F'],
['g', 'G'],
['h', 'H'],
['j', 'J'],
['k', 'K'],
['l', 'L'],
['m', 'M'],
['ù', '%'],
['*', 'µ'],
['\0', '\0'],
['ê', 'Ê'],
['w', 'W'],
['x', 'X'],
['c', 'C'],
['v', 'V'],
['b', 'B'],
['n', 'N'],
[',', '?'],
[';', '.'],
[':', '/'],
['!', '§'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
[' ', ' ']
];
pub fn get_char(scancode: u8, shift: bool) -> char {
if let Some(c) = AZERTY.get(scancode as usize) {
if shift {
c[1]
} else {
c[0]
}
} else {
'\0'
}
}
}
pub mod bepo {
static BEPO: [[char; 2]; 58] = [
['\0', '\0'],
['\x1B', '\x1B'],
['"', '1'],
['«', '2'],
['»', '3'],
['(', '4'],
[')', '5'],
['@', '6'],
['+', '7'],
['-', '8'],
['/', '9'],
['*', '0'],
['=', '°'],
['%', '`'],
['\x7F', '\x7F'],
['\t', '\t'],
['b', 'B'],
['é', 'É'],
['p', 'P'],
['o', 'O'],
['è', 'È'],
['^', '!'],
['v', 'V'],
['d', 'D'],
['l', 'L'],
['j', 'J'],
['z', 'Z'],
['w', 'W'],
['\n', '\n'],
['\0', '\0'],
['a', 'A'],
['u', 'U'],
['i', 'I'],
['e', 'E'],
[',', ';'],
['c', 'C'],
['t', 'T'],
['s', 'S'],
['r', 'R'],
['n', 'N'],
['m', 'M'],
['ç', 'Ç'],
['\0', '\0'],
['ê', 'Ê'],
['à', 'À'],
['y', 'Y'],
['x', 'X'],
['.', ':'],
['k', 'K'],
['\'', '?'],
['q', 'Q'],
['g', 'G'],
['h', 'H'],
['f', 'F'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
[' ', ' ']
];
pub fn get_char(scancode: u8, shift: bool) -> char {
if let Some(c) = BEPO.get(scancode as usize) {
if shift {
c[1]
} else {
c[0]
}
} else {
'\0'
}
}
}
pub mod it {
static IT: [[char; 2]; 58] = [
['\0', '\0'],
['\x1B', '\x1B'],
['1', '!'],
['2', '"'],
['3', '£'],
['4', '$'],
['5', '%'],
['6', '&'],
['7', '/'],
['8', '('],
['9', ')'],
['0', '='],
['?', '\''],
['ì', '^'],
['\x7F', '\x7F'],
['\t', '\t'],
['q', 'Q'],
['w', 'W'],
['e', 'E'],
['r', 'R'],
['t', 'T'],
['y', 'Y'],
['u', 'U'],
['i', 'I'],
['o', 'O'],
['p', 'P'],
['è', 'é'],
['+', '*'],
['\n', '\n'],
['\x20', '\x20'],
['a', 'A'],
['s', 'S'],
['d', 'D'],
['f', 'F'],
['g', 'G'],
['h', 'H'],
['j', 'J'],
['k', 'K'],
['l', 'L'],
['ò', 'ç'],
['à', '°'],
['ù', '§'],
['\0', '\0'],
['<', '>'],
['z', 'Z'],
['x', 'X'],
['c', 'C'],
['v', 'V'],
['b', 'B'],
['n', 'N'],
['m', 'M'],
[',', ';'],
['.', ':'],
['-', '_'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
[' ', ' ']
];
pub fn get_char(scancode: u8, shift: bool) -> char {
if let Some(c) = IT.get(scancode as usize) {
if shift {
c[1]
} else {
c[0]
}
} else {
'\0'
}
}
}
+169 -17
View File
@@ -6,6 +6,7 @@ use orbclient::KeyEvent as OrbKeyEvent;
use redox_log::{OutputBuilder, RedoxLogger};
use xhcid_interface::{ConfigureEndpointsReq, DevDesc, PortReqRecipient, XhciClientHandle};
mod keymap;
mod report_desc;
mod reqs;
mod usage_tables;
@@ -105,6 +106,144 @@ fn setup_logging() -> Option<&'static RedoxLogger> {
}
}
fn send_key_event(usage_page: u32, usage: u8, pressed: bool, shift_opt: Option<bool>) {
let scancode = match usage_page {
0x07 => match usage {
0x04 => orbclient::K_A,
0x05 => orbclient::K_B,
0x06 => orbclient::K_C,
0x07 => orbclient::K_D,
0x08 => orbclient::K_E,
0x09 => orbclient::K_F,
0x0A => orbclient::K_G,
0x0B => orbclient::K_H,
0x0C => orbclient::K_I,
0x0D => orbclient::K_J,
0x0E => orbclient::K_K,
0x0F => orbclient::K_L,
0x10 => orbclient::K_M,
0x11 => orbclient::K_N,
0x12 => orbclient::K_O,
0x13 => orbclient::K_P,
0x14 => orbclient::K_Q,
0x15 => orbclient::K_R,
0x16 => orbclient::K_S,
0x17 => orbclient::K_T,
0x18 => orbclient::K_U,
0x19 => orbclient::K_V,
0x1A => orbclient::K_W,
0x1B => orbclient::K_X,
0x1C => orbclient::K_Y,
0x1D => orbclient::K_Z,
0x1E => orbclient::K_1,
0x1F => orbclient::K_2,
0x20 => orbclient::K_3,
0x21 => orbclient::K_4,
0x22 => orbclient::K_5,
0x23 => orbclient::K_6,
0x24 => orbclient::K_7,
0x25 => orbclient::K_8,
0x26 => orbclient::K_9,
0x27 => orbclient::K_0,
0x28 => orbclient::K_ENTER,
0x29 => orbclient::K_ESC,
0x2A => orbclient::K_BKSP,
0x2B => orbclient::K_TAB,
0x2C => orbclient::K_SPACE,
0x2D => orbclient::K_MINUS,
0x2E => orbclient::K_EQUALS,
0x2F => orbclient::K_BRACE_OPEN,
0x30 => orbclient::K_BRACE_CLOSE,
0x31 => orbclient::K_BACKSLASH,
// 0x32 non-us # and ~
0x33 => orbclient::K_SEMICOLON,
0x34 => orbclient::K_QUOTE,
0x35 => orbclient::K_TICK,
0x36 => orbclient::K_COMMA,
0x37 => orbclient::K_PERIOD,
0x38 => orbclient::K_SLASH,
0x39 => orbclient::K_CAPS,
0x3A => orbclient::K_F1,
0x3B => orbclient::K_F2,
0x3C => orbclient::K_F3,
0x3D => orbclient::K_F4,
0x3E => orbclient::K_F5,
0x3F => orbclient::K_F6,
0x40 => orbclient::K_F7,
0x41 => orbclient::K_F8,
0x42 => orbclient::K_F9,
0x43 => orbclient::K_F10,
0x44 => orbclient::K_F11,
0x45 => orbclient::K_F12,
// 0x46 print screen
// 0x47 scroll lock
// 0x48 pause
// 0x49 insert
0x4A => orbclient::K_HOME,
0x4B => orbclient::K_PGUP,
0x4C => orbclient::K_DEL,
0x4D => orbclient::K_END,
0x4E => orbclient::K_PGDN,
0x4F => orbclient::K_RIGHT,
0x50 => orbclient::K_LEFT,
0x51 => orbclient::K_DOWN,
0x52 => orbclient::K_UP,
// 0x53 num lock
// 0x54 num /
// 0x55 num *
// 0x56 num -
// 0x57 num +
// 0x58 num enter
0x59 => orbclient::K_NUM_1,
0x5A => orbclient::K_NUM_2,
0x5B => orbclient::K_NUM_3,
0x5C => orbclient::K_NUM_4,
0x5D => orbclient::K_NUM_5,
0x5E => orbclient::K_NUM_6,
0x5F => orbclient::K_NUM_7,
0x60 => orbclient::K_NUM_8,
0x61 => orbclient::K_NUM_9,
0x62 => orbclient::K_NUM_0,
// 0x62 num .
// 0x64 non-us \ and |
// 0x64 app
// 0x66 power
// 0x67 num =
// unmapped values
0xE0 => orbclient::K_CTRL, // TODO: left control
0xE1 => orbclient::K_LEFT_SHIFT,
0xE2 => orbclient::K_ALT,
// 0xE3 left super
0xE4 => orbclient::K_CTRL, // TODO: right control
0xE5 => orbclient::K_RIGHT_SHIFT,
0xE6 => orbclient::K_ALT_GR,
// 0xE7 right super
// reserved values
_ => {
println!("unknown usage_page {:#x} usage {:#x}", usage_page, usage);
return;
},
},
_ => {
println!("unknown usage_page {:#x}", usage_page);
return;
},
};
//TODO: other keymaps
let character = if let Some(shift) = shift_opt {
keymap::us::get_char(scancode, shift)
} else {
'\0'
};
println!("{:#x?}", OrbKeyEvent {
character,
scancode,
pressed,
});
}
fn main() {
let _logger_ref = setup_logging();
@@ -199,6 +338,7 @@ fn main() {
None => return None,
};
if global_state.usage_page != Some(0x7) {
println!("Unsupported usage page: {:#x?}", global_state.usage_page);
return None;
}
let bit_length = report_size * report_count;
@@ -249,24 +389,25 @@ fn main() {
// The usages are selectors.
}
for report_index in 0..report_count {
}
/*if input.contains(MainItemFlags::VARIABLE) {
if input.contains(MainItemFlags::VARIABLE) {
// The item is a variable.
let binary_view = BinaryView::new(&report_buffer, bit_offset as usize, bit_length as usize);
if report_count == 8 && report_size == 1 && local_state.usage_min == Some(224) && local_state.usage_max == Some(231) && global_state.logical_min == Some(0) && global_state.logical_max == Some(1) {
let bits = binary_view.read_u8(0).expect("Failed to read array item");
for bit in 0..8 {
if bits & (1 << bit) > 0 {
pressed_keys.push(0xE0 + bit);
}
}
println!("Report variable {:#x?}", bits);
} else {
println!("unknown report variable item");
}
} else {
// The item is an array.
std::mem::swap(&mut pressed_keys, &mut last_pressed_keys);
pressed_keys.clear();
println!("INPUT FLAGS: {:?}", input);
assert_eq!(report_size, 8);
for report_index in 0..report_count as usize {
@@ -275,19 +416,30 @@ fn main() {
if usage != 0 {
pressed_keys.push(usage);
}
println!("Report index array {}: {}", report_index, usage);
println!("Report index array {}: {:#x}", report_index, usage);
}
}*/
}
for (current, last) in pressed_keys.iter().copied().zip(last_pressed_keys.iter().copied()) {
if current == last { continue }
if current != 0 {
// Keycode current changed state to "pressed".
} else {
// Keycode current changed state to "released".
}
}
println!();
for usage in last_pressed_keys.iter() {
if ! pressed_keys.contains(usage) {
println!("Released {:#x}", usage);
send_key_event(global_state.usage_page.unwrap_or(0), *usage, false, None);
}
}
for usage in pressed_keys.iter() {
if ! last_pressed_keys.contains(usage) {
println!("Pressed {:#x}", usage);
send_key_event(global_state.usage_page.unwrap_or(0), *usage, true, Some(
pressed_keys.contains(&0xE1) || pressed_keys.contains(&0xE5)
));
}
}
std::mem::swap(&mut pressed_keys, &mut last_pressed_keys);
pressed_keys.clear();
}
}
}