Re: Capture a non-printable char and test what it is
by haukex (Archbishop) on May 21, 2022 at 15:27 UTC
|
Can anyone tell me how I would capture a non-printable character from STDIN and test what the character is?
Specifically, I want to test if the escape key has been pressed.
See Term::ReadKey:
use warnings;
use strict;
use Term::ReadKey qw/ReadMode ReadKey/;
use Data::Dumper;
$Data::Dumper::Useqq=1;
print "Press a key\n";
ReadMode 'cbreak';
my $key = ReadKey(0);
ReadMode 'restore';
print Dumper($key);
if ( $key eq "\e" ) {
print "Escape pressed\n";
}
Trying to build a console based text editor.
Beware of reinventing the wheel, but anyway, see Curses and perhaps Curses::UI (though the latter is pretty old by now).
| [reply] [Watch: Dir/Any] [d/l] |
|
How does \e represent the escape key? Where do you find that?
If I look at the ascii table I see that the escape key can be represented as: 27 (decimal), 1B (hexadecimal), 033 (octal). But I am not sure how to test whether the value returned from ReadKey is one of those.
| [reply] [Watch: Dir/Any] |
|
Where do you find that?
kcott is right that I simply looked at the code's output, but it's also documented in Quote and Quote like Operators.
If I look at the ascii table I see that the escape key can be represented as: 27 (decimal), 1B (hexadecimal), 033 (octal).
Those work too: the string "\e" is the same as "\x1B" and "\033" - you can try this out yourself with eq.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
|
|
|
Press a key
$VAR1 = "\e";
Escape pressed
Had you pressed the enter key:
Press a key
$VAR1 = "\n";
I suggest you also read ++haj's post for additional information
and alternative methods to use.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
|
If I look at the ascii table
then you only see a part of the non-printable characters available on modern computer systems. Unicode has more control characters, emoji skin tone modifiers, right-to-left mark and a host of other stuff that is unprintable on it's own.
As an additional bonus, the same character on screen can sometimes be encoded in Unicode in multiple ways, see Unicode equivalence.
Unfortunately, input processing has gotten a tad more complex since the world gave up on ye olde ASCII table. On the bright side, these days more than the 20% of world population of the old ASCII days can now type their name into a computer with a reasonable expectation that it will be processed correctly.
perl -e 'use Crypt::Digest::SHA256 qw[sha256_hex]; print substr(sha256_hex("the Answer To Life, The Universe And Everything"), 6, 2), "\n";'
| [reply] [Watch: Dir/Any] [d/l] |
|
|
Re: Capture a non-printable char and test what it is
by haj (Vicar) on May 21, 2022 at 15:35 UTC
|
Capturing non-printable characters isn't that different from capturing any other character. One gotcha is that on a terminal your program usually does not receive any characters until the user hits the <ENTER> key.
If you want to capture individual characters, you need to check which characters have a meaning to your console - and thus never reach your program. The following small example uses Term::ReadKey in "raw" mode to capture one byte and then prints its hex value plus its interpretation. This works for the escape key and also for combinations with the <CTRL> key.
A warning, though: This example reads one byte, not one character. If your terminal uses UTF-8 encoding and you enter a key outside the ASCII range, then you'll receive only part of one character (Dealing with UTF-8 is left as an exercise to the reader). Also, cursor keys, function keys and the like are usually sequences which start with an escape character, my short example drops the rest of the sequence.
use Term::ReadKey;
use charnames ':full';
ReadMode 4;
print "Enter a key: ";
my $key = ReadKey(0);
printf "%v02x",$key;
print " = ",charnames::viacode(ord $key),"\n";
END {
ReadMode 0;
}
| [reply] [Watch: Dir/Any] [d/l] |
|
Thank you. knowing about the ord function is useful.
| [reply] [Watch: Dir/Any] |