当前位置: 首页 > news >正文

让控制台支持 ANSI 转义序列,输出下划线、修改颜色或其他控制

各种操作系统的控制台都支持 ANSI 转义序列(ANSI Escape Code)。使用转义序列,可以对控制台进行很多额外的定制,例如修改颜色、修改标题栏,将文字添加下划线等。

当然,.NET 已经帮助我们封装了很大的一部分功能了,我们重点可以放在 .NET 没有封装的那部分上。


基本的准备代码

在开始之前,我们先添加一些基础性代码,这是对系统核心功能的调用。

const int STD_OUTPUT_HANDLE = -11;
const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004;

[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetStdHandle(int nStdHandle);

[DllImport("kernel32.dll")]
static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);

[DllImport("kernel32.dll")]
static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);

在 Main 函数中,添加一些调用:

static void Main(string[] args)
{
    Console.Title = "Walterlv.Demo";

    var handle = GetStdHandle(STD_OUTPUT_HANDLE);
    GetConsoleMode(handle, out var mode);
    mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
    SetConsoleMode(handle, mode);

    // 我们准备在这里添加新的代码。

    Console.Read();
}

开始使用 ANSI 转义序列

添加下划线

const string UNDERLINE = "\x1B[4m";
const string RESET = "\x1B[0m";
Console.WriteLine($"Some {UNDERLINE}underlined{RESET} text");

下划线转义
▲ 下划线转义

修改颜色

const string RED = "\x1B[31m";
Console.WriteLine($"Some {UNDERLINE}underlined{RESET} and {RED}red{RESET} text");

颜色转义
▲ 颜色转义(当然,.NET 封装有 API)

其他转义序列

其他转义序列,可阅读 ANSI escape code - Wikipedia。不过 Windows 能支持的并不多。

关于颜色,不同控制台上对于相同转义序列的颜色值和颜色支持程度也不同。

关于 ENABLE_VIRTUAL_TERMINAL_PROCESSING

这是用来开启虚拟终端处理的一个标识,Windows 从一开始就默认关闭这个标识,必须通过 SetConsoleMode 手工开启。虽然在 10.0.10586 版本时短暂开启了一个版本,随后在 10.0.14393 中又再次默认关闭了。


参考资料

  • SetConsoleMode function - Windows Console - Microsoft Docs
  • Win10 New Console: Enable ENABLE_VIRTUAL_TERMINAL_PROCESSING by default (or with a flag) · Issue #92 · rprichard/winpty
  • (Re?)enable ENABLE_VIRTUAL_TERMINAL_PROCESSING by default – Welcome to the Windows developer feedback site!
  • ANSI escape code - Wikipedia
  • c# - adding text decorations to console output - Stack Overflow
  • Windows 10 Command Prompt: New Console vs. Legacy Console - Password Recovery

相关文章:

  • 在 GitHub 公开仓库中隐藏自己的私人邮箱地址
  • Win32 程序在启动时激活前一个启动程序的窗口
  • C#/.NET 读取或修改文件的创建时间和修改时间
  • 通过解读 WPF 触摸源码,分析 WPF 插拔设备触摸失效的问题(问题篇)
  • .NET 中各种混淆(Obfuscation)的含义、原理、实际效果和不同级别的差异(使用 SmartAssembly)
  • .NET 中 GetProcess 相关方法的性能
  • 常用输入法快速输入自定义格式的时间和日期(搜狗/QQ/手心/微软拼音)
  • 好的框架需要好的 API 设计 —— API 设计的六个原则
  • .NET/C# 使用反射注册事件
  • .NET/C# 判断某个类是否是泛型类型或泛型接口的子类型
  • .NET/C# 使用反射调用含 ref 或 out 参数的方法
  • WPF 多线程 UI:设计一个异步加载 UI 的容器
  • .NET 命令行参数包含应用程序路径吗?
  • 分析现有 WPF / Windows Forms 程序能否顺利迁移到 .NET Core 3.0(使用 .NET Core 3.0 Desktop API Analyzer )
  • C# 空合并操作符(??)不可重载?其实有黑科技可以间接重载!
  • @jsonView过滤属性
  • [ 一起学React系列 -- 8 ] React中的文件上传
  • 【干货分享】SpringCloud微服务架构分布式组件如何共享session对象
  • canvas 五子棋游戏
  • flask接收请求并推入栈
  • golang中接口赋值与方法集
  • HomeBrew常规使用教程
  • Java Agent 学习笔记
  • JAVA 学习IO流
  • mysql常用命令汇总
  • PAT A1120
  • Python 使用 Tornado 框架实现 WebHook 自动部署 Git 项目
  • React as a UI Runtime(五、列表)
  • zookeeper系列(七)实战分布式命名服务
  • 服务器之间,相同帐号,实现免密钥登录
  • 记录一下第一次使用npm
  • 理解在java “”i=i++;”所发生的事情
  • 力扣(LeetCode)21
  • 模型微调
  • 前端知识点整理(待续)
  • 浅析微信支付:申请退款、退款回调接口、查询退款
  • 时间复杂度与空间复杂度分析
  • 阿里云API、SDK和CLI应用实践方案
  • 没有任何编程基础可以直接学习python语言吗?学会后能够做什么? ...
  • # 再次尝试 连接失败_无线WiFi无法连接到网络怎么办【解决方法】
  • $分析了六十多年间100万字的政府工作报告,我看到了这样的变迁
  • (k8s中)docker netty OOM问题记录
  • (react踩过的坑)antd 如何同时获取一个select 的value和 label值
  • (附源码)计算机毕业设计ssm本地美食推荐平台
  • (译)计算距离、方位和更多经纬度之间的点
  • (转)C#开发微信门户及应用(1)--开始使用微信接口
  • (转载)OpenStack Hacker养成指南
  • *_zh_CN.properties 国际化资源文件 struts 防乱码等
  • .htaccess配置常用技巧
  • .NET 中创建支持集合初始化器的类型
  • .NET6使用MiniExcel根据数据源横向导出头部标题及数据
  • .NET开发人员必知的八个网站
  • .NET开源的一个小而快并且功能强大的 Windows 动态桌面软件 - DreamScene2
  • .NET中的Exception处理(C#)
  • .php结尾的域名,【php】php正则截取url中域名后的内容