Input 如何在D2(火卫一)中获得单次按键?

Input 如何在D2(火卫一)中获得单次按键?,input,keyboard,d,phobos,Input,Keyboard,D,Phobos,有没有一种简单、跨平台的方法可以使用火卫一在D2中点击一次键 例如,“按任意键继续…”提示或Brainfuck解释器 我尝试过的所有方法都需要在传递输入(例如getchar())之前按Enter键。我对此做了一些研究,我发现,虽然D1.0下的Phobos库以std.c.stdio.getch()的形式提供了您所需的功能,但D2.0缺少此功能。Phobos中的其他标准输入函数似乎都没有您想要的行为 据我所知,这是因为所需的行为(即,在不需要输入键的情况下获取单个字符)相当不标准,必须以相对丑陋、特

有没有一种简单、跨平台的方法可以使用火卫一在D2中点击一次键

例如,“按任意键继续…”提示或Brainfuck解释器


我尝试过的所有方法都需要在传递输入(例如getchar())之前按Enter键。

我对此做了一些研究,我发现,虽然D1.0下的Phobos库以
std.c.stdio.getch()的形式提供了您所需的功能,但D2.0缺少此功能。Phobos中的其他标准输入函数似乎都没有您想要的行为

据我所知,这是因为所需的行为(即,在不需要输入键的情况下获取单个字符)相当不标准,必须以相对丑陋、特定于平台的方式实现。(在最初的形式中,函数
getch
存在于C中,这是一个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
库。它实现了一个函数,如果您不介意为库查找D绑定,或者只使用C接口,那么它肯定会实现您想要的功能。请注意,它需要一点设置,而不仅仅是调用所需的函数;他有更多关于这件事的信息

D 1.0 现在,对于一些相当丑陋的解决方案。使用D 1.0可以让你在火卫一标准库中找到你需要的东西,但这显然需要使用更老、更硬的语言版本,我个人不认为标准库中缺少一个控制台IO函数可以作为使用旧版本D的理由

我相信在切换到D2.0之后,Tango也失去了它的
getch
声明(在
Tango.stdc.stdio
下),但是我对Tango的了解非常有限,所以我可能是错的

你自己写吧 如果你决定了,你可以自己写
getch
。我无法找到使用
getch
的跨平台C实现,这让我对一个相对简单的10行左右的函数实现的可能性感到悲观,因为它可以简单地适应D


另一方面,Walter Bright你知道,设计D语言的人提供了这种函数的D实现。然而,即使这样也似乎有些过时,因为在当前版本的DMD2编译器中,
cfmakeraw
是未定义的符号之一。但是,它几乎是一个可行的解决方案。

在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版本,修改自:


请说得更具体些。首被告或次被告?Phobos或Tango?在C语言中,非标准
conio.h
头中的
getch
函数满足您的需要。然而,从我所知道的,它不是在D的
std.c.*
中。我会继续查找。此线程包含一些相关信息:我只需按ENTER键继续…
并完成:\手册声明部分的补充:您可能可以将该函数声明添加到代码中,然后链接到数字MARS C++运行库,据我所知,它定义了<代码> GETCH < /C>。这可能行不通,但值得一提。另一个黑客解决方案是肯定的。你试过在你的系统上编译这个吗?在我的系统上(编译器是DMD2),我得到
kbhit
getch
的链接器错误。我相信它们已从运行时库中删除(有关详细信息,请参阅我的答案)-或者它可能只是我的编译器版本,我不能代表Windows版本。@jgottula我使用的是DMD 2.052
kbhit
getch
是在snn.lib中定义的,如果我没有弄错的话,它是编译器特定的库(?)。GDC也编译了这个例子,我使用的是Linux x86_64,DMD2.049(略落后于当前的2.052)。我将研究Linux端是否存在类似snn.lib的东西。也许这是平台特定的库差异(这并不奇怪,因为标准库名称空间中没有声明
kbhit
getch
)。snn.lib似乎是数字Mars C运行库(请参阅)。不幸的是,对应的Linux页面没有说明哪些库是哪些库。现在我发现了一些说明:在Windows端,链接器首先链接到phobos.lib(D运行时),然后链接到snn.lib(C运行时)。但是在Linux上,一切似乎都包含在libphobos2.a中
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
}