If this's helpfu|

Expector

园龄:2年9个月粉丝:0关注:0

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 termiostcgetattrtcsetattrcfmakeraw 以及 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 许可协议进行许可。

posted @   Expector  阅读(94)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起