From e6168da6dcf28fd1fc070d580be0c3393edb6203 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Wed, 4 Aug 2021 20:31:17 +0200 Subject: [PATCH 1/6] Change keyboard layout at runtime --- src/sys/keyboard.rs | 119 ++++++++++++++++++-------------------------- 1 file changed, 48 insertions(+), 71 deletions(-) diff --git a/src/sys/keyboard.rs b/src/sys/keyboard.rs index 9ea967ed..8897ed91 100644 --- a/src/sys/keyboard.rs +++ b/src/sys/keyboard.rs @@ -1,79 +1,55 @@ use crate::sys; + use lazy_static::lazy_static; -use pc_keyboard::{layouts, DecodedKey, HandleControl, KeyCode, Keyboard, ScancodeSet1}; +use pc_keyboard::{layouts, DecodedKey, Error, HandleControl, KeyCode, KeyEvent, Keyboard, ScancodeSet1}; use spin::Mutex; use x86_64::instructions::port::Port; -// TODO: Support dyn KeyboardLayout - -#[cfg(feature = "qwerty")] lazy_static! { - pub static ref KEYBOARD: Mutex> = Mutex::new(Keyboard::new( - layouts::Us104Key, - ScancodeSet1, - HandleControl::MapLettersToUnicode - )); + pub static ref KEYBOARD: Mutex> = Mutex::new(None); } -#[cfg(feature = "dvorak")] -lazy_static! { - pub static ref KEYBOARD: Mutex> = Mutex::new(Keyboard::new( - layouts::Dvorak104Key, - ScancodeSet1, - HandleControl::MapLettersToUnicode - )); +pub enum KeyboardLayout { + Qwerty(Keyboard), + Dvorak(Keyboard), } -pub fn init() { - /* - let mut port = Port::new(0x60); +impl KeyboardLayout { + fn add_byte(&mut self, scancode: u8) -> Result, Error> { + match self { + KeyboardLayout::Qwerty(keyboard) => keyboard.add_byte(scancode), + KeyboardLayout::Dvorak(keyboard) => keyboard.add_byte(scancode), + } + } - // Identify - let res = unsafe { - port.write(0xF2 as u8); // Identify - port.read() - }; - if res != 0xFA { // 0xFA == ACK, 0xFE == Resend - return init(); + fn process_keyevent(&mut self, key_event: KeyEvent) -> Option { + match self { + KeyboardLayout::Qwerty(keyboard) => keyboard.process_keyevent(key_event), + KeyboardLayout::Dvorak(keyboard) => keyboard.process_keyevent(key_event), + } } - let res = unsafe { - port.read() - }; - printk!("[{:.6}] keyboard: identify {:#X}\n", sys::clock::uptime(), res); - let res = unsafe { - port.read() - }; - printk!("[{:.6}] keyboard: identify {:#X}\n", sys::clock::uptime(), res); - // Self-test - let res = unsafe { - port.write(0xFF as u8); // Reset and self-test - port.read() - }; - if res != 0xFA { // 0xFA == ACK, 0xFE == Resend - return init(); + fn from(name: &str) -> Option { + match name { + "qwerty" => Some(KeyboardLayout::Qwerty(Keyboard::new(layouts::Us104Key, ScancodeSet1, HandleControl::MapLettersToUnicode))), + "dvorak" => Some(KeyboardLayout::Dvorak(Keyboard::new(layouts::Dvorak104Key, ScancodeSet1, HandleControl::MapLettersToUnicode))), + _ => None, + } } - let res = unsafe { - port.read() - }; - if res == 0xAA { // 0xAA == Passed, 0xFC or 0xFD == Failed, 0xFE == Resend - printk!("[{:.6}] keyboard: self test passed\n", sys::clock::uptime()); +} + +pub fn set_keyboard(layout: &str) -> bool { + if let Some(keyboard) = KeyboardLayout::from(layout) { + *KEYBOARD.lock() = Some(keyboard); + true } else { - printk!("[{:.6}] keyboard: self test failed ({:#X})\n", sys::clock::uptime(), res); + false } +} + +pub fn init() { + set_keyboard(option_env!("MOROS_KEYBOARD").unwrap_or("qwerty")); - // Switch to scancode set 2 - // TODO: Not working because PS/2 controller is configured to do the translation (0xAB, 0x41) - let res = unsafe { - port.write(0xF0 as u8); // Set current scancode set - port.write(0x02 as u8); // to 2 - port.read() - }; - if res != 0xFA { // 0xFA == ACK, 0xFE == Resend - return init(); - } - printk!("[{:.6}] keyboard: switch to scancode set 2\n", sys::clock::uptime()); - */ sys::idt::set_irq_handler(1, interrupt_handler); } @@ -93,18 +69,19 @@ fn send_csi(c: char) { } fn interrupt_handler() { - let mut keyboard = KEYBOARD.lock(); - let scancode = read_scancode(); - if let Ok(Some(key_event)) = keyboard.add_byte(scancode) { - if let Some(key) = keyboard.process_keyevent(key_event) { - match key { - DecodedKey::Unicode(c) => send_key(c), - DecodedKey::RawKey(KeyCode::ArrowUp) => send_csi('A'), - DecodedKey::RawKey(KeyCode::ArrowDown) => send_csi('B'), - DecodedKey::RawKey(KeyCode::ArrowRight) => send_csi('C'), - DecodedKey::RawKey(KeyCode::ArrowLeft) => send_csi('D'), - _ => {}, - }; + if let Some(ref mut keyboard) = *KEYBOARD.lock() { + let scancode = read_scancode(); + if let Ok(Some(key_event)) = keyboard.add_byte(scancode) { + if let Some(key) = keyboard.process_keyevent(key_event) { + match key { + DecodedKey::Unicode(c) => send_key(c), + DecodedKey::RawKey(KeyCode::ArrowUp) => send_csi('A'), + DecodedKey::RawKey(KeyCode::ArrowDown) => send_csi('B'), + DecodedKey::RawKey(KeyCode::ArrowRight) => send_csi('C'), + DecodedKey::RawKey(KeyCode::ArrowLeft) => send_csi('D'), + _ => {}, + }; + } } } } From 944301de2490f011139457d254b5e53e20c07133 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Wed, 4 Aug 2021 20:31:39 +0200 Subject: [PATCH 2/6] Add keyboard command --- src/usr/keyboard.rs | 29 +++++++++++++++++++++++++++++ src/usr/mod.rs | 1 + src/usr/shell.rs | 9 +++++---- 3 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 src/usr/keyboard.rs diff --git a/src/usr/keyboard.rs b/src/usr/keyboard.rs new file mode 100644 index 00000000..a05c7cdb --- /dev/null +++ b/src/usr/keyboard.rs @@ -0,0 +1,29 @@ +use crate::{sys, usr}; + +pub fn main(args: &[&str]) -> usr::shell::ExitCode { + if args.len() == 1 { + println!("Usage: keyboard "); + return usr::shell::ExitCode::CommandError; + } + match args[1] { + "set" => { + if args.len() == 2 { + return error("keyboard layout missing"); + } else { + let layout = args[2]; + if !sys::keyboard::set_keyboard(layout) { + return error("unknown keyboard layout"); + } + } + }, + _ => { + return error("invalid command"); + } + } + usr::shell::ExitCode::CommandSuccessful +} + +fn error(message: &str) -> usr::shell::ExitCode { + println!("Error: {}", message); + usr::shell::ExitCode::CommandError +} diff --git a/src/usr/mod.rs b/src/usr/mod.rs index 4b4450dc..53fe92de 100644 --- a/src/usr/mod.rs +++ b/src/usr/mod.rs @@ -18,6 +18,7 @@ pub mod http; pub mod httpd; pub mod install; pub mod ip; +pub mod keyboard; pub mod list; pub mod lisp; pub mod mem; diff --git a/src/usr/shell.rs b/src/usr/shell.rs index 274df78a..d2614382 100644 --- a/src/usr/shell.rs +++ b/src/usr/shell.rs @@ -6,11 +6,11 @@ use alloc::vec::Vec; use alloc::string::String; // TODO: Scan /bin -const AUTOCOMPLETE_COMMANDS: [&str; 35] = [ +const AUTOCOMPLETE_COMMANDS: [&str; 36] = [ "base64", "clear", "colors", "copy", "date", "delete", "dhcp", "disk", "edit", "env", "exit", - "geotime", "goto", "halt", "help", "hex", "host", "http", "httpd", "install", "ip", "lisp", - "list", "memory", "move", "net", "print", "read", "route", "shell", "sleep", "tcp", "user", - "vga", "write" + "geotime", "goto", "halt", "help", "hex", "host", "http", "httpd", "install", "ip", "keyboard", + "lisp", "list", "memory", "move", "net", "print", "read", "route", "shell", "sleep", "tcp", + "user", "vga", "write" ]; #[repr(u8)] @@ -176,6 +176,7 @@ pub fn exec(cmd: &str) -> ExitCode { "disk" => usr::disk::main(&args), "user" => usr::user::main(&args), "mem" | "memory" => usr::mem::main(&args), + "kb" | "keyboard" => usr::keyboard::main(&args), "lisp" => usr::lisp::main(&args), _ => ExitCode::CommandUnknown, } From 83e035a829c4596dfd69258dc5a46f880e9beb6d Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Wed, 4 Aug 2021 20:52:31 +0200 Subject: [PATCH 3/6] Add env var to makefile --- Cargo.toml | 4 +--- Makefile | 9 ++++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0642f8b2..f339e549 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,11 +9,9 @@ repository = "https://github.com/vinc/moros" readme = "README.md" [features] -default = ["video", "qwerty", "rtl8139"] +default = ["video", "rtl8139"] video = [] serial = [] -qwerty = [] -dvorak = [] rtl8139 = [] pcnet = [] diff --git a/Makefile b/Makefile index b117be41..77604785 100644 --- a/Makefile +++ b/Makefile @@ -13,8 +13,10 @@ output = video keyboard = qwerty nic = rtl8139 -bin=target/x86_64-moros/release/bootimage-moros.bin -img=disk.img +export MOROS_KEYBOARD = $(keyboard) + +bin = target/x86_64-moros/release/bootimage-moros.bin +img = disk.img $(img): qemu-img create $(img) 32M @@ -22,7 +24,8 @@ $(img): # Rebuild MOROS if the features list changed image: $(img) touch src/lib.rs - cargo bootimage --no-default-features --features $(output),$(keyboard),$(nic) --release + env | grep MOROS + cargo bootimage --no-default-features --features $(output),$(nic) --release dd conv=notrunc if=$(bin) of=$(img) opts = -m 32 -cpu max -nic model=$(nic) -hda $(img) From cefa08457d203338326aac9d5c0d52b415c27343 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Wed, 4 Aug 2021 21:58:39 +0200 Subject: [PATCH 4/6] Add azerty layout --- src/sys/keyboard.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/sys/keyboard.rs b/src/sys/keyboard.rs index 8897ed91..1fdde65b 100644 --- a/src/sys/keyboard.rs +++ b/src/sys/keyboard.rs @@ -10,29 +10,33 @@ lazy_static! { } pub enum KeyboardLayout { - Qwerty(Keyboard), + Azerty(Keyboard), Dvorak(Keyboard), + Qwerty(Keyboard), } impl KeyboardLayout { fn add_byte(&mut self, scancode: u8) -> Result, Error> { match self { - KeyboardLayout::Qwerty(keyboard) => keyboard.add_byte(scancode), + KeyboardLayout::Azerty(keyboard) => keyboard.add_byte(scancode), KeyboardLayout::Dvorak(keyboard) => keyboard.add_byte(scancode), + KeyboardLayout::Qwerty(keyboard) => keyboard.add_byte(scancode), } } fn process_keyevent(&mut self, key_event: KeyEvent) -> Option { match self { - KeyboardLayout::Qwerty(keyboard) => keyboard.process_keyevent(key_event), + KeyboardLayout::Azerty(keyboard) => keyboard.process_keyevent(key_event), KeyboardLayout::Dvorak(keyboard) => keyboard.process_keyevent(key_event), + KeyboardLayout::Qwerty(keyboard) => keyboard.process_keyevent(key_event), } } fn from(name: &str) -> Option { match name { - "qwerty" => Some(KeyboardLayout::Qwerty(Keyboard::new(layouts::Us104Key, ScancodeSet1, HandleControl::MapLettersToUnicode))), + "azerty" => Some(KeyboardLayout::Azerty(Keyboard::new(layouts::Azerty, ScancodeSet1, HandleControl::MapLettersToUnicode))), "dvorak" => Some(KeyboardLayout::Dvorak(Keyboard::new(layouts::Dvorak104Key, ScancodeSet1, HandleControl::MapLettersToUnicode))), + "qwerty" => Some(KeyboardLayout::Qwerty(Keyboard::new(layouts::Us104Key, ScancodeSet1, HandleControl::MapLettersToUnicode))), _ => None, } } From 38f34ba0e0ce6e94c8401187705038e11102f907 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Wed, 4 Aug 2021 21:59:46 +0200 Subject: [PATCH 5/6] Fix tests --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 77604785..365858fa 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ qemu: qemu-system-x86_64 $(opts) test: - cargo test --lib --no-default-features --features serial,$(keyboard),$(nic) -- \ + cargo test --lib --no-default-features --features serial,$(nic) -- \ -display none -serial stdio -device isa-debug-exit,iobase=0xf4,iosize=0x04 clean: From d6add356577d1c3325a730c79bdd2924c7e4e8f9 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Wed, 4 Aug 2021 22:03:33 +0200 Subject: [PATCH 6/6] Fix CI --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 58e9d9fc..ae9ad059 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -24,4 +24,4 @@ jobs: - run: rustup component add rust-src - run: rustup component add llvm-tools-preview - run: cargo install bootimage - - run: cargo test --lib --no-default-features --features serial,qwerty,pcnet -- -display none -serial stdio -device isa-debug-exit,iobase=0xf4,iosize=0x04 + - run: cargo test --lib --no-default-features --features serial,pcnet -- -display none -serial stdio -device isa-debug-exit,iobase=0xf4,iosize=0x04