zoukankan      html  css  js  c++  java
  • 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
    ", 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游戏, 让其支持跨平台, 并支持配置扩展.

    后记   -   未来有 ∞ 次

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

  • 相关阅读:
    运用vue-awesome-swiper实现一个slide居中一个缩小显示
    IntersectionObserver
    leetcode 加一
    Cuda总结
    webrtc 视频数据 采集 发送 接收 显示
    webrtc ice代码流程走读
    webrtc sdp 组建 流程以及 sdp协议解析
    webrtc 视频参数配置
    webrtc 线程整理
    webrtc turn协议
  • 原文地址:https://www.cnblogs.com/life2refuel/p/5720043.html
Copyright © 2011-2022 走看看