Search code examples
shellcmduser-inputd

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


I need to get user input (y/n) keypress in console.

How I can do it? I know that I can use readln, but is there any other way? I am trying to use getc()

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

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

but I am getting error:

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

next attempt:

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

        }
        return key;

    }

This code compile, but failure at execution time with strange error "Error executing command run"


Solution

  • One library that does the single press is my terminal.d

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

    It looks more complex than it is. Here's an example to get a single key:

    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!"); 
    }   
    

    To build, put terminal.d in your folder and then compile them together: dmd yourfile.d terminal.d.

    First, you construct a terminal. The two types are linear or cellular. Linear outputs one line at a time, cellular goes "full screen" in the console.

    Then, you make an input struct based on that terminal. The ConsoleInputFlags says what you want: do you want echo? Mouse input? etc. raw is the simplest one: it will send you plain keyboard input as they happen with relatively little else.

    Then you can write to the terminal and get characters from the input. The input.getch() line fetches a single character, returning immediately when something is available without buffering. Other functions available on input include kbhit, which returns true if a key was hit so input is available, false if it isn't - useful for a real time game, being checked on a timer, or nextEvent, which gives full input support, including mouse events. The Demo in the terminal.d source code shows something with full support:

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

    Another useful convenience function on terminal itself btw is getline, which grabs a full line at a time, but also lets the user edit it and offers history and autocomplete. terminal also offers a function called color to do colored output, and moveTo, useful in cellular mode, to move the cursor around the screen. Browse the code to learn more, if you're interested.