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

i am using a hexified ascii value to recognize keystrokes (with ReadKey), so:

if ($key =~ /\x7e/) { BLOCK }


Unfortunately of course some "multicharacter" keys respond to the same number (eg, PgUp and PgDn are 7e); I can get all three values for these keys but how can i use that with \x to distinguish PgUp from PgDn?

Replies are listed 'Best First'.
Re: using \x in regex
by almut (Canon) on Feb 29, 2008 at 19:42 UTC

    I think $key = ReadKey() is always returning individual bytes in $key. If so, you need to build up some context to match against. I.e., if the longest multicharacter sequence is 4 chars, you'd keep the last 4 bytes returned from ReadKey(). You can then compare this 4-byte string against the target sequence. If the sequence you're interested in is shorter, just compare against the last n bytes in the string.

    For example, on my keyboard, where PgUp produces the sequence 1b 5b 35 7e, I could use the following snippet to react to this keypress:

    use Term::ReadKey; my $buf = ''; ReadMode 4; # raw mode while (my $key = ReadKey()) { last if $key eq "q"; # quit loop $buf .= $key; $buf = substr($buf, -4); # keep last 4 bytes # debug print unpack("H*", $buf), "\n"; if ($buf eq "\x1b\x5b\x35\x7e") { # \e[5~ print "PgUp\n"; } } ReadMode 0; # reset tty
      that is definitely the key, thanx ;}

      Since each of the four bytes from ReadKey for a "multicharacter" key is the same as one byte from a fresh keypress, is there no way to distinguish a four-byte key from four one byte keys? Otherwise, a waiting ReadKey loop will have to answer to EITHER the 1-byte flavour OR the 4-byte, but could not answer to either/or...

      ...unless the first byte of the 4-bytes is unique (indicating a multi-character key). Which it appears that it is (1b)...

      ...to be continued
        ... Which it appears that it is (1b)

        Yes, 1b is the escape key, which introduces an escape sequence.

        Still, it's somewhat tricky to handle, because sequences may have different lengths (e.g. my function keys (F1-F12) produce 5-bytes). What you could do is put all possible escape sequences into some lookup hash. Then, when you encounter the escape char, reset $buf and switch into an "escape mode", which means that for every char received from ReadKey(), you'd try to lookup the current buffer content in the hash. Once you succeed, you've reached the end of the escape sequence, and you can switch back to "normal mode". To be able to handle possibly unforeseen sequences, you'll probably want to switch back from escape mode anyway as soon as you've reached a certain buffer length without a successful lookup. Or some such...  (I could post some code, in case I should have failed to make it clear...:)

Re: using \x in regex
by ysth (Canon) on Feb 29, 2008 at 19:28 UTC
    The regex is looking for a ~ anywhere in $key, while it sounds like what you want is to compare against the entire value in $key. For example:
    if ($key eq "~") { # it's a tilde } elsif ($key eq "\e[5~") { # pgup } elsif ($key eq "\e[6~") { # pgdown }
Re: using \x in regex
by Narveson (Chaplain) on Feb 29, 2008 at 18:55 UTC

    What is in $key when the user presses PgUp?

    What is in $key when the user presses PgDn?

      $key IS PgUp or PgDn (see Term::ReadKey), which means that value is not usable, BUT ord($key) will give you the ascii value (an integer), hex this decimal and that value can be used in regex with \x -- except in this case PgUp and PgDn have the same value to \x (7e)