catch arrow keys

M

Michael Goerz

Hi, how can I catch if someone presses the Arrow-Keys (Up, Down, Left,
Right) on the keyboard? I tried

use Term::ReadKey;
while (not defined ($pressedkey = ReadKey(-1))) {
# No key yet
}
printf(" Decimal: %d\tHex: %x\n", ord($pressedkey),
ord($pressedkey));

but that only return the escape-symbol (27) for each of the arrow-keys.
I need to react on which key was pressed.

Thanks,
Michael Goerz
 
X

xhoster

Michael Goerz said:
Hi, how can I catch if someone presses the Arrow-Keys (Up, Down, Left,
Right) on the keyboard? I tried

use Term::ReadKey;
while (not defined ($pressedkey = ReadKey(-1))) {
# No key yet
}

Isn't that pretty silly? You go out of your way to do a nonblocking
read, only to put it into a busy-wait loop which emulates blocking in
a very inefficient way.

$pressedkey = ReadKey();

printf(" Decimal: %d\tHex: %x\n", ord($pressedkey),
ord($pressedkey));

but that only return the escape-symbol (27) for each of the arrow-keys.
I need to react on which key was pressed.

Control keys return multiple bytes per key-press. Once you see the 27, you
need to call ReadKey some more to get the rest of them.

Xho
 
J

jl_post

Michael said:
Hi, how can I catch if someone presses the Arrow-Keys (Up, Down, Left,
Right) on the keyboard? I tried

use Term::ReadKey;
while (not defined ($pressedkey = ReadKey(-1))) {
# No key yet
}
printf(" Decimal: %d\tHex: %x\n", ord($pressedkey),
ord($pressedkey));

but that only return the escape-symbol (27) for each of the arrow-keys.
I need to react on which key was pressed.


Dear Michael,

You might want to try reading the next two keys to see which
direction was pressed. If you get "[A", then that means UP was
pressed. "[B" means DOWN was pressed, "[C" means RIGHT was pressed,
and "[D" means LEFT was pressed.

Therefore, try this modification to your script:


use Term::ReadKey;
ReadMode 4; # Turn off controls keys
while (not defined ($key = ReadKey(-1))) {
# No key yet
}
if (ord($key) != 27) {
print "Got key $key\n";
} elsif ($key = ReadKey(-1) and $key ne '[') {
print "Not sure what I have...\n"
} else {
$key = ReadKey(-1);
if ($key eq 'A') { print "UP pressed.\n" }
elsif ($key eq 'B') { print "DOWN pressed.\n" }
elsif ($key eq 'C') { print "RIGHT pressed.\n" }
elsif ($key eq 'D') { print "LEFT pressed.\n" }
else { print "Not sure what I have...\n" }
}
ReadMode 0; # Reset tty mode before exiting


Just a warning: I don't know how portable this solution is, so
don't expect it to work on all platforms (like Win32).

I hope this helps, Michael.

-- Jean-Luc
 
J

jl_post

(e-mail address removed) replied:
Isn't that pretty silly? You go out of your way to do a nonblocking
read, only to put it into a busy-wait loop which emulates blocking in
a very inefficient way.


