我有一个 C/C++ 程序,为 Windows 编写,并用 Visual Studio 编译。它是一个命令行工具,这意味着它可以合理地在 Cygwin Bash 下运行,可能在 MinTTY 中,并且它的一些用户现在正在这样做。
我想改变我的程序,让它与 Cygwin 一起玩得更好。
我的程序目前使用Windows 控制台 API来输出漂亮的彩色文本并管理光标,并且通常是“交互式的”(或 1980 年代“交互式”定义的“交互式”),至少当它的输出不是管道传输到文件。
为了让我的程序更好地与 Cygwin 配合使用,我可以让它发出 ANSI\x1B[...
转义码而不是调用控制台 API,但真正的问题是知道何时这样做。
我认为有四种情况:
作为交互式 Windows 控制台程序调用。-->(使用控制台 API。)
作为普通的 Windows 控制台程序调用,但用户在某处通过管道传输其输出。-->(根本不发出任何样式或交互式调用。)
由 Bash 或在 MinTTY 下作为交互式程序调用。-->(使用 ANSI 转义码。)
由 Bash 调用,但用户将其输出传送到某处。-->(根本不发出任何样式或交互式调用。)
我可以通过测试句柄是否GetConsoleMode()
成功来区分案例1 ;stdout
如果成功,我肯定有一个 Windows 控制台,当我打开代码以使用控制台 API 时就是这种情况。
我想以不同的方式对待案例 3 并使用 ANSI 代码,但不幸的是,案例 2、3 和 4 似乎几乎无法区分:
- 对于所有三种情况,
stdout
句柄似乎只是一个不透明的对象。FILE_TYPE_PIPE
- 我可以使用
OSTYPE
环境变量,至少猜测我在 Cygwin 下,它将案例 2 与案例 3 和 4 区分开来。 - 如果我可以链接到
cygwin1.dll
,我可能会以某种方式使用它isatty()
,但我不能链接到它,因为我的许多用户没有(也不会)安装 Cygwin。(而且我根本不相信这会奏效,即使它是可能的。) - MSVC 的本地人
_isatty()
认为 Cygwin Bash 是一个管道,而不是一个交互式外壳,因为它只是在底层使用GetFileType()
。
简而言之,我看不出将案例 3 与案例 4 分开的明显方法。
现在,我将案例 3 与案例 2 和案例 4 完全相同,Cygwin 用户(包括我自己)得到了糟糕的玻璃电传打字机交互,而不是友好的交互式全屏显示,我真的很想解决这个问题。
那么有什么方法可以将交互式Cygwin 调用与其他调用区分开来,以便我的本机 Windows 程序在被 Cygwin Bash 或其他类似的 shell 调用时表现得很好?
(重要提示: 有一个解决方案不在讨论范围内:该程序不会被编译为原生 Cygwin 程序。这是一个 Windows 程序,它是使用 Microsoft 工具链编译的,不会使用 GCC 编译。目标是更改/更新它以使其在 Cygwin 下表现得尽可能好——而不实际链接到任何 Cygwin DLL。我只能合理地为 Windows 分发一个可执行文件,而不是两个。)