My
app needs to switch between the existing
Term::ReadLine::Gnu line-oriented command mode and a new hotkey mode (based on
Term::TermKey) and then back again.
My problem is that the terminal doesn't echo keystrokes
after returning to the ReadLine mode.
The test program starts in ReadLine mode, with prompt and echo of the input line. Entering 'hot' (as in hotkey) sets the TermKey mode in which Keytrokes are dumped to the screen as text. Entering <Escape> in the TermKey mode, restarts the ReadLine mode.
Edit: I was missing a call to initialize_prompt(),thank for being there to listen, PerlMonks!
Edit2: No,it still doesn't echo properly. I found the necessary call to restore the echo (seek to ECHO in the code below). However I now have the problem that two Enter keystrokes are needed to conclude a line entry.
Edit3: For the last problem, I just needed to get rid of my reference so the object would be garbage-collected.
use Term::ReadLine;
use v5.10;
use strict;
use warnings;
use Event;
use AnyEvent;
use AnyEvent::TermKey qw( FORMAT_VIM KEYMOD_CTRL );
our $text = {};
our $engine = {};
our $config = {};
$config->{press_space_to_start}++;
initialize_terminal();
initialize_prompt();
Event::loop();
sub initialize_terminal {
$text->{term} = new Term::ReadLine("Ecasound/Nama");
$text->{term_attribs} = $text->{term}->Attribs;
# $text->{term_attribs}->{attempted_completion_function} = \&comple
+te;
$text->{term_attribs}->{already_prompted} = 1;
# to detect spacebar and toggle transport
# create a STDIN watcher that intervenes when space
# received in column one
$engine->{events}->{stdin} = AE::io(*STDIN, 0, sub {
&{$text->{term_attribs}->{'callback_read_char'}}();
if ( $config->{press_space_to_start} and
$text->{term_attribs}->{line_buffer} eq " " ){
toggle_transport();
$text->{term_attribs}->{line_buffer} = q();
$text->{term_attribs}->{point} = 0;
$text->{term_attribs}->{end} = 0;
$text->{term}->stuff_char(10);
&{$text->{term_attribs}->{'callback_read_char'}}();
}
});
$text->{term}->callback_handler_install(prompt(), \&process_line);
$SIG{INT} = sub { die "caught SIGINT" }; # blocks until newline on
+ STDIN
# $engine->{events}->{sigint} = AE::signal('INT', sub { die "caugh
+t SIGINT");
$text->{term_attribs}->{'callback_read_char'}->();
}
sub prompt { "Nama > " }
sub process_line {
say("\nReadLine got: @_");
setup_hotkeys() if shift =~ /hot/ ;
}
sub setup_hotkeys {
destroy_terminal();
setup_termkey()
}
sub setup_termkey {
my $cv = AnyEvent->condvar;
$engine->{events}->{termkey} = AnyEvent::TermKey->new(
term => \*STDIN,
on_key => sub {
my ( $key ) = @_;
my $key_string = $key->termkey->format_key( $key, FORMAT_V
+IM );
print "TermKey got key: $key_string\n";
$cv->send if $key->type_is_unicode and
$key->utf8 eq "C" and
$key->modifiers & KEYMOD_CTRL;
$cv->send, teardown_hotkeys() if $key_string =~ /Escape/;
},
);
$cv->recv;
}
sub initialize_prompt {
$text->{term}->stuff_char(10); # necessary to respond to Ctrl-C at
+ first prompt
&{$text->{term_attribs}->{'callback_read_char'}}();
print prompt();
$text->{term_attribs}->{already_prompted} = 0;
}
sub teardown_hotkeys {
$text->{termkey}->termkey->stop(); # <---- RESTORES ECHO
delete $text->{termkey}; # <-------------- OBJECT GARBAGE COLLECTE
+D
initialize_terminal();
initialize_prompt();
}
sub destroy_terminal {
$text->{term}->rl_deprep_terminal();
delete $text->{term};
delete $engine->{events}->{stdin};
}
sub toggle_transport { say "toggle transport" }