+#ifndef __CONSOLE_H
+#define __CONSOLE_H
+
+// constants for command keys returned from readkey()
+#define KEY_UP -1024
+#define KEY_DOWN -1025
+#define KEY_LEFT -1026
+#define KEY_RIGHT -1027
+#define KEY_ENTER -1028
+#define KEY_BACKSPACE -1029
+#define KEY_TAB -1030
+#define KEY_BREAK -1031
+
+#define is_command_key(k) (k <= -1024 && k > -2048)
+
+#endif //__CONSOLE_H
#include <stddef.h>
struct console_operations {
- int32_t (*readb)();
- size_t (*read)(uint8_t buf[], size_t len);
+ int32_t (*readkey)();
size_t (*readline)(uint8_t buf[], size_t len);
void (*writeb)(uint8_t b);
void (*write)(uint8_t a[], size_t len);
#include <sysops.h>
+#include <console.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
return 0;
}
+int keydebug() {
+ while (1) {
+ int k = sys_ops->console->readkey();
+ if (k == -1) continue;
+ if (is_command_key(k)) {
+ switch(k) {
+ case KEY_UP: puts("[up]"); break;
+ case KEY_DOWN: puts("[down]"); break;
+ case KEY_LEFT: puts("[left]"); break;
+ case KEY_RIGHT: puts("[right]"); break;
+ case KEY_ENTER: puts("[enter]"); break;
+ case KEY_BACKSPACE: puts("[backspace]"); break;
+ case KEY_TAB: puts("[tab]"); break;
+ case KEY_BREAK: puts("[break]"); break;
+ }
+ } else {
+ printf("%c (%02x)\n", (char)k, k);
+ }
+ }
+}
+
void shell_main(struct MemoryRange *r) {
lua_State *L;
char buffer[128];
"mov r1, #0\n"
"sdiv r0, r0, r1\n"
);
+ } else if (strcmp(buffer, "keydebug") == 0) {
+ keydebug();
} else {
luaL_loadstring(L, buffer);
int r = lua_pcall(L, 0, LUA_MULTRET, 0);
use core::slice;
use crate::console::get_global_console;
+use crate::console::Key;
pub struct RustConsoleOperations {
- pub readb: fn() -> Option<u8>,
- pub read: fn(&mut [u8]) -> usize,
+ pub readkey: fn() -> Option<Key>,
pub readline: fn(buf: &mut [u8]) -> usize,
pub writeb: fn(b: u8),
pub write: fn(a: &[u8]),
#[repr(C)]
pub struct CConsoleOperations {
- pub readb: extern "C" fn() -> i32,
- pub read: extern "C" fn(buf: *mut u8, len: usize) -> usize,
+ pub readkey: extern "C" fn() -> i32,
pub readline: extern "C" fn(buf: *mut u8, len: usize) -> usize,
pub writeb: extern "C" fn(b: u8),
pub write: extern "C" fn(a: *const u8, len: usize),
/* Console driver function table */
/* Rust versions */
-fn rust_readb() -> Option<u8> {
- get_global_console().readb()
-}
-
-fn rust_read(buf: &mut [u8]) -> usize {
- get_global_console().read(buf)
+fn rust_readkey() -> Option<Key> {
+ get_global_console().readkey()
}
fn rust_readline(buf: &mut [u8]) -> usize {
}
pub const RUST_CONSOLE_OPERATIONS: RustConsoleOperations = RustConsoleOperations {
- readb: rust_readb,
- read: rust_read,
+ readkey: rust_readkey,
readline: rust_readline,
writeb: rust_writeb,
write: rust_write,
};
/* C versions */
-extern "C" fn c_readb() -> i32 {
- match rust_readb() {
- Some(b) => b as i32,
+extern "C" fn c_readkey() -> i32 {
+ match rust_readkey() {
+ Some(k) => match k {
+ Key::Char(c) => c as i32,
+ Key::Command(c) => -(1024 + c as i32),
+ }
None => -1,
}
}
-extern "C" fn c_read(buf: *mut u8, len: usize) -> usize {
- if len == 0 {
- return 0;
- }
-
- let buf = unsafe { slice::from_raw_parts_mut(buf, len) };
- rust_read(buf)
-}
-
extern "C" fn c_readline(buf: *mut u8, len: usize) -> usize {
let buf = unsafe { slice::from_raw_parts_mut(buf, len) };
rust_readline(buf)
}
pub const C_CONSOLE_OPERATIONS: CConsoleOperations = CConsoleOperations {
- readb: c_readb,
- read: c_read,
+ readkey: c_readkey,
readline: c_readline,
writeb: c_writeb,
write: c_write,
+pub enum Command {
+ Up,
+ Down,
+ Left,
+ Right,
+ Enter,
+ Backspace,
+ Tab,
+ Break,
+}
+
+pub enum Key {
+ Char(char),
+ Command(Command),
+}
+
+pub struct ModifierState {
+ control: bool,
+ alt: bool,
+ shift: bool,
+}
use core::fmt;
+mod key;
pub mod serial;
-pub mod traits;
-pub mod interfaces;
+mod traits;
+mod interfaces;
use crate::console::serial::SerialTerminal;
-pub use crate::console::traits::*;
-pub use crate::console::interfaces::*;
+pub use key::*;
+pub use traits::*;
+pub use interfaces::*;
#[link_section = ".kgbss"]
static mut G_CONSOLE: Option<Console> = None;
}
}
- pub fn readb(&mut self) -> Option<u8> {
- self.terminal.readb()
- }
-
- pub fn read(&mut self, buf: &mut [u8]) -> usize {
- self.terminal.read(buf)
+ pub fn readkey(&mut self) -> Option<Key> {
+ self.terminal.readkey()
}
pub fn readline(&mut self, buf: &mut [u8]) -> usize {
use atsam3xa::interrupt;
use cortex_m::interrupt as cm_interrupt;
+use crate::console::key::*;
use crate::console::traits::*;
use crate::console::get_global_console;
}
impl ConsoleIO for SerialTerminal {
- fn readb(&mut self) -> Option<u8> {
+ fn readkey(&mut self) -> Option<Key> {
cm_interrupt::free(|_| {
- self.input_buffer.pop_front()
+ let b = self.input_buffer.pop_front()?;
+ match b {
+ 0x1b => {
+ if self.input_buffer.len() >= 2 {
+ // escape sequence incoming
+ let b = self.input_buffer.pop_front().unwrap();
+ if b != 0x5b {
+ return None;
+ }
+
+ let b = self.input_buffer.pop_front().unwrap();
+ match b {
+ 0x41 => Some(Key::Command(Command::Up)),
+ 0x42 => Some(Key::Command(Command::Down)),
+ 0x43 => Some(Key::Command(Command::Right)),
+ 0x44 => Some(Key::Command(Command::Left)),
+ _ => None,
+ }
+ } else {
+ // not enough characters yet, put the ESC back in the buffer
+ self.input_buffer.push_front(0x1b).unwrap();
+ None
+ }
+ },
+ 0x0d => Some(Key::Command(Command::Enter)),
+ 0x08 => Some(Key::Command(Command::Backspace)),
+ 0x09 => Some(Key::Command(Command::Tab)),
+ 0x03 => Some(Key::Command(Command::Break)),
+ b => Some(Key::Char(b as char)),
+ }
})
}
- fn read(&mut self, buf: &mut [u8]) -> usize {
- let len = if buf.len() > self.input_buffer.len() {
- self.input_buffer.len()
- } else {
- buf.len()
- };
-
- for i in 0..len {
- buf[i] = self.readb().unwrap();
- }
-
- len
- }
-
fn readline(&mut self, buf: &mut [u8]) -> usize {
let mut c = 0;
+ let mut cursor = 0;
loop {
- let byte = match self.readb() {
- Some(b) => b,
+ match self.readkey() {
+ Some(k) => match k {
+ Key::Char(x) => {
+ if c == buf.len() {
+ // Don't overflow the buffer
+ continue;
+ }
+
+ // FIXME proper unicode output
+ self.writeb(x as u8);
+ if cursor < c {
+ // reprint everything to the right of the cursor
+ for i in cursor..c {
+ self.writeb(buf[i]);
+ }
+ for i in (cursor..c).rev() {
+ buf[i + 1] = buf[i];
+ self.writeb(0x08);
+ }
+ }
+ buf[cursor] = x as u8;
+
+ c += 1;
+ cursor += 1;
+ },
+ Key::Command(x) => match x {
+ Command::Backspace => {
+ if c == 0 || cursor == 0 {
+ // buffer empty
+ continue;
+ }
+ self.writeb(0x08);
+ for i in cursor..c {
+ // reprint everything from the cursor rightward
+ self.writeb(buf[i]);
+ }
+ self.writeb(0x20);
+ for i in cursor..c {
+ buf[i - 1] = buf[i];
+ self.writeb(0x08);
+ }
+ self.writeb(0x08);
+ c -= 1;
+ cursor -= 1;
+ },
+ Command::Enter => {
+ break;
+ },
+ Command::Left => {
+ if cursor == 0 {
+ continue;
+ }
+ cursor -= 1;
+ self.write("\x1b[1D");
+ },
+ Command::Right => {
+ if cursor == c {
+ continue;
+ }
+ cursor += 1;
+ self.write("\x1b[1C");
+ },
+ _ => continue,
+ }
+ },
None => continue,
};
- if byte == 0xd {
- break;
- } else if byte == 0x8 {
- if c == 0 {
- // buffer empty
- continue;
- }
- self.write("\x08 \x08");
- c -= 1;
- continue;
- }
-
- if c == buf.len() {
- // Don't overflow the buffer
- continue;
- }
-
- self.writeb(byte);
- buf[c] = byte;
- c += 1;
}
c
fn pos(&mut self, x: usize, y: usize) {
use core::fmt::Write;
- assert!(x < 80 && y < 25);
+ assert!(x < 40 && y < 25);
write!(self, "\x1b[{};{}H", y, x).ok();
}
+use crate::console::Key;
+
pub trait ConsoleIO {
// input
- fn readb(&mut self) -> Option<u8>;
- fn read(&mut self, buf: &mut [u8]) -> usize;
+ fn readkey(&mut self) -> Option<Key>;
fn readline(&mut self, buf: &mut [u8]) -> usize;
fn discard(&mut self);