Get single keystroke?

2011-03-21 Thread Sean Eskapp
Is there a way to get a single keystroke in D2? Any method I've tried requires
pushing Enter before the stroke is registered.


Re: Get single keystroke?

2011-03-21 Thread Lars Holowko
On Mon, Mar 21, 2011 at 1:33 PM, Sean Eskapp eatingstap...@gmail.com wrote:
 Is there a way to get a single keystroke in D2? Any method I've tried requires
 pushing Enter before the stroke is registered.


Hi Sean,

what you want to do is OS dependent.

I needed something similar ('press key to continue')

e.g.: for Windows

import core.sys.windows.windows;

bool kbHit() {
// inspired by
http://faq.cprogramming.com/cgi-bin/smartfaq.cgi?answer=1045691686id=1043284392
HANDLE stdIn = GetStdHandle(STD_INPUT_HANDLE);
DWORD saveMode;

GetConsoleMode(stdIn, saveMode);
SetConsoleMode(stdIn, ENABLE_PROCESSED_INPUT);

bool ret = false;

if (WaitForSingleObject(stdIn, INFINITE) == WAIT_OBJECT_0) {
uint num;
char ch;

ReadConsoleA(stdIn, ch, 1, num, cast(void *) 0L);
ret = true;
}

SetConsoleMode(stdIn, saveMode);
return ret;
}

void wait_for_key() {
writeln(\nPress any key to continue);
while (!kbHit())
{}
}


for Linux/Unix something like
http://www.linuxquestions.org/questions/programming-9/kbhit-34027/
should work.

Hope that helps,

Lars


Re: Get single keystroke?

2011-03-21 Thread Andrej Mitrovic
Here's something simpler:

import std.stdio : writefln;

extern(C) int kbhit();
extern(C) int getch();

void main()
{
while(!kbhit())
{
// keep polling
// might use thread.sleep here.
}

writefln(Key hit was %s., getch());
}


Re: Get single keystroke?

2011-03-21 Thread Andrej Mitrovic
Replace that writefln with this:

writefln(Key hit was %s., cast(char)getch());

You should get the right key displayed then.


Re: Get single keystroke?

2011-03-21 Thread bearophile
Lars Holowko:

 what you want to do is OS dependent.

But the need to get a keystroke is simple and not so uncommon, so I think 
Phobos needs a function to do that that works on both Windows/Linux (and Mac 
too).

Bye,
bearophile


Re: Get single keystroke?

2011-03-21 Thread Sean Eskapp
== Quote from Andrej Mitrovic (andrej.mitrov...@gmail.com)'s article
 Here's something simpler:
 import std.stdio : writefln;
 extern(C) int kbhit();
 extern(C) int getch();
 void main()
 {
 while(!kbhit())
 {
 // keep polling
 // might use thread.sleep here.
 }
 writefln(Key hit was %s., getch());
 }

What extra linker dependencies does this add?


Re: Get single keystroke?

2011-03-21 Thread Ali Çehreli

On 03/21/2011 02:42 PM, bearophile wrote:
 Lars Holowko:

 what you want to do is OS dependent.

 But the need to get a keystroke is simple and not so uncommon, so I 
think Phobos needs a function to do that that works on both 
Windows/Linux (and Mac too).


If D sticks to the C (and C++) heritage, there is no guarantee that 
there is a keyboard around. The interface is stdin, stdout, and stderr; 
which are just character streams.


But I agree: some subset of ncurses would be nice when a keyboard is 
available.



 Bye,
 bearophile

Ali



Re: Get single keystroke?

2011-03-21 Thread Jonathan M Davis
 Lars Holowko:
  what you want to do is OS dependent.
 
 But the need to get a keystroke is simple and not so uncommon, so I think
 Phobos needs a function to do that that works on both Windows/Linux (and
 Mac too).

