From 756a768dc727b7ce6e187f00723fed4ca0791421 Mon Sep 17 00:00:00 2001 From: Tom Feist Date: Mon, 20 Sep 2010 22:51:23 +0100 Subject: new key detection system that incorporates a buffer to identify sequences that start with an Esc, and distinguish them from a press of the Esc key. --- vim-mode/vim_mode.pl | 113 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 85 insertions(+), 28 deletions(-) (limited to 'vim-mode/vim_mode.pl') diff --git a/vim-mode/vim_mode.pl b/vim-mode/vim_mode.pl index 47ae262..892abf7 100644 --- a/vim-mode/vim_mode.pl +++ b/vim-mode/vim_mode.pl @@ -23,8 +23,15 @@ sub DEBUG () { 0 } # circular buffer to keep track of the last N keystrokes. my @key_buf; +my $key_buf_timer; +my $key_buf_enabled = 0; +my $should_ignore = 0; + +sub M_CMD() { 1 } # command mode +sub M_INS() { 0 } # insert mode + +my $mode = M_INS; -my $mode = 0; # 0 is insert, 1 is command. no Ex for now. my $commands = { @@ -56,7 +63,7 @@ my $commands sub cmd_jump_word { my ($params) = @_; - + } sub cmd_insert { @@ -65,9 +72,10 @@ sub cmd_insert { _input_pos($pos); - $mode = 0; + $mode = M_INS; _update_mode(); + _stop(); } @@ -91,7 +99,7 @@ sub cmd_move { sub vim_mode_cb { my ($sb_item, $get_size_only) = @_; my $mode_str = ''; - if ($mode == 0) { + if ($mode == M_INS) { $mode_str = 'Insert'; } else { $mode_str = '%_Command%_'; @@ -102,25 +110,84 @@ sub vim_mode_cb { sub got_key { my ($key) = @_; - _key_buf_add($key); - if ($mode == 0) { - # we're in insert mode. - if ($key == 27) { # esc - - $mode = 1; - _update_mode(); - Irssi::signal_stop(); - return; - } - return; - } else { +# goals: + +# * all keys should work normally in insert mode (including Arrow keys) +# * we should be able to reliably detect a single press of the esc key and +# switch to command mode +# * + +# whenever we see an escape, we need to be sure it's not part of a +# longer escape sequence (eg ^[[A for arrowkeys or whatever) + +# when we see an escape (27), we start a timer for a short period, and +# capture all additional keystrokes into a buffer. + +# once the timer expires, we examine the buffer to see if it's a plain escape +# (hopefully time is short enough that we don't get user-repeated keypresses) +# or an escape sequence, which we can then parse and do whatever with. + +# issues: + +# do the buffered commands get evaluated? (ie: do we sig_stop them?) +# + return if ($should_ignore); + + if ($key == 27) { + print "Esc seen, starting buffer"; + $key_buf_enabled = 1; + $key_buf_timer + = Irssi::timeout_add_once(10, \&handle_key_buffer, undef); + } + + if ($key_buf_enabled) { + push @key_buf, $key; + _stop(); + } + + if ($mode == M_CMD) { # command mode handle_command($key); } - print "Keys: ", join ', ', @key_buf; } +sub handle_key_buffer { + + Irssi::timeout_remove($key_buf_timer); + $key_buf_timer = undef; + # see what we've collected. + print "Key buffer contains: ", join(", ", @key_buf); + + if (@key_buf == 1 && $key_buf[0] == 27) { + + print "Command Mode"; + $mode = M_CMD; + _update_mode(); + + } else { + # we need to identify what we got, and either replay it + # or pass it off to the command handler. + if ($mode == M_CMD) { + # command + my $key_str = join '', map { chr $_ } @key_buf; + if ($key_str =~ m/^\e\[([ABCD])/) { + print "Arrow key: $1"; + } else { + print "Dunno what that is." + } + } else { + $should_ignore = 1; + for my $key (@key_buf) { + Irssi::signal_emit('gui key pressed', $key); + } + $should_ignore = 0; + } + } + + @key_buf = (); + $key_buf_enabled = 0; +} sub handle_command { my ($key) = @_; @@ -130,24 +197,14 @@ sub handle_command { print "Going to execute command: ", $cmd->{command}; $cmd->{func}->( $cmd->{params} ); } else { - # some error handling. + _stop(); # disable everything else } } - - Irssi::signal_add_first 'gui key pressed' => \&got_key; Irssi::statusbar_item_register ('vim_mode', 0, 'vim_mode_cb'); -sub _key_buf_add { - my ($key) = @_; - push @key_buf, $key; - if (@key_buf > 5) { - shift @key_buf; - } -} - sub _input { my ($data) = @_; if (defined $data) { -- cgit v1.2.3