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

时间:2011-03-21 00:27:19

标签: input keyboard d phobos

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

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

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

2 个答案:

答案 0 :(得分:5)

我已经对此事进行了一些研究,我发现,虽然D 1.0下的Phobos库正好以std.c.stdio.getch()的形式提供了所需,但D 2.0缺少此功能。 Phobos中的其他任何标准输入函数似乎都没有您想要的行为。

据我所知,这是因为所需的行为(即,不需要Enter按键获得单个字符)是非标准的,必须以相对丑陋的,特定于平台的方式实现。 (在其初始形式中,函数getch存在于C <conio.h>中,这是一个特定于DOS的标题,尽管不属于标准C库,但已成为事实上的跨平台标准。)显然,Phobos运行时库的维护者决定以更清晰的库的名义去除这一特定的向后兼容功能,但这是以牺牲这一功能为代价的。

手动声明

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

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的

另一种可能性是使用ncurses库。它实现了一个getch函数,它肯定会做你想要的 - 只要你很酷找到库的D绑定或只是使用C接口。请注意,它需要一个smidgen更多的设置,而不仅仅是调用你想要的功能; this thread提供了有关此事的更多信息。

D 1.0

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

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

自己写下

如果你确定了,你可以自己编写getch。我无法使用Google Code Search找到getch的跨平台C实现,这让我对一个相对简单的10行或类似功能实现的可能性感到悲观,适应D。

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

答案 1 :(得分: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());
}

它甚至可能适用于D1,但我还没有尝试过。

这是从Walter's post修改的Linux版本:

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
}