Perl Term::ReadKey со стрелками

Я использую Term::ReadKey в ReadMode('cbreak'), чтобы прочитать один символ и выполнить действие, основанное на вводе. Это прекрасно работает для всех других клавиш, кроме клавиш со стрелками. Когда нажимаются клавиши со стрелками, действие выполняется 3 раза, и я понимаю, что это потому, что клавиши со стрелками переводятся в "^[[A" и т. Д....

Как мне перевести клавиши со стрелками в какое-то произвольное единственное значение, которое может интерпретировать ReadKey?

Я попробовал следующий код, но он не работает:

use Term::ReadKey;

ReadMode('cbreak');

my $keystroke = '';

while ($keystroke ne 'h') {

    print "Enter key: "; 

    #Read user keystroke 
    $keystroke = ReadKey(0);

    chomp($keystroke);


    if(ord($keystroke) == 27) {
         $keystroke = ('0');
    }
}

Вот мой код, основанный на предложении:

use Term::RawInput;
use strict;
use warnings;

my $keystroke = '';
my $special = ''; 

while(lc($keystroke) ne 'i' && lc($keystroke) ne 't'){

    my $promptp = "Enter key: ";

    ($keystroke,$special) = rawInput($promptp, 1);

    if ($keystroke ne '') {
        print "You hit the normal '$keystroke' key\n";
    } else {
        print "You hit the special '$special' key\n";
    }

    chomp($keystroke);

    $keystroke = lc($keystroke);
}

if($keystroke eq 'i') {
    #Do something
}

if($keystroke eq 't') {
    #Do something
}

Теперь, что бы я ни нажимал, я не могу выйти из этого цикла

Вот вывод:

Enter key: 
Enter key:
Enter key: You hit the normal 't' key

#Proceeds to function

4 ответа

Решение

Вот мое рабочее решение...

use Term::ReadKey;

ReadMode('cbreak');

{
    #Temporarily turn off warnings so no messages appear for uninitialized $keystroke
    #that for some reason appears for the if statement
    no warnings;

    my $keystroke = '';

    while ($keystroke ne 'h') {

        print "\nEnter key: ";

        #Read user keystroke 
        $keystroke = ReadKey(0);

        #The first character for the arrow keys (ex. '^[[A') evaluates to 27 so I check for 
        #that
        if(ord($keystroke) == 27) {
            #Flush the rest of the characters from input buffer
            #This produces an 'Use of uninitialized value...' error
            #for the other two characters, hence 'no warnings' at the beginning.
            #This will ignore the other 2 characters and only cause a single iteration
            while( defined ReadKey(-1) ) {}
        }
     }
}

Term::RawInput не охватывает все, но это довольно хорошее начало для этой задачи:

use Term::RawInput;
my ($keystroke,$special) = rawInput("", 1);
if ($keystroke ne '') {
    print "You hit the normal '$keystroke' key\n";
} else {
    print "You hit the special '$special' key\n";
}

Если вы хотите прочитать высокоуровневые семантические идеи "нажатий клавиш", а не низкоуровневые идеи "байтов из терминала", вам понадобится что-то, что может проанализировать и собрать эти многобайтовые последовательности для вас.

Для такого рода задач я написал Term:: TermKey:

use Term::TermKey;

my $tk = Term::TermKey->new( \*STDIN );

print "Press any key\n";

$tk->waitkey( my $key );

print "You pressed: " . $tk->format_key( $key, 0 );

На основе mob ответ, используя Term:: RawInput, я сделал этот скрипт для эмуляции более сложного взаимодействия ввода. Самым важным отличием является использование rawInput: mob предложил: rawInput("",1)Я узнаю, что на самом деле с помощью rawInput("> ") (без второго параметра) упрощает работу, а подсказка ">" более полезна.

Этот код принимает команды и специальные ключи. Кроме того, он прекрасно отображается для использования в качестве интерактивной оболочки для вашей системы.

DELETE ключ удалит все символы и BACKSPACE один персонаж. ESC выйдет из оболочки. Вы можете добавить больше клавиш для включения стрелок или чего-либо еще для выполнения специальных функций. Этот код распечатывает любую специальную клавишу, которая не включена в if..elsif (чтобы вы знали, что вам нужно добавить).

use warnings;
use strict;
use Term::RawInput;

sub out {
    my $out = shift;
    print "[ $out ]\n";
}

do {
    my ($keystroke,$special) = rawInput("> ");
    if($special eq 'ESC') {
        print "\n";
        exit;
    } elsif($special eq 'ENTER') {
        out($keystroke);
    } elsif($special ne 'DELETE') {
        if ($keystroke ne '') {
            out($keystroke);
        } else {
            print "'$special' key is not associated\n";
        }
    }
} while(1);

Вы можете реализовать свои команды внутри "снаружи";

Другие вопросы по тегам