1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
# You may distribute under the terms of either the GNU General Public License
# or the Artistic License (the same terms as Perl itself)
#
# (C) Paul Evans, 2020 -- leonerd@leonerd.org.uk
package Tickit::App::Plugin::EscapePrefix;
use strict;
use warnings;
our $VERSION = '0.02';
use Tickit 0.64 qw( MOD_ALT );
use Tickit::Term qw( BIND_FIRST );
=head1 NAME
C<Tickit::App::Plugin::EscapePrefix> - C<Tickit> application plugin for Escape-prefixed shortcut keys
=head1 SYNOPSIS
use Tickit;
use Tickit::App::Plugin::EscapePrefix;
my $tickit = Tickit->new;
Tickit::App::Plugin::EscapePrefix->apply( $tickit );
...
$tickit->run;
=head1 DESCRIPTION
This package applies code to a L<Tickit> instance to let it handle
C<< <Escape > >>-prefixed shortcut keys, by converting them into the
equivalent C<< <M-...> >> modified keys instead.
Once applied using the L</apply> method, the plugin will consume any plain
C<< <Escape> >> keys typed at the terminal. If another key arrives soon
afterwards, this key will be consumed and instead a new keypress event emitted
that adds the "meta" modifier to it. For example, typing C<< <Escape> <a> >>
will instead emit the modified key C<< <M-a> >> to the application. If no
subsequent key arrives after a timeout of 3 seconds then the modification will
not apply.
While the plugin is still pending anothey keypress to modify, a small
indicator window will appear in the bottom left of the display, showing
C<ESC-> in a reverse-video style, to remind the user the keypress is pending.
=cut
=head1 METHODS
=cut
=head2 apply
Tickit::App::Plugin::EscapePrefix->apply( $tickit )
Applies the plugin code to the given toplevel L<Tickit> instance.
=cut
sub apply
{
my $pkg = shift;
my ( $t ) = @_;
my $esc_held;
my $esc_indicator_window = $t->rootwin->make_float( 0, 0, 1, 4 );
$esc_indicator_window->hide;
$esc_indicator_window->pen->chattr( rv => 1 );
$esc_indicator_window->bind_event( expose => sub {
my ( $win, undef, $info ) = @_;
$info->rb->text_at( 0, 0, "ESC-" );
} );
my $timer_id;
$t->term->bind_event( key => BIND_FIRST, sub {
my ( $term, $ev, $info ) = @_;
if( $esc_held ) {
$esc_held = 0;
$esc_indicator_window->hide;
$t->cancel_timer( $timer_id ) if defined $timer_id;
undef $timer_id;
$term->emit_key(
type => "key",
str => "M-" . $info->str,
mod => $info->mod | MOD_ALT,
);
return 1;
}
if( $info->type eq "key" and $info->str eq "Escape" ) {
$esc_held = 1;
$esc_indicator_window->reposition( $t->rootwin->lines - 1, 0 );
$esc_indicator_window->show;
$t->cancel_timer( $timer_id ) if defined $timer_id;
$timer_id = $t->timer( after => 3, sub {
$esc_held = 0;
$esc_indicator_window->hide;
undef $timer_id;
} );
return 1;
}
return 0;
} );
}
=head1 TODO
=over 4
Much configuration - timeout; style, text and position of indicator window
=back
=cut
=head1 AUTHOR
Paul Evans <leonerd@leonerd.org.uk>
=cut
0x55AA;
|