如何在D2(Phobos)中进行单键击?

bfo*_*ops 8 keyboard d input phobos

是否有一种简单的跨平台方式可以使用Phobos在D2中进行单次击键?

例如,"按任意键继续..."提示,或Brainfuck翻译.

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

jgo*_*ula 5

我已经对这个问题进行了一些研究,我发现,虽然D 1.0下的Phobos库正好以你需要的形式存在std.c.stdio.getch(),但D 2.0缺乏这个功能.Phobos中的其他标准输入函数似乎都没有您想要的行为.

据我了解,这是因为所需的行为(即,不需要Enter键的单个字符)是非标准的,必须以相对丑陋,特定于平台的方式实现.(在它的初始形式中,该函数getch存在于C中<conio.h>,这是一个特定于DOS的标题,尽管不是标准C库的一部分,它已成为事实上的跨平台标准.)显然,Phobos运行时库的维护者决定在清理程序库的名称中删除这一特定的向后兼容功能,但这是以此功能为代价的.

手动申报

据说,您可以通过将此函数添加到源文件来解决此缺失的函数声明:

extern (C) int getch();
Run Code Online (Sandbox Code Playgroud)

但是,我发现这会产生一个链接器错误,表明该函数已完全从运行时库中删除,而不是仅仅删除其声明std.c.stdio.这当然值得一试 - 它可能会在您的系统和编译器上运行,我真的不知道.

编辑2:这实际上似乎适用于Windows; 它在Linux方面对我失败了.似乎Windows下的DMD首先链接到Phobos/D运行时(phobos.lib),然后是C运行时(snn.lib); 但是,在Linux上,DMD链接到一个提供两个部分的运行时库.这种差异似乎导致与未声明的功能(getch其中)的链接仅适用于Windows.如果Windows是您唯一关注的平台,那么此解决方案可能是合适的.如果您需要更多跨平台兼容性,请继续阅读.

ncurses的

另一种可能性是使用该ncurses库.它实现了一个getch绝对可以满足您需求的功能 - 前提是您可以为库找到D绑定或只使用C接口.请注意,它需要一个smidgen更多的设置,而不仅仅是调用你想要的功能; 这个帖子有关于此事的更多信息.

D 1.0

现在,对于一些相当丑陋的解决方案.使用D 1.0将允许您在Phobos标准库中找到您需要的内容 - 但这显然需要使用该语言的旧版本,我个人并不认为标准库中缺少一个控制台IO功能是合理的使用旧版本的D.

我相信Tango 在转向D 2.0时也失去了getch声明(下tango.stdc.stdio),但我对Tango的了解非常有限,所以我可能错了.

自己写吧

如果你有决心,你可以自己写getch.我无法找到getch使用谷歌代码搜索的跨平台C实现,这让我对一个相对简单的,10行或类似功能实现的可能性感到悲观,可以简单地适应D.

另一方面,Walter Bright - 你知道,设计 D语言的人 - 在这里提供了这种功能的D实现.但是,即使这看起来有些过时,因为其中一个符号cfmakeraw在当前版本的DMD2编译器下未定义.然而,它真的很接近成为一个可行的解决方案.


And*_*vić 5

在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());
}
Run Code Online (Sandbox Code Playgroud)

它甚至可能适用于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
}
Run Code Online (Sandbox Code Playgroud)