1

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"

Suliman
  • 1,469
  • 3
  • 13
  • 19

3 Answers3

2

The error is because phobos is conflicting with the runtime.

std.stdio publicly imports core.stdc.stdio, and they both define stdin, but as different types. getc() really just calls fgetc( stdin ), so when the runtime tries calling getc(), it passes in the stdin from std.stdio instead of the correct one from core.stdc.stdio, resulting in the error.

The best way to get around the conflict is just to alias core.stdc.stdio as something else and then use the fully qualified name.

import std.stdio;

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

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

But beware that getc() uses a buffer internally, and won't return until the user presses the enter key, at which point it reads the first char from the buffer and returns that, and will continue to read the next char from the buffer for subsequent calls until it reaches the end. So entering nnn<enter> in the terminal window results in try again being printed 3 times. If you want a method that returns a single char without the need for the enter key, you'll need to look for a library solution, no standard functions for that exist in either C or D.

If you're not concerned with a cross-platform solution, there's a Windows-specific header that defines a getch() function which doesn't use a buffer and returns on every keystroke, rather than on enter. Just add this to your code and replace the call to getc() with a call to getch().

extern( C ) int getch();
2

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.

Adam D. Ruppe
  • 25,382
  • 4
  • 41
  • 60
1

How about:

import std.stdio;

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

The important bit is the " %c\n". %c tells readf to match a char rather than a string.

Colin Grogan
  • 2,462
  • 3
  • 12
  • 12