Actually, he got that code straight from "perldoc Term::ReadKey".
(But I don't disagree with you that that code could be written better.)

-- Jean-Luc
 
M

Michael Goerz

Isn't that pretty silly? You go out of your way to do a nonblocking
read, only to put it into a busy-wait loop which emulates blocking in
a very inefficient way.

$pressedkey = ReadKey();
Then I have to press Enter after each "keystroke". The code I used
before was actually taken from
http://search.cpan.org/~jstowe/TermReadKey-2.30/ReadKey.pm
Control keys return multiple bytes per key-press. Once you see the 27, you
need to call ReadKey some more to get the rest of them.
Yes, that appears to work. Thanks a lot!

Michael
 
M

Michael Goerz

use Term::ReadKey;
ReadMode 4; # Turn off controls keys
while (not defined ($key = ReadKey(-1))) {
# No key yet
}
if (ord($key) != 27) {
print "Got key $key\n";
} elsif ($key = ReadKey(-1) and $key ne '[') {
print "Not sure what I have...\n"
} else {
$key = ReadKey(-1);
if ($key eq 'A') { print "UP pressed.\n" }
elsif ($key eq 'B') { print "DOWN pressed.\n" }
elsif ($key eq 'C') { print "RIGHT pressed.\n" }
elsif ($key eq 'D') { print "LEFT pressed.\n" }
else { print "Not sure what I have...\n" }
}
ReadMode 0; # Reset tty mode before exiting


Just a warning: I don't know how portable this solution is, so
don't expect it to work on all platforms (like Win32).

I hope this helps, Michael.

-- Jean-Luc
That's perfect! Thank you!

Michael
 
M

Michael Goerz

(e-mail address removed) replied:


Actually, he got that code straight from "perldoc Term::ReadKey".
(But I don't disagree with you that that code could be written better.)

-- Jean-Luc

What would be more efficient code, if I don't want to have to press
Enter after each keystroke? In fact, the tight loop bothers me somewhat.

Michael
 
J

jl_post

Michael said:
What would be more efficient code, if I don't want to have to press
Enter after each keystroke? In fact, the tight loop bothers me somewhat.


Basically, the purpose of the while-loop is to wait until a key has
been read in. If no key was read in, the while-block gets executed.
In the above example, the block does absolutely nothing. (Sometimes
you may want something to happen if no was pressed, which is why I
think the example was written like this.)

However, if all you want to do is wait until the first key is
pressed, you basically want to perform a "blocking" read (as opposed to
a "non-blocking" read). The "ReadKey(-1)" performs a "non-blocking"
read; to do a "blocking" read, you want to pass in a zero for
ReadKey()'s argument.

Therefore, I would recommend changing the above while-loop to the
following one line of code:

$pressedkey = ReadKey(0); # Note: no loop!

This will prevent the program from advancing any further until a key is
pressed.

By the way, did you know that you can get comprehensive
documentation for a module by using the perldocs? That is, you can
read the documentation for Term::ReadKey by typing the following at any
Unix prompt:

perldoc Term::ReadKey

The reason I ask this is because, in a previous post, you mentioned
that you found the Term::ReadKey documentation online. (I once knew a
programmer who'd been programming Perl for several years who wasn't
aware that he could look up the documentation for any module just by
typing "perldoc ModuleName" at a Unix prompt. Instead of using
documentation he already had, he had to scour the web to find it!)

(And sometimes the programmers who already know about the perldocs
don't realize that there are a lot of other programmers who don't know
about them, so the ones who don't know about the usefulness of the
perldocs continue to be left in the dark about them.)

Anyway, I hope this helps you, Michael.

-- Jean-Luc
 
M

Michael Goerz

Therefore, I would recommend changing the above while-loop to the
following one line of code:

$pressedkey = ReadKey(0); # Note: no loop!

This will prevent the program from advancing any further until a key is
pressed.
Wow, yes... that's exactly what I was looking for. Should have read the
docs more carefully.
By the way, did you know that you can get comprehensive
documentation for a module by using the perldocs? That is, you can
read the documentation for Term::ReadKey by typing the following at any
Unix prompt:

perldoc Term::ReadKey
Yes, I know, but usually I prefer the online documentation, because of
its very readable formatting (syntax highlighting) and because it's
easier to browse around
Anyway, I hope this helps you, Michael.
That did help a lot! Thanks again.

Michael
 
X

xhoster

Then I have to press Enter after each "keystroke".

In your original code, exactly as you posted it, you need to press Enter,
too. I suspect this is because the code you posted is not the real code
you are running, but rather your real code has "ReadMode 4;" in it.

If you don't include the "ReadMode 4;", then you have to press Enter
either way. If you do include the "ReadMode 4;", then you don't need
to press Enter, either way. It isn't about the ReadKey, it is about the
ReadMode


Yep, but that example is expecting you to replace the "# No key yet" line
with something meaningful. If you leave it as is, then you are better
off using the blocking ReadKey.

Cheers,

Xho
 
M

Michele Dondi

programmer who'd been programming Perl for several years who wasn't
aware that he could look up the documentation for any module just by
typing "perldoc ModuleName" at a Unix prompt. Instead of using

s/Unix//; # Works on all DOS/Win* cli's I know of too.


Michele
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,540
Members
45,025
Latest member
KetoRushACVFitness

Latest Threads

Top