• Linux终端控制与ANSI转义序列


    1 前言

    Windows系统中,我们可以通过系统提供的接口操作控制台缓冲区的显示。那么在linux平台应该如何实现呢?答案就是ANSI转义序列
    在计算机系统中,ANSI转义码(或转义序列)是一种使用带内信号控制视频文本终端的格式、颜色和其他输出选项的方法。
    为了编码这种格式化信息,特定的字节序列被嵌入到文本中,终端将查找并将其解释为命令,而不是字符代码。

    2 CSI

    实际上,ANSI转义序列的范围比较大,包括ASCII码表中的被称为Control characters 控制字符(C0代码)之外,还包括了ESC字符开头的C1代码。
    而这里介绍的就是C1代码中最常用的部分CSI序列
    ANSI转义序列中以 ESC [ 开头的叫作 Control Sequence Introducer,简写为 CSI
    以 CSI 开头的指令有很多,大致可分四类:光标控制、屏幕控制、和字符渲染(Graphic Rendition)指令。
    CSI序列的语法如下所示:

    0x1B + "[" + [[0-9]*[;]] + <fun>
    
    • 1
    • 开始,0x1B 是ansi escape code开始的标准
    • 其次,[ 是CSI (Control Sequence Introducer)
    • 然后,中间部分由0个或者多个数字组成,是函数的参数,多个参数之间由分号进行分割
    • 最终,一个字母代表需要调用的函数名

    CSI (Control Sequence Introducer) 各部分的字符范围如下:

    组成部分字符范围ASCII
    参数字节0x30–0x3F0–9:;<=>?
    中间字节0x20–0x2F空格、!"#$%&’()*+,-./
    最终字节0x40–0x7E@A–Z[]^_`a–z{
    2.1 光标控制
    控制码说明
    \033[nA光标上移 n(默认1) 行 <<若至屏幕顶端则无效>>
    \033[nB光标下移 n (默认1)行 <<若至屏幕底端则无效>>
    \033[nC光标前移 n (默认1)列 <<若至屏幕右端则无效>>
    \033[nD光标后退 n (默认1)列 <<若至屏幕左端则无效>>
    \033[nE光标下移 n (默认1)行 <<非标准>>
    \033[nF光标上移 n (默认1)行 <<非标准>>
    \033[nG光标移动至当前行n(默认1)列 <<非标准>>
    \033[x;yH光标移动至x行y列(默认从1开始,左上角)
    \033[s保存光标位置
    \033[u取出保存的光标位置来使用
    \033[?25l隐藏光标
    \033[?25h显示光标
    2.2 屏幕控制
    控制码说明
    \033[nJ清除指定范围屏幕。0:光标位置至屏幕末尾;1:光标位置至屏幕开头;2:全屏幕
    \033[nK擦除行中指定范围列。0:光标位置至行尾;1:光标位置至行头;2:整行
    \033[nS整页向上滚动n行。<<非标准>>
    \033[nT整页向下滚动n行。<<非标准>>
    2.3 字符渲染

    字符渲指令全称 Select Graphic Rendition,简写为 SGR。其格式为 CSI n m,以数字开头,并以 m 结尾,n 的取值范围是 0-107。又可以分成两类,一类控制字符显示样式,另一类控制显示颜色。

    代码含义
    0所有属性 OFF,即返回正常显示模式 (Normal)
    1粗体(Bold)/高亮度显示 (Bright)
    3斜体(未广泛支持)
    4下划线
    5闪烁显示
    7反显(前景色与背景色交换)
    39默认前景色
    49默认背景色

    设置颜色:

    前景背景颜色
    3040黑色
    3141红色
    3242绿色
    3343黄色
    3444蓝色
    3545紫红色
    3646青蓝色
    3747白色

    3 示例

    3.1 清除屏幕
      printf("\x1b[2J"); // 清屏幕
      printf("\x1b[?25l"); // 设置光标不可见
    
    • 1
    • 2
    3.2 禁用回显
      struct termios setting;
      tcgetattr(STDIN_FILENO, &setting); // 禁用回显
      setting.c_lflag &= ~ECHO;
      tcsetattr(STDIN_FILENO, TCSANOW, &setting);
    
    • 1
    • 2
    • 3
    • 4
    3.3 获取标准输入
      fd_set io;
      FD_SET(STDIN_FILENO, &io);
      timeval timeout = {sec, usec};
      select(STDIN_FILENO + 1, &io, NULL, NULL, &timeout); // 监听标准输入
    
      char cmd[10] = {0};
      read(STDIN_FILENO, cmd, sizeof(cmd)); // read读取标准输入避免循环getc阻塞
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    3.4 数据输出到屏幕
      printf("\x1b[2;1H"); // 光标定位至第二行开头
      printf("\x1b[30;47m"); // 设置白底黑字
      fill(header, strlen(header)); // 输出
      printf("\x1b[39;49m"); // 设置默认颜色
    
    // 光标移动至指定行的行首
    void move(int y) { printf("\x1b[%d;1H", y); }
    
    // 输出字符串同时清除光标后的列
    void print(const char* str) { printf("%s\x1b[K", str); }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4 完整示例

    平台实现简单的进程信息查看。simple_taskmgr

  • 相关阅读:
    Docker系列——Grafana+Prometheus+Node-exporter服务器监控平台(一)
    为什么嵌入通常优于TF-IDF:探索NLP的力量
    Android修改开机动画
    [附源码]Python计算机毕业设计SSM京津冀区域产学研项目管理信息系统(程序+LW)
    商业合作保密协议
    LOJ #10134. 「一本通 4.4 练习 1」Dis
    html5+css简易实现图书网联系我们页面
    Windows10安装配置Docker客户端和WSL2与Hyper-V虚拟机
    红黑树-自平衡二叉搜索树
    移动端高级开发
  • 原文地址:https://blog.csdn.net/qq_38933606/article/details/133615079