如何使用 getc() 在 D 中获取单个按键?

How to get single keypress in D with getc()?

我需要在控制台中获取用户输入 (y/n) 按键。

我该怎么做?我知道我可以使用 readln,但还有其他方法吗?我正在尝试使用 getc()

import std.stdio;
import std.string;
import std.stream;

void main()
{
    while (getc() != 'y') 
    {
    writeln("try again");
    }
}

但我收到错误消息:

source\app.d(6): Error: function core.stdc.stdio.getc (shared(_iobuf)* stream) is not callable using argument types (File)

下一次尝试:

 char [] checkYesNo() @property
    {
        char [] key;
        while(readln(key) != 'y')
        {

        }
        return key;

    }

此代码编译通过,但在执行时因奇怪错误而失败 "Error executing command run"

错误是因为 phobos 与运行时冲突。

std.stdio 公开导入 core.stdc.stdio,它们都定义了 stdin,但类型不同。 getc() 实际上只是调用 fgetc( stdin ),因此当运行时尝试调用 getc() 时,它会传入 std.stdio 中的 stdin 而不是 [=13] 中的正确的 stdin =], 导致错误.

解决冲突的最佳方法是将 core.stdc.stdio 别名设为其他名称,然后使用完全限定名称。

import std.stdio;

void main()
{
    while (getc() != 'y') 
    {
        writeln("try again");
    }
}

auto getc()
{
    import stdc = core.stdc.stdio;
    return stdc.getc( stdc.stdin );
}

但请注意 getc() 在内部使用缓冲区,并且不会 return 直到用户按下回车键,此时它从缓冲区读取第一个字符并且 returns that, and will continue to read the next char from the buffer for subsequent calls until it reads the end。因此在终端 window 中输入 nnn<enter> 会导致 try again 被打印 3 次。如果你想要一个 return 不需要回车键的单个字符的方法,你需要寻找一个库解决方案,C 或 D 中都没有标准函数。

如果您不关心 cross-platform 解决方案,可以使用 Windows-specific header 定义不使用缓冲区的 getch() 函数和 returns 在每次击键时,而不是在输入时。只需将其添加到您的代码中,并将对 getc() 的调用替换为对 getch().

的调用
extern( C ) int getch();

我的 terminal.d

有一个可以单按的图书馆

https://github.com/adamdruppe/arsd/blob/master/terminal.d

它看起来比实际更复杂。这是获取单个密钥的示例:

import terminal; 
void main() { 
  auto terminal = Terminal(ConsoleOutputType.linear); 
  auto input = RealTimeConsoleInput(&terminal, ConsoleInputFlags.raw); 
  terminal.writeln("Press any key to exit"); 
  auto ch = input.getch(); 
  terminal.writeln("Bye!"); 
}   

要构建,请将 terminal.d 放入您的文件夹,然后将它们一起编译:dmd yourfile.d terminal.d.

首先,您构建一个终端。这两种类型是线性的或蜂窝状的。 Linear 一次输出一行,cellular 在控制台中变为 "full screen"。

然后,您根据该终端创建一个输入结构。 ConsoleInputFlags 说的是你想要的:你想要回声吗?鼠标输入?等。raw 是最简单的一个:它会向您发送纯键盘输入,因为它们发生的情况相对较少。

然后您可以写入终端并从输入中获取字符。 input.getch() 行获取单个字符,当某些内容可用时立即返回而无需缓冲。 input 上可用的其他功能包括 kbhit,其中 returns 如果按下某个键则输入可用,则为 true,否则为 false - 对实时游戏有用,正在检查一个计时器,或 nextEvent,它提供完整的输入支持,包括鼠标事件。 terminal.d 源代码中的演示显示了完全支持的内容:

https://github.com/adamdruppe/arsd/blob/master/terminal.d#L2265

terminal 本身的另一个有用的便利功能是 getline,它一次抓取整行,但也允许用户编辑它并提供历史记录和自动完成。 terminal 还提供了一个名为 color 的功能来进行彩色输出,而 moveTo 在蜂窝模式下很有用,可以在屏幕上移动光标。如果您有兴趣,请浏览代码以了解更多信息。

怎么样:

import std.stdio;

void main(){
    writefln("Enter something: ");
    char entered;
    do{ 
        readf(" %c\n", &entered);
        writefln("Entered: %s", entered);
    }while(entered != 'y');
}

重要的一点是“%c\n”。 %c 告诉 readf 匹配字符而不是字符串。