C基础 一个可以改变linux的函数getch

引言  -  getch简述

  引用老的TC版本getch说明. (文章介绍点有点窄,  应用点都是一些恐龙游戏时代的开发细节)

#include <conio.h>

/*
 * 立即从客户端得到输入的字符. 出错返回EOF
 */
int __cdecl getch(void);

记得三年之前看过一本书 <<C专家编程>> 有一章提到在立即从标准输入中得到输入字符(后面还介绍了一种linux实现, 对于现在linux版本不行了).

那位作者评价就是, 由于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\n", rt, rt);
    rt = _getch();
    printf("%d => %c\n", 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\n", ch, ch);

    ch = sh_getch();
    printf("%d => %c\n", 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游戏, 让其支持跨平台, 并支持配置扩展.

后记   -   未来有 ∞ 次

Get Over  http://music.163.com/#/song?id=22771653

时间: 2024-10-05 08:34:43

C基础 一个可以改变linux的函数getch的相关文章

[C++基础]一个比较常用的配置文件/初始化文件读取程序

在编程中,我们经常会遇到一些配置文件或初始化文件.这些文件通常后缀名为.ini或者.conf,可以直接用记事本打开.里面会存储一些程序参数,在程序中直接读取使用.例如,计算机与服务器通信,服务器的ip地址,段口号可以存储于ini文件中.这样如果我想换另外一台服务器时,直接将ini文件中的ip地址改变即可,程序源代码不需要做任何修改. 本文将分享一段常用代码,用于读取配置文件中的信息.本文中的代码为C语言编写,在ubuntu 12.04 linux系统中调试没有问题.具体操作如下: 1. 首先用记

作业3:构造一个简单的Linux系统MenuOS 20135115臧文君

构造一个简单的Linux系统MenuOS 注:作者:臧文君,原创作品转载请注明出处,<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.Linux内核源代码介绍 1.根目录 arch/x86目录下的代码是我们重点关注的,arch中包括支持不同CPU的源代码. init目录下包含内核启动相关的代码,如main.c(start_kernel函数相当于普通C程序的main函数,是Linux内核初始化的起点). ipc

HOOK API (一)——HOOK基础+一个鼠标钩子实例

HOOK API (一)——HOOK基础+一个鼠标钩子实例 0x00 起因 最近在做毕业设计,有一个功能是需要实现对剪切板的监控和进程的防终止保护.原本想从内核层实现,但没有头绪.最后决定从调用层入手,即采用HOOK API的技术来挂钩相应的API,从而实现预期的功能.在这样的需求下,就开始学习了HOOK API. 0x01什么是HOOK API HOOK(钩子,挂钩)是一种实现Windows平台下类似于中断的机制[24].HOOK机制允许应用程序拦截并处理Windows消息或指定事件,当指定的

linux API函数大全

还没有认真研读过,今晚在其他博客上找了比较久,今晚时间也不多了,等有空再细看 先复制先 获取当前执行路径:getcwd 1. API之网络函数 WNetAddConnection 创建同一个网络资源的永久性连接  WNetAddConnection2 创建同一个网络资源的连接  WNetAddConnection3 创建同一个网络资源的连接  WNetCancelConnection 结束一个网络连接  WNetCancelConnection2 结束一个网络连接  WNetCloseEnum

Linux mmap函数简介

一.简介 Linux提供了内存映射函数mmap, 它把文件内容映射到一段内存上(准确说是虚拟内存上), 通过对这段内存的读取和修改, 实现对文件的读取和修改, 先来看一下mmap的函数声明: 头文件: <unistd.h> <sys/mman.h> 原型: void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offsize); 返回值: 成功则返回映射区起始地址, 失败则返回MAP_FAI

动态替换Linux核心函数的原理和实现

转载:https://www.ibm.com/developerworks/cn/linux/l-knldebug/ 动态替换Linux核心函数的原理和实现 在调试Linux核心模块时,有时需要能够实时获取内部某个路径上的某些函数的执行状态,例如查看传入的变量是否是期望的值,以便判断整个执行流程是否依然正常.由于系统运行时的动态性,使得在执行之前无法预先知道在执行路径的什么地方可能出现问题,因此只能在整个路径上增加许多不必要的信息查询点,造成有用的状态信息被淹没,而且这种增加信息输出的方式(一般

linux fcntl函数

linux fcntl函数 #include <unistd.h>#include <fcntl.h>int fcntl(int fd, int cmd);int fcntl(int fd, int cmd, long arg);int fcntl(int fd, int cmd, struct flock *lock); [描述]fcntl()针对(文件)描述符提供控制.参数fd是被参数cmd操作(如下面的描述)的描述符.针对cmd的值,fcntl能够接受第三个参数int arg

linux 线程函数大全

Technorati 标签: Linux thread 索引: 1.创建线程pthread_create 2.等待线程结束pthread_join 3.分离线程pthread_detach 4.创建线程键pthread_key_create 5.删除线程键pthread_key_delete 6.设置线程数据pthread_setspecific 7.获取线程数据pthread_getspecific 8.获取线程标示符pthread_self 9.比较线程pthread_equal 10.一次

linux crypt函数

linux crypt函数 1. crypt定义 #define _XOPEN_SOURCE /* See feature_test_macros(7) */ #include <unistd.h > char *crypt(const char *key, const char *salt); 上面是man 3 crypt看到的crypt函数定义. 从定义中看到要想使用crypt函数那么就得定义_XOPEN_SOURCE宏,有一些人只是把unistd.h包含进来,然后发现编译的时候出现cry