read_key_termios/lib.rs
1//! Read Key (Termios): A tiny crate to read keys on Linux without introducing a huge amount of
2//! dependencies.
3//!
4//! fn read_key(fd: i32) -> u8; Takes in the FD to read. Blocks until a key has been pressed.
5//! This should be used with polling acceptably. It retuns a byte for the user to parse.
6//!
7//! fn init(); Enters raw mode, and allows the keys to start being read.
8//!
9//! fn close(): Enters cooked mode. Read_key() will not work after this.
10
11/// The reason we don't use Bindgen to generate the structures is to keep this crate as small as
12/// possible, to suit it's one purpose. Most users will know what this struct is, if they are
13/// familiar with Libc. If, not I suggest you have a look.
14#[repr(C)]
15pub struct Termios {
16 pub c_iflag: i32,
17 pub c_oflag: i32,
18 pub c_cflag: i32,
19 pub c_lflag: i32,
20}
21
22static ECHO: i32 = 0o0000010;
23static ICANON: i32 = 0x00002;
24static TCSAFLUSH: i32 = 2;
25
26extern "C" {
27 fn tcgetattr(fd: i32, termios: &mut Termios);
28 fn tcsetattr(fd: i32, int: i32, termios: &mut Termios);
29 fn read(fd: i32, char: &mut u8, amount: i32);
30}
31
32/// Enters raw mode in the terminal so that the user can start to read keys properly. This uses
33/// bindings to Termios to convert the terminal to raw mode.
34///
35/// # Safety
36/// As it uses bindings to C, this will inherently be unsafe.
37pub fn init() {
38 let fd = std::os::fd::AsRawFd::as_raw_fd(&std::io::stdout()); // most likely 0
39
40 unsafe {
41 let mut termios: Termios = std::mem::zeroed();
42
43 tcgetattr(fd, &mut termios);
44
45 termios.c_lflag &= !(ECHO | ICANON); // disables ECHO and cooked mode
46
47 tcsetattr(fd, TCSAFLUSH, &mut termios);
48 }
49}
50
51/// Leaves raw mode in your terminal so that the user is returned to a normal terminal instance
52/// (cooked mode).
53///
54/// # Safety
55/// This calls functions in C, so it is unsafe.
56pub fn close() {
57 let fd = std::os::fd::AsRawFd::as_raw_fd(&std::io::stdout());
58
59 unsafe {
60 let mut termios: Termios = std::mem::zeroed();
61
62 tcgetattr(fd, &mut termios);
63
64 termios.c_lflag |= ECHO | ICANON; // re-enables echo
65
66 tcsetattr(fd, TCSAFLUSH, &mut termios);
67 }
68}
69
70/// Reads a key from the specified FD and returns it.
71///
72/// # Safety
73/// This uses the function `read` from C.
74pub fn read_key(fd: i32) -> u8 {
75 let mut c: u8 = 0;
76 unsafe {
77 read(fd, &mut c, 1);
78 }
79 c
80}