Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Reading all nonblocking keystrokes in Win2000

by Washizu (Scribe)
on Nov 15, 2001 at 23:42 UTC ( [id://125648]=perlquestion: print w/replies, xml ) Need Help??

Washizu has asked for the wisdom of the Perl Monks concerning the following question:

My problem:
I would like to have a module that can check to see if the user is pressing keys at any time, and what keys are being pressed. I don't want to have to wait for a carriage return.

My failed solution:

#!/usr/local/bin/perl5 # Use Perl 5 use Term::ReadKey; my $c = ""; ReadMode(5); while ($c ne "q") # Press q to exit { $c = ReadKey(-1); if ($c ne "") { print $c; } } ReadMode(0);

Why it Fails:
Although it returns characters, numbers, and symbols just fine, it returns something strange on other keyboard input, such as the delete key, arrow keys, insert, home, etc. In the terminal it looks like a space, but it is something else. I know this because when I test for " ", it doesn't equate.

Question:
How can I get the keystrokes I'm looking for?

-----------------------------------
Washizu
The best offense is a good offense.

Replies are listed 'Best First'.
Re: Reading all nonblocking keystrokes in Win2000
by clintp (Curate) on Nov 16, 2001 at 05:22 UTC
    Somewhere in the dusty, musty, trivial bits of DOS knowledge that's in the back of my brain I seem to remember that the getc() call under DOS has to be called _twice_ for special characters. The first byte is a flag byte and the second one contains the actual keyboard scan code.

    The Term::ReadKey module appears to use getc() or Win32Peek() to get its characters. I'll bet if you get a null (ord==0) and then immediately read for another key you'll get the scan code for the special key. I don't have a MS system handy or I'd test this theory out...

    Update:Google does it again. An explanation of getc under ths baroque environment.

      Term::ReadKey uses Win32Peek(), but could anyone explain exactly how to use this subroutine anywhere else? I don't know how it is being called since it isn't defined in the Term::ReadKey package or any of the modules it uses (as far as I could tell).

      -----------------------------------
      Washizu
      The best offense is a good offense.

        You shouldn't need to bother with Win32Peek() at all. It's probably just a fancy-ass timed wrapper for getc(). Since Google doesn't seem to think it's part of the Win32 API it's probably something that the Term::ReadKey author whipped up to do timed reads.

        What happens when you get a zero-byte and then do a second ReadKey() right away? Kinda like (pseudocode):

        c=ReadKey if (c==0) { # Oh, this is a special key c=ReadKey }
Re: Reading all nonblocking keystrokes in Win2000
by c-era (Curate) on Nov 16, 2001 at 00:35 UTC
    Look up ASCII, and change print $c; to  print ord($c);. The delete key doesn't have a character map (which is why you get a space) your program will need to compair with the delete character, not the space character. Also look at what pressing return does ; )

      Good thinking, but unfortunatly I tried that already.

      When I use 'print ord $c' it prints 0 for the arrow keys and insert, delete, home, etc. It prints the actual codes for ENTER and SPACE, but I'd like to have everything.

      -----------------------------------
      Washizu
      The best offense is a good offense.

Re: Reading all nonblocking keystrokes in Win2000
by clintp (Curate) on Nov 16, 2001 at 21:50 UTC
    Having finally found a Win32 system, I tried this and you're right. You can tell IF one of these keys is pressed but not which one. If the return is truly undef, then nothing was pressed, if it's a null byte (ord($c)==0 and length $c) then one of these other keys was pressed.

    The Win32PeekChar routine is an XS routine, it interfaces C and Perl. Looking at the module's source it doesn't look like its at all equipped to give a multibyte return value -- so you're screwed. The Win32 API calls used (PeekConsoleInput, ReadConsoleInput, WaitForSingleObject) might provide the raw information to Win32PeekChar but I'm not going to research the Win32 API for someone else's question. I'm not a masochist. :)

    It is possible to do this because the Tk module can catch these kinds of events. But Tk is a hefty beast if all you want is to catch keystrokes. Perhaps brush up on your C programming and fix ReadKey.xs to do the Right Thing.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://125648]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (1)
As of 2024-04-25 00:41 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found