Last active
November 4, 2020 16:21
-
-
Save sigmaSd/393d8c8ce201e04b1df6fda4898a71f8 to your computer and use it in GitHub Desktop.
[dependencies] ctrlc = "3.1.7" libc = "0.2.80" scopeguard = "1.1.0" termios = "0.3.3"
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::io; | |
use std::io::prelude::*; | |
use std::os::unix::io::AsRawFd; | |
use termios::*; | |
const KDSKBMODE: u64 = 0x4B45; | |
fn main() { | |
if let Err(e) = try_main() { | |
eprintln!("Something happened: {}", e); | |
} | |
} | |
fn try_main() -> io::Result<()> { | |
let tty0_f = std::fs::File::open("/dev/tty0")?; | |
let tty0 = tty0_f.as_raw_fd(); | |
let old_termios = Termios::from_fd(tty0)?; | |
let oldkbmode: libc::c_int = unsafe { get_mode(tty0) }?; | |
// cleanup | |
scopeguard::defer! { | |
clean_up(tty0, old_termios, oldkbmode); | |
} | |
let running = Arc::new(AtomicBool::new(true)); | |
let flag = running.clone(); | |
ctrlc::set_handler(move || { | |
flag.store(false, Ordering::SeqCst); | |
}) | |
.expect("Error setting Ctrl-C handler"); | |
showkey(&tty0_f, tty0, running)?; | |
Ok(()) | |
} | |
use std::sync::atomic::{AtomicBool, Ordering}; | |
use std::sync::Arc; | |
fn showkey(mut tty0_f: &std::fs::File, tty0: i32, running: Arc<AtomicBool>) -> io::Result<()> { | |
let mut buf = [0u8; 18]; | |
let mut new = Termios::from_fd(tty0)?; | |
new.c_lflag &= !(ICANON | ECHO | ISIG); | |
new.c_iflag = 0; | |
new.c_cc[VMIN] = 18; | |
new.c_cc[VTIME] = 1; | |
tcsetattr(tty0, TCSAFLUSH, &new)?; | |
const K_RAW: u64 = 0x0; | |
unsafe { | |
if libc::ioctl(tty0, KDSKBMODE, K_RAW) != 0 { | |
return Err(io::Error::last_os_error()); | |
} | |
} | |
while running.load(Ordering::SeqCst) { | |
let n = tty0_f.read(&mut buf)?; | |
print(&buf, n); | |
} | |
Ok(()) | |
} | |
fn print(buf: &[u8], n: usize) { | |
let mut i = 0; | |
while i < n { | |
let kc; | |
let s: String; | |
s = if (buf[i] & 0x80) != 0 { | |
"release".into() | |
} else { | |
"press".into() | |
}; | |
if i + 2 < n | |
&& buf[i].trailing_zeros() >= 7 | |
&& (buf[i + 1] & 0x80) != 0 | |
&& (buf[i + 2] & 0x80) != 0 | |
{ | |
kc = ((buf[i + 1] & 0x7f) << 7) | (buf[i + 2] & 0x7f); | |
i += 3; | |
} else { | |
kc = buf[i] & 0x7f; | |
i += 1; | |
} | |
println!("keycode {} {}", kc, s); | |
} | |
} | |
unsafe fn get_mode(tty0: i32) -> io::Result<libc::c_int> { | |
const KDGKBMODE: u64 = 0x4B44; | |
const K_XLATE: i32 = 0x01; | |
const K_MEDIUMRAW: i32 = 0x02; | |
const K_UNICODE: i32 = 0x03; | |
const K_RAW: i32 = 0x0; | |
let mut kbm = 1; | |
let oldkbmode: &mut libc::c_int = &mut kbm; | |
let m: String; | |
if libc::ioctl(tty0, KDGKBMODE, &mut *oldkbmode) != 0 { | |
return Err(io::Error::last_os_error()); | |
} | |
match *oldkbmode { | |
x if x == K_RAW => { | |
m = "RAW".into(); | |
} | |
x if x == K_XLATE => { | |
m = "XLATE".into(); | |
} | |
x if x == K_MEDIUMRAW => { | |
m = "MEDIUMRAW".into(); | |
} | |
x if x == K_UNICODE => { | |
m = "UNICODE".into(); | |
} | |
_ => { | |
m = "?UNKNOWN?".into(); | |
} | |
} | |
println!("Old keyboard mode was: {}\n", m); | |
Ok(*oldkbmode) | |
} | |
fn clean_up(tty0: i32, old_termios: Termios, oldkbmode: libc::c_int) { | |
unsafe { | |
if libc::ioctl(tty0, KDSKBMODE, oldkbmode) != 0 { | |
eprintln!( | |
"Could not restore orignal keyboard mode. error: {}", | |
io::Error::last_os_error() | |
) | |
}; | |
if let Err(e) = tcsetattr(tty0, 0, &old_termios) { | |
eprintln!( | |
"Could not restore original termios attributes. Error: {}", | |
e | |
); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment