首页 / 操作系统 / Linux / C基础 一个可以改变Linux的函数getch
引言 - getch简述引用老的TC版本getch说明. (文章介绍点有点窄, 应用点都是一些恐龙游戏时代的开发细节)#include <conio.h>
/* * 立即从客户端得到输入的字符. 出错返回EOF */int __cdecl getch(void);记得三年之前看过一本书 <<C专家编程>> 有一章提到在立即从标准输入中得到输入字符(后面还介绍了一种linux实现, 对于现在linux版本不行了)。C专家编程 清晰 (有书签索引) PDF 下载 http://www.linuxidc.com/Linux/2012-05/60077.htm那位作者评价就是, 由于linux对于""getch""支持的不友好, 导致了linux错失了很多游戏开发人员. 当然现在版本, window 上也没有这个函数了. 改成下面这个挫的样子#include <conio.h>_Check_return_ _DCRTIMP int __cdecl _getch(void);总得而言""立即交互"" 是游戏开发的入口. 很有必要.前言 - 从实际例子中了解getch 现在Visual Studio 2015 Update3 中测试一段 getch 立即得到结果的代码 main.c#include <stdio.h>#include <stdlib.h>#include <conio.h>/* * 制作等待, 函数 */int main(int argc, char * argv[]) {printf("请输入任意字符结束程序......");int rt = _getch();printf("%d => %c
", rt, rt);rt = _getch();printf("%d => %c
", rt, rt);system("pause");return 0;}运行结果从上可以看出, _getch 名字变了, 但是功能和getch没有变化.这里我们封装一下. 看新的文件, 一个演示小demo#include <stdio.h>#include <conio.h>/* * 定义统一接口 sh_getch 理解得到玩家输入 *: 返回 输入int值, 错误为EOF */#define sh_getch _getch/* * 等待函数 */static void _pause(void) {printf("请按任意键继续. . .");
rewind(stdin);sh_getch();}/* * 继续等待函数 */int main(int argc, char * argv[]) {_pause();return 0;}来替代原先的 window 上 的 system("pause"), linux 上 pause(). rewind 重置文件FILE * 流, 清除输入流保证当前流是干净的.正文 - linux上实现一个getch, 立即接收 linux 需要借助 termio.h 终端控制头文件. 主要实现如下#include <termio.h>/* * 得到用户输入的一个字符 *: 返回得到字符 */int sh_getch(void) {int cr;struct termios nts, ots;if (tcgetattr(0, &ots) < 0) // 得到当前终端(0表示标准输入)的设置return EOF;nts = ots;cfmakeraw(&nts); // 设置终端为Raw原始模式,该模式下所有的输入数据以字节为单位被处理if (tcsetattr(0, TCSANOW, &nts) < 0) // 设置上更改之后的设置return EOF;cr = getchar();if (tcsetattr(0, TCSANOW, &ots) < 0) // 设置还原成老的模式return EOF;return cr;}主要是设置终端为原始接收字符模式, 可以接收立即返回, 随后还原老的环境设置. 终端缓冲, 也是出于效率考虑, 否则编程太复杂了.同样测试 一个 getch.c #include <stdio.h>#include <termio.h>/* * 得到用户输入的一个字符 *: 返回得到字符 */int sh_getch(void);/* * 测试标准快速输入 */int main(int argc, char * argv[]) {int ch;printf("请按任意键继续. . .");ch = sh_getch();printf("%d => %c
", ch, ch);ch = sh_getch();printf("%d => %c
", ch, ch);return 0;}linux上演示结果 gcc -Wall -ggdb3 -o getch.out getch.c一切正常. 到这里我们关闭getch跨平台实现细节都确定了. 那么我们实现一个跨平台的getch版本. 先看头文件声明部分(*.h 文件插入)./* * error=> 以后再说 * 跨平台的丑陋从这里开始 * __GNUC=> linux 平台特殊操作 * __MSC_VER=> window 平台特殊操作 */#ifdef __GUNC__// 下面是依赖GCC编译器实现#include <termio.h>/* * 得到用户输入的一个字符 *: 返回得到字符 */int sh_getch(void);#elif _MSC_VER // 下面是依赖Visual Studio编译器实现#include <conio.h>// window 上用_getch 替代了getch, 这里为了让其回来#define sh_getch_getch#else#error "error : Currently only supports the Visual Studio and GCC!"#endif再看实现部分 (*.c 文件中插入)// 为linux扩展一些功能#if defined(__GUNC__)/* * 得到用户输入的一个字符 *: 返回得到字符 */int sh_getch(void) {int cr;struct termios nts, ots;if (tcgetattr(0, &ots) < 0) // 得到当前终端(0表示标准输入)的设置return EOF;nts = ots;cfmakeraw(&nts); // 设置终端为Raw原始模式,该模式下所有的输入数据以字节为单位被处理if (tcsetattr(0, TCSANOW, &nts) < 0) // 设置上更改之后的设置return EOF;cr = getchar();if (tcsetattr(0, TCSANOW, &ots) < 0) // 设置还原成老的模式return EOF;return cr;}#endif 这就是getch跨平台实现的关键了. 从这里开始,你就可以构建自己喜欢的游戏了, 通过 sh_getch 入口开始. 预备下次重构C字符串,再下次采用simplec框架重写一个老的灭龙传说V2.0.0游戏, 让其支持跨平台, 并支持配置扩展.