Assuming that it could be done cleanly, it would be a good function to add, 
but honestly, I dispute that it's a common need in this day and age. If all 
you need is something like press any key to continue, you can easily do that 
with the current functions by having press enter to continue, and if you 
need to do something other than that, odds are you need something more 
powerful like ncurses anyway. Not to mention, I don't think that interactive 
console apps are all that common these days. They definitely exist, but most 
console apps essentially run a single command for you and then quit. Most of 
the types of applications which would have have been interactive console apps 
in the past are now GUI apps.

So, while it certainly wouldn't hurt to add a function like this to Phobos 
(assuming that it could be done cleanly), I really don't think that it's a 
common need anymore.

- Jonathan M Davis


Re: Get single keystroke?

2011-03-21 Thread Andrej Mitrovic
On 3/21/11, Sean Eskapp eatingstap...@gmail.com wrote:
 == Quote from Andrej Mitrovic (andrej.mitrov...@gmail.com)'s article
 Here's something simpler:
 import std.stdio : writefln;
 extern(C) int kbhit();
 extern(C) int getch();
 void main()
 {
 while(!kbhit())
 {
 // keep polling
 // might use thread.sleep here.
 }
 writefln(Key hit was %s., getch());
 }

 What extra linker dependencies does this add?


snn.lib


Re: Get single keystroke?

2011-03-21 Thread Andrej Mitrovic
On 3/21/11, Sean Eskapp eatingstap...@gmail.com wrote:
 What about on Linux?


I'm not sure. Both DMD and GDC can run the example on Windows. Perhaps
they've got these functions implemented for Linux as well. But
according to this:
https://secure.wikimedia.org/wikipedia/en/wiki/Conio.h

it seems these functions are usually only available for compilers
targeting Windows. Have you tried compiling it on Linux, or does it
fail to link?


Re: Get single keystroke?

2011-03-21 Thread Andrej Mitrovic
It looks like its not available on Linux, I've just tried with DMD.


Re: Get single keystroke?

2011-03-21 Thread Sean Eskapp
== Quote from Andrej Mitrovic (andrej.mitrov...@gmail.com)'s article
 I believe I've found you a solution:
 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
 }
 I've tested this under Ubuntu and DMD 2.052 and it works.

Great, thanks!


Re: Get single keystroke?

2011-03-21 Thread Andrej Mitrovic
On 3/21/11, teo teo.ubu...@yahoo.com wrote:
 On Mon, 21 Mar 2011 23:22:17 +0100, Andrej Mitrovic wrote:

 Woops forgot to add import std.stdio, here's a fixed version:

 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
 }

 It looks like this can be dangerous, because the terminal can be left in
 an unusable state. Please read this:
 http://groups.google.com/group/comp.os.linux.development.apps/
 browse_thread/thread/0667d16089e2b6fc


H mentions using tcgetattr to save old state and restoring it with
tcsetattr. This is what this code does. Btw this code is not mine,
Walter posted it and I just added the cfmakeraw prototype. So kudos
goes to him.


Re: Get single keystroke?

2011-03-21 Thread Ali Çehreli

On 03/21/2011 03:37 PM, Andrej Mitrovic wrote:
 On 3/21/11, teoteo.ubu...@yahoo.com  wrote:
 On Mon, 21 Mar 2011 23:22:17 +0100, Andrej Mitrovic wrote:

 Woops forgot to add import std.stdio, here's a fixed version:

 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
 }

 It looks like this can be dangerous, because the terminal can be left in
 an unusable state. Please read this:
 http://groups.google.com/group/comp.os.linux.development.apps/
 browse_thread/thread/0667d16089e2b6fc


 H mentions using tcgetattr to save old state and restoring it with
 tcsetattr. This is what this code does. Btw this code is not mine,
 Walter posted it and I just added the cfmakeraw prototype. So kudos
 goes to him.

Thanks for posting this.

It can be improved by moving the last tcsetattr to an earlier 
scope(exit) statement:


termios  ostate;
tcgetattr(1, ostate);
scope (exit) tcsetattr(1, TCSADRAIN, ostate);

Ali