tags:

views:

664

answers:

5

I read this article and try to do the exercise in D Programming Language, but encounter a problem in the first exercise.

(1) Display series of numbers (1,2,3,4, 5....etc) in an infinite loop. The program should quit if someone hits a specific key (Say ESCAPE key).

Of course the infinite loop is not a big problem, but the rest is. How could I grab a key hit in D/Tango? In tango FAQ it says use C function kbhit() or get(), but as I know, these are not in C standard library, and does not exist in glibc which come with my Linux machine which I use to programming.

I know I can use some 3rd party library like ncurses, but it has same problem just like kbhit() or get(), it is not standard library in C or D and not pre-installed on Windows. What I hope is that I could done this exercise use just D/Tango and could run it on both Linux and Windows machine.

How could I do it?

A: 

D generally has all the C stdlib available (Tango or Phobos) so answers to this question for GNU C should work in D as well.

If tango doesn't have the needed function, generating the bindings is easy. (Take a look at CPP to cut through any macro junk.)

BCS
A: 

kbhit is indeed not part of any standard C interfaces, but can be found in conio.h.

However, you should be able to use getc/getchar from tango.stdc.stdio - I changed the FAQ you mention to reflect this.

larsivi
A: 

Thanks for both of your replies.

Unfortunately, my main development environment is Linux + GDC + Tango, so I don't have conio.h, since I don't use DMC as my C compiler.

And I also found both getc() and getchar() is also line buffered in my development environment, so it could not achieve what I wish I could do.

In the end, I've done this exercise by using GNU ncurses library. Since D could interface C library directly, so it does not take much effort. I just declare the function prototype that I used in my program, call these function and linking my program against ncurses library directly.

It works perfectly on my Linux machine, but I still not figure out how could I do this without any 3rd party library and could run on both Linux and Windows yet.

import tango.io.Stdout;
import tango.core.Thread;

// Prototype for used ncurses library function.
extern(C)
{
    void * initscr();
    int cbreak ();
    int getch();
    int endwin();
    int noecho();
}

// A keyboard handler to quit the program when user hit ESC key.
void keyboardHandler ()
{
    initscr();
    cbreak();
    noecho();
    while (getch() != 27) {
    }
    endwin();
}

// Main Program
void main ()
{
    Thread handler = new Thread (&keyboardHandler);
    handler.start();

    for (int i = 0; ; i++) {
        Stdout.format ("{}\r\n", i).flush;

        // If keyboardHandler is not ruuning, it means user hits
        // ESC key, so we break the infinite loop.
        if (handler.isRunning == false) {
            break;
        }
    }

    return 0;
}
Brian Hsu
+2  A: 

Here's how you do it in the D programming language:

    import std.c.stdio;
    import std.c.linux.termios;

    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
    c = fgetc(stdin);

    // Close
    tcsetattr(1, TCSADRAIN, &ostate);       // return to original mode
Walter Bright
cfmakeraw is an undefined symbol under phobos-2
alvatar
A: 

As Lars pointed out, you can use _kbhit and _getch defined in conio.h and implemented in (I believe) msvcrt for Windows. Here's an article with C++ code for using _kbhit and _getch.

DK