是否有一种简单的跨平台方法可以使用 Phobos 在 D2 中获得单次击键?
例如,“按任意键继续...”提示或 Brainfuck 解释器。
我尝试过的所有方法都需要在传递输入之前按 Enter 键(例如 getchar())。
在 Windows 上使用 D2 的最简单的解决方案:
import std.stdio : writefln;
extern(C) int kbhit();
extern(C) int getch();
void main()
{
while(!kbhit())
{
// keep polling
// might use Thread.Sleep here to avoid taxing the cpu.
}
writefln("Key hit was %s.", cast(char)getch());
}
它甚至可能适用于 D1,但我还没有尝试过。
这是一个 Linux 版本,根据Walter 的帖子进行了修改:
import std.stdio : writefln;
import std.c.stdio;
import std.c.linux.termios;
extern(C) void cfmakeraw(termios *termios_p);
void main()
{
termios ostate; /* saved tty state */
termios nstate; /* values for editor mode */
// Open stdin in raw mode
/* Adjust output channel */
tcgetattr(1, &ostate); /* save old state */
tcgetattr(1, &nstate); /* get base of new state */
cfmakeraw(&nstate);
tcsetattr(1, TCSADRAIN, &nstate); /* set mode */
// Read characters in raw mode
writefln("The key hit is %s", cast(char)fgetc(stdin));
// Close
tcsetattr(1, TCSADRAIN, &ostate); // return to original mode
}
我对这个问题做了一些研究,我发现,虽然 D 1.0 下的 Phobos 库以 的形式完全有你需要的东西std.c.stdio.getch()
,但 D 2.0 缺少这个功能。Phobos 中的其他标准输入函数似乎都没有您想要的行为。
据我了解,这是因为所需的行为(即,在不需要 Enter 键的情况下获取单个字符)是相当不标准的,并且必须以相对难看的、特定于平台的方式实现。(在最初的形式中,该函数getch
存在于 C's<conio.h>
中,这是一个特定于 DOS 的头文件,尽管不是标准 C 库的一部分,但它已成为事实上的跨平台标准。)显然,Phobos 运行时库的维护者决定以更干净的库的名义去除这一特定的向后兼容功能,但以牺牲该功能为代价。
据报道,您可以通过将其添加到源文件中来解决这个丢失的函数声明:
extern (C) int getch();
但是,我发现这会产生一个链接器错误,表明该函数已从运行时库中完全删除,而不仅仅是将其声明从std.c.stdio
. 这当然值得一试——它可能会在你的系统和编译器上运行,我真的不知道。
编辑 2:这实际上似乎适用于 Windows;它在 Linux 方面对我来说失败了。Windows 下的 DMD 似乎首先链接到 Phobos/D 运行时(phobos.lib),然后是 C 运行时(snn.lib);但是,在 Linux 上,DMD 链接到一个提供这两个部分的运行时库。这种差异似乎导致与未声明函数(getch
其中)的链接只能在 Windows 上工作。如果 Windows 是您关心的唯一平台,那么此解决方案可能是合适的。如果您需要更多的跨平台兼容性,请继续阅读。
另一种可能性是使用ncurses
库。它实现了一个getch
肯定会做你想做的事情的函数——前提是你很擅长为库找到 D 绑定或只使用 C 接口。请注意,它需要更多的设置,而不仅仅是调用您想要的函数;这个线程有更多关于此事的信息。
现在,对于一些相当丑陋的解决方案。使用 D 1.0 可以让你在 Phobos 标准库中找到你需要的东西——但这显然需要使用该语言的旧的、更硬的版本,我个人认为标准库中缺少一个控制台 IO 功能并不是理由用于使用旧版本的 D。
我相信 Tango 在切换到 D 2.0 时也失去了它的getch
声明(下tango.stdc.stdio
),但我对 Tango 的了解非常有限,所以我可能错了。
如果你有决心,你可以写你自己的getch
. 我无法找到getch
使用Google Code Search的跨平台 C 实现,这让我对可以简单地适应 D 的相对简单、10 行左右的函数实现的可能性感到悲观。
另一方面,Walter Bright——你知道,设计D 语言的人——在这里提供了这种函数的 D 实现。然而,即使这样似乎也有些过时了,因为cfmakeraw
在当前版本的 DMD2 编译器下,符号之一是未定义的。然而,它真的很接近成为一个可行的解决方案。