C/C++ 以及 Rust 中的 getch() 实现
getch
是一个在 C 语言编程中常用的函数,用于从键盘读取一个字符,但不回显到屏幕上。
在 Windows 环境下,getch
实现通常包含在 <conio.h>
头文件中。需要注意的是,getch
这个符号并非标准,标准的符号是 _getch
,虽然 getch
一般会被指向 _getch
,但你应当使用 _getch
而非 getch
。
在 Unix/Linux 环境下,没有系统提供的 getch
实现,我们可以通过以下方法实现:
#include <termio.h> int getch(void) { struct termios tm, tm_old; int fd = 0, ch; if (tcgetattr(fd, &tm) < 0) { // 保存现在的终端设置 return -1; } tm_old = tm; cfmakeraw(&tm); // 更改终端为原始模式,该模式下所有的输入数据以字节处理 if (tcsetattr(fd, TCSANOW, &tm) < 0) { // 设置上更改之后的设置 return -1; } ch = getchar(); if (tcsetattr(fd, TCSANOW, &tm_old) < 0) { // 更改设置为最初的样子 return -1; } return ch; }
其中 struct termios
,tcgetattr
,tcsetattr
,cfmakeraw
以及 getchar
的定义为:
typedef unsigned char cc_t; typedef unsigned int speed_t; typedef unsigned int tcflag_t; #define NCCS 32 struct termios{ tcflag_t c_iflag; /* input mode flags */ tcflag_t c_oflag; /* output mode flags */ tcflag_t c_cflag; /* control mode flags */ tcflag_t c_lflag; /* local mode flags */ cc_t c_line; /* line discipline */ cc_t c_cc[NCCS]; /* control characters */ speed_t c_ispeed; /* input speed */ speed_t c_ospeed; /* output speed */ }; int tcgetattr(int __fd, struct termios *__termios_p); void cfmakeraw(struct termios *__termios_p); int tcsetattr(int __fd, int __optional_actions, const struct termios *__termios_p); int getchar(void);
据此,我们可以通过 Rust 的 FFI 为 rust
实现一个 getch
:
#[cfg(target_os = "windows")] mod conio { use std::os::raw::c_int; extern "C" { pub fn _getch() -> c_int; } } #[cfg(target_os = "linux")] #[allow(non_camel_case_types)] mod conio { use std::os::raw::c_int; type tcflag_t = ::std::os::raw::c_uint; type speed_t = ::std::os::raw::c_uint; type cc_t = ::std::os::raw::c_uchar; const NCCS: usize = 32; const TCSANOW: i32 = 0; #[repr(C)] #[derive(Default, Copy, Clone)] struct termios { c_iflag: tcflag_t, c_oflag: tcflag_t, c_cflag: tcflag_t, c_lflag: tcflag_t, c_line: cc_t, c_cc: [cc_t; NCCS], c_ispeed: speed_t, c_ospeed: speed_t, } extern "C" { fn tcgetattr(__fd: c_int, __termios_p: *mut termios) -> c_int; fn tcsetattr(__fd: c_int, __optional_actions: c_int, __termios_p: *const termios) -> c_int; fn cfmakeraw(__termios_p: *mut termios); fn getchar() -> c_int; } #[allow(unused_mut, unused_assignments)] pub fn _getch() -> c_int { unsafe { let mut tm: termios = Default::default(); let mut tm_old: termios = Default::default(); let fd = 0; let mut ch: c_int; if tcgetattr(fd, &mut tm) < 0 { return -1; } tm_old = tm; cfmakeraw(&mut tm); if tcsetattr(fd, TCSANOW, &mut tm) < 0 { return -1; } ch = getchar(); if tcsetattr(fd, TCSANOW, &mut tm_old) < 0 { return -1; } ch } } } #[allow(unused_unsafe)] fn getch() -> char { unsafe { conio::_getch() as u8 as char } }
本文作者:Expector
本文链接:https://www.cnblogs.com/expector/p/18487584/getch
版权声明:本作品采用 CC BY-NC-ND 许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步