getch/
lib.rs

1#[cfg(not(windows))]
2extern crate termios;
3#[cfg(not(windows))]
4use std::io::Read;
5#[cfg(windows)]
6pub struct Getch{}
7
8#[cfg(not(windows))]
9pub enum Getch {
10    Termios(termios::Termios),
11    None
12}
13
14#[cfg(windows)]
15extern crate libc;
16#[cfg(windows)]
17use libc::c_int;
18#[cfg(windows)]
19extern "C" {
20    fn _getch()->c_int;
21}
22
23#[cfg(not(windows))]
24use termios::{tcsetattr,ICANON,ECHO};
25
26impl Getch {
27    #[cfg(windows)]
28    pub fn new() -> Getch {
29        Getch{}
30    }
31    #[cfg(not(windows))]
32    pub fn new() -> Getch {
33        if let Ok(mut termios) = termios::Termios::from_fd(0) {
34            let c_lflag = termios.c_lflag;
35            termios.c_lflag &= !(ICANON|ECHO);
36
37            if let Ok(()) = tcsetattr(0, termios::TCSADRAIN, &termios) {
38                termios.c_lflag = c_lflag;
39                return Getch::Termios(termios)
40            }
41        }
42        Getch::None
43    }
44
45    #[cfg(windows)]
46    pub fn getch(&self) -> Result<u8, std::io::Error> {
47        loop {
48            unsafe {
49                let k= _getch();
50                if k==0 {
51                    // Ignore next input.
52                    _getch();
53                } else {
54                    return Ok(k as u8)
55                }
56            }
57        }
58    }
59    #[cfg(not(windows))]
60    pub fn getch(&self) -> Result<u8, std::io::Error> {
61        let mut r:[u8;1]=[0];
62        let mut stdin = std::io::stdin();
63        loop {
64            if stdin.read(&mut r[..])? == 0 { return Ok(0) }
65            else {
66                if r[0]==27 {
67                    if stdin.read(&mut r[..])? == 0 { return Ok(0) }
68                    if r[0] == b'[' || (r[0] >= b'0' && r[0] <= b'9') {
69                        if stdin.read(&mut r[..])? == 0 { return Ok(0) }
70                        // Skip all until we see a letter.
71                        while !((r[0] >= b'a' && r[0] <= b'z') || (r[0] >= b'A' && r[0] <= b'Z')) {
72                            if stdin.read(&mut r[..])? == 0 { return Ok(0) }
73                        }
74                        if stdin.read(&mut r[..])? == 0 { return Ok(0) }
75                        return Ok(r[0])
76                    } else if r[0] == b'(' || r[0] == b')' || r[0] == b'#' {
77                        // skip the next character and return
78                        if stdin.read(&mut r[..])? == 0 { return Ok(0) }
79                        if stdin.read(&mut r[..])? == 0 { return Ok(0) }
80                        return Ok(r[0])
81                    } else {
82                        // return the next character
83                        if stdin.read(&mut r[..])? == 0 { return Ok(0) }
84                        return Ok(r[0])
85                    }
86                } else {
87                    // TODO: accept utf-8
88                    return Ok(r[0])
89                }
90            }
91        }
92    }
93}
94
95impl Drop for Getch {
96    #[cfg(not(windows))]
97    fn drop(&mut self) {
98        if let Getch::Termios(ref mut termios) = *self {
99            tcsetattr(0, termios::TCSADRAIN, &termios).unwrap_or(())
100        }
101    }
102    #[cfg(windows)]
103    fn drop(&mut self) {
104    }
105}