如何在 D2 (Phobos) 中获得单次击键?

发布于 2024-10-25 08:38:56 字数 140 浏览 6 评论 0原文

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

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

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

Is there a simple, cross-platform way to get a single keystroke in D2 using Phobos?

For instance, a "Press any key to continue..." prompt, or a Brainfuck interpreter.

All the methods I've tried require an Enter keypress before passing the input (getchar(), for instance).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

祁梦 2024-11-01 08:38:57

在 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 版本,修改自 沃尔特的帖子

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
}

The simplest solution that works with D2 on Windows:

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());
}

It might even work with D1, but I haven't tried it out.

Here's a Linux version, modified from Walter's post:

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
}
反目相谮 2024-11-01 08:38:57

我对这个问题做了一些研究,我发现,虽然 D 1.0 下的 Phobos 库以 std.c.stdio.getch() 的形式提供了您所需要的内容, D 2.0缺少这个功能。 Phobos 中的其他标准输入函数似乎都没有您想要的行为。

据我了解,这是因为所需的行为(即无需按 Enter 键即可获取单个字符)相当不标准,并且必须以相对丑陋的特定于平台的方式实现。 (在其最初形式中,函数 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

另一种可能性是使用 ncurses 库。它实现了一个 getch 函数,它肯定会做你想做的事情想要 — 前提是您愿意为库查找 D 绑定或仅使用 C 接口。请注意,它需要比仅仅调用您想要的函数更多的设置; 此帖子提供了有关此事的更多信息。

D 1.0

现在,我们来看看一些相当丑陋的解决方案。使用 D 1.0 可以让你在 Phobos 标准库中找到你需要的东西,但这显然需要使用该语言的旧的、更硬核的版本,而且我个人并不认为标准库中缺少一个控制台 IO 函数是合理的使用旧版本的 D。

我相信 Tango 在切换到 D 2.0 时也丢失了其 getch 声明(在 tango.stdc.stdio 下),但我的知识探戈极其有限,所以我可能是错的。

自己编写

如果您下定决心,可以编写自己的 getch。我无法使用 Google 找到 getch 的跨平台 C 实现代码搜索,这让我对一个相对简单的、大约 10 行左右的函数实现可以简单地适应 D 的可能性感到悲观。

另一方面,Walter Bright——你知道,那个人设计 D 语言 - 提供此类函数的 D 实现此处。然而,即使这似乎也有些过时,因为其中一个符号 cfmakeraw 在当前版本的 DMD2 编译器下未定义。然而,它确实非常接近于一个可行的解决方案。

I've done some research on the matter, and I've found that, while the Phobos library under D 1.0 had exactly what you need in the form of std.c.stdio.getch(), D 2.0 lacks this function. None of the other standard input functions in Phobos appear to have the behavior you want.

As I understand it, this is because the desired behavior (that is, getting a single character without the need for an Enter keypress) is rather nonstandard and has to be implemented in relatively ugly, platform-specific ways. (In its initial form, the function getch existed in C's <conio.h>, a DOS-specific header that has become somewhat of a de facto cross-platform standard despite not being part of the standard C library.) Evidently the maintainers of the Phobos runtime library decided to strip out this particular bit of backwards-compatible functionality in the name of a cleaner library, but at the expense of this functionality.

Manual declaration

Reportedly, you can get around this missing function declaration by adding this to your source file:

extern (C) int getch();

However, I have found that this produces a linker error, suggesting that the function was removed from the runtime library entirely, rather than merely having its declaration removed from std.c.stdio. It's certainly worth a try—it might happen to work on your system and compiler, I really don't know.

Edit 2: This actually seems to work on Windows; it failed for me on the Linux side. It appears that DMD under Windows first links to the Phobos/D runtime (phobos.lib), then the C runtime (snn.lib); however, on Linux, DMD links to one runtime library that supplies both parts. This difference appears to cause linkage to undeclared functions (getch among them) to only work on Windows. If Windows is the only platform you're concerned with, this solution is probably suitable. If you need more cross-platform compatibility, read on.

ncurses

Another possibility is to use the ncurses library. It implements a getch function that will definitely do what you want—provided that you're cool with finding D bindings for the library or just using the C interface. Be aware that it requires a smidgen more setup than just calling the function you want; this thread has more information on the matter.

D 1.0

Now, for some considerably uglier solutions. Using D 1.0 would allow you to find what you need in the Phobos standard library—but this obviously entails using the older, crustier version of the language and I personally do not find the lack of one console IO function in the standard library to be justification for using the old version of D.

I believe that Tango also lost its getch declaration (under tango.stdc.stdio) over the switch to D 2.0, but my knowledge of Tango is extremely limited, so I may be wrong.

Write it yourself

If you're determined, you could just write your own getch. I wasn't able to find a cross-platform C implementation of getch using Google Code Search, which leaves me pessimistic about the likelihood of a relatively simple, 10-line-or-so function implementation that could simply be adapted to D.

On the other hand, Walter Bright—you know, the guy who designed the D language—provides a D implementation of just this sort of function here. However, even this appears to be somewhat outdated, because one of the symbols, cfmakeraw, is undefined under the current version of the DMD2 compiler. However, it's really close to being a workable solution.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文