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 }
}
C/C++ 以及 Rust 中的 getch() 实现的更多相关文章
- Rust 中的继承与代码复用
在学习Rust过程中突然想到怎么实现继承,特别是用于代码复用的继承,于是在网上查了查,发现不是那么简单的. C++的继承 首先看看c++中是如何做的. 例如要做一个场景结点的Node类和一个Sprit ...
- Rust 中的类型转换
1. as 运算符 as 运算符有点像 C 中的强制类型转换,区别在于,它只能用于原始类型(i32 .i64 .f32 . f64 . u8 . u32 . char 等类型),并且它是安全的. 例 ...
- Rust中的RefCell和内部可变性
RefCell Rust在编译阶段会进行严格的借用规则检查,规则如下: 在任意给定时间,要么只能有一个可变引用,要么只能有多个不可变引用. 引用必须总是有效. 即在编译阶段,当有一个不可变值时,不能可 ...
- Rust中的Slices
这个slice切片,python中有,go中有, 但确实,Rust中最严格. 精彩见如下URL: Rust 程序设计语言(第二版) 简体中文版 · GitBook (Legacy) https://k ...
- 刷完欧拉计划中难度系数为5%的所有63道题,我学会了Rust中的哪些知识点?
我为什么学Rust? 2019年6月18日,Facebook发布了数字货币Libra的技术白皮书,我也第一时间体验了一下它的智能合约编程语言MOVE,发现这个MOVE是用Rust编写的,看来想准确理解 ...
- 【译】Rust中的array、vector和slice
原文链接:https://hashrust.com/blog/arrays-vectors-and-slices-in-rust/ 原文标题:Arrays, vectors and slices in ...
- 【译】理解Rust中的闭包
原文标题:Understanding Closures in Rust 原文链接:https://medium.com/swlh/understanding-closures-in-rust-21f2 ...
- 【译】理解Rust中的局部移动
原文标题:Understanding Partial Moves in Rust 原文链接:https://whileydave.com/2020/11/30/understanding-partia ...
- 【译】理解Rust中的Futures (一)
原文标题:Understanding Futures In Rust -- Part 1 原文链接:https://www.viget.com/articles/understanding-futur ...
- 【译】理解Rust中的Futures(二)
原文标题:Understanding Futures in Rust -- Part 2 原文链接:https://www.viget.com/articles/understanding-futur ...
随机推荐
- 如何使用Python编写一个Lisp解释器
原文出处: Peter Norvig 译文出处: jnjc(@jnjcc) 本文有两个目的: 一是讲述实现计算机语言解释器的通用方法,另外一点,着重展示如何使用Python来实现Lisp方言Sch ...
- Git之清除历史记录操作
近期公司需要将之前代码仓库中的提交记录都清理,所以操作一下,记录一下步骤: 安全考虑: 有时候在提交代码时,不小心提交了敏感数据,如账号密码什么的,这样在历史记录中就可以查看到,这样很不安全,所以就需 ...
- Graylog之告警
官方文档:https://docs.graylog.org/en/3.0/index.html 前面我们已经了解了Graylog的搭建,以及日志的接入方法.我们知道graylog可以将收集的的日志通过 ...
- ZCMU-1110
思路:- 首先可以知道最少动就是从三个角对称的划分 因为不是对称划分则会出现破坏了正三角,后面还要重新对好 之后就可以进行推导(按三角形我没看懂) 其中设底上截出来的三角形的底为i,则上面就是n-2* ...
- Java8提供的Stream方式进行分组GroupingBy
有时我们需要对集合进行分组操作,这时可以使用Java8提供的Stream方式进行分组.挺好用的,此处记录下.直接贴code: Road实体: @Data @NoArgsConstructor @A ...
- m4 mac mini本地部署ComfyUI,测试Flux-dev-GGUF的workflow模型10步出图,测试AI绘图性能,基于MPS(fp16),优点是能耗小和静音
m4 mac mini已经发布了一段时间,针对这个产品,更多的是关于性价比的讨论,如果抛开各种补贴不论,价位上和以前发布的mini其实差别不大,真要论性价比,各种windows系统的mini主机的价格 ...
- cajviewer逆向分析-HN文件格式分析和010editor模板开发
文章首发于 https://mp.weixin.qq.com/s/7STPL-2nCUKC3LHozN6-zg 概述 本文介绍对cajviewer中对HN文件格式的逆向分析并介绍如何编写相应的010e ...
- LeetCode题集-9 - 回文数
题目:给你一个整数 x ,如果 x 是一个回文整数,返回 true :否则,返回 false . 回文数 是指正序(从左向右)和倒序(从右向左)读都是一样的整数. 例如,121 是回文,而 123 不 ...
- 用 Ingram 和 masscan 来扫描全网存在漏洞的camera
前言 大学的时候也写过和Ingram差不多的工具,不过那时候已经玩到没有兴致了,代码已不知道哪里去.没想到在Github看到了这个工具,实现思路和我的几乎一样,互联网就是这么神奇. Ingram的Gi ...
- IntelliJ IDEA 2020+Maven+SSM框架正常编译并与行后端代码时控制台的提示信息