1
0
forked from aniani/vim

patch 9.1.0563: Cannot process any Key event

Problem:  Cannot process any Key event
Solution: Add the KeyInputPre autocmd
          (Shougo Matsushita)

closes: #15182

Co-authored-by: zeertzjq <zeertzjq@outlook.com>
Co-authored-by: K.Takata <kentkt@csc.jp>
Signed-off-by: Shougo Matsushita <Shougo.Matsu@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Shougo Matsushita
2024-07-11 22:05:12 +02:00
committed by Christian Brabandt
parent e7b98ab96e
commit 8367884909
10 changed files with 182 additions and 2 deletions

View File

@@ -1,4 +1,4 @@
*autocmd.txt* For Vim version 9.1. Last change: 2024 Jul 09 *autocmd.txt* For Vim version 9.1. Last change: 2024 Jul 11
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
@@ -439,6 +439,8 @@ Name triggered by ~
|CompleteDone| after Insert mode completion is done, after clearing |CompleteDone| after Insert mode completion is done, after clearing
info info
|KeyInputPre| just before a key is processed
|User| to be used in combination with ":doautocmd" |User| to be used in combination with ":doautocmd"
|SigUSR1| after the SIGUSR1 signal has been detected |SigUSR1| after the SIGUSR1 signal has been detected
@@ -977,6 +979,21 @@ InsertLeavePre Just before leaving Insert mode. Also when
*InsertLeave* *InsertLeave*
InsertLeave Just after leaving Insert mode. Also when InsertLeave Just after leaving Insert mode. Also when
using CTRL-O |i_CTRL-O|. But not for |i_CTRL-C|. using CTRL-O |i_CTRL-O|. But not for |i_CTRL-C|.
*KeyInputPre*
KeyInputPre Just before a key is processed. The pattern is
matched against a string that indicates the
current mode, which is the same as what is
returned by `mode(1)`.
The |v:char| variable indicates the key typed
and can be changed during the event to process
a different key. When |v:char| is not a
single character or a special key, the first
character is used.
The following values of |v:event| are set:
typed The key is typed or not.
It is not allowed to change the text
|textlock| or the current mode.
{only with the +eval feature}
*MenuPopup* *MenuPopup*
MenuPopup Just before showing the popup menu (under the MenuPopup Just before showing the popup menu (under the
right mouse button). Useful for adjusting the right mouse button). Useful for adjusting the

View File

@@ -1995,7 +1995,8 @@ v:beval_winid The |window-ID| of the window, over which the mouse pointer
*v:char* *char-variable* *v:char* *char-variable*
v:char Argument for evaluating 'formatexpr' and used for the typed v:char Argument for evaluating 'formatexpr' and used for the typed
character when using <expr> in an abbreviation |:map-<expr>|. character when using <expr> in an abbreviation |:map-<expr>|.
It is also used by the |InsertCharPre| and |InsertEnter| events. It is also used by the |InsertCharPre|, |InsertEnter| and
|KeyInputPre| events.
*v:charconvert_from* *charconvert_from-variable* *v:charconvert_from* *charconvert_from-variable*
v:charconvert_from v:charconvert_from

View File

@@ -5554,6 +5554,7 @@ Jobs eval.txt /*Jobs*
K various.txt /*K* K various.txt /*K*
KDE gui_x11.txt /*KDE* KDE gui_x11.txt /*KDE*
KVim gui_x11.txt /*KVim* KVim gui_x11.txt /*KVim*
KeyInputPre autocmd.txt /*KeyInputPre*
Kibaale uganda.txt /*Kibaale* Kibaale uganda.txt /*Kibaale*
Korean mbyte.txt /*Korean* Korean mbyte.txt /*Korean*
L motion.txt /*L* L motion.txt /*L*

View File

@@ -41607,6 +41607,7 @@ Functions: ~
Autocommands: ~ Autocommands: ~
|CursorMovedC| after the cursor was moved in the comamnd-line |CursorMovedC| after the cursor was moved in the comamnd-line
|KeyInputPre| process any Key event in any mode
|SessionWritePost| after writing the session file |:mksession| |SessionWritePost| after writing the session file |:mksession|
|TermResponseAll| after the terminal response to |t_RV| and others is |TermResponseAll| after the terminal response to |t_RV| and others is
received received

View File

@@ -155,6 +155,7 @@ static keyvalue_T event_tab[] = {
KEYVALUE_ENTRY(EVENT_INSERTENTER, "InsertEnter"), KEYVALUE_ENTRY(EVENT_INSERTENTER, "InsertEnter"),
KEYVALUE_ENTRY(EVENT_INSERTLEAVE, "InsertLeave"), KEYVALUE_ENTRY(EVENT_INSERTLEAVE, "InsertLeave"),
KEYVALUE_ENTRY(EVENT_INSERTLEAVEPRE, "InsertLeavePre"), KEYVALUE_ENTRY(EVENT_INSERTLEAVEPRE, "InsertLeavePre"),
KEYVALUE_ENTRY(EVENT_KEYINPUTPRE, "KeyInputPre"),
KEYVALUE_ENTRY(EVENT_MENUPOPUP, "MenuPopup"), KEYVALUE_ENTRY(EVENT_MENUPOPUP, "MenuPopup"),
KEYVALUE_ENTRY(EVENT_MODECHANGED, "ModeChanged"), KEYVALUE_ENTRY(EVENT_MODECHANGED, "ModeChanged"),
KEYVALUE_ENTRY(EVENT_OPTIONSET, "OptionSet"), KEYVALUE_ENTRY(EVENT_OPTIONSET, "OptionSet"),
@@ -2021,6 +2022,15 @@ has_insertcharpre(void)
return (first_autopat[(int)EVENT_INSERTCHARPRE] != NULL); return (first_autopat[(int)EVENT_INSERTCHARPRE] != NULL);
} }
/*
* Return TRUE when there is an KeyInputPre autocommand defined.
*/
int
has_keyinputpre(void)
{
return (first_autopat[(int)EVENT_KEYINPUTPRE] != NULL);
}
/* /*
* Return TRUE when there is an CmdUndefined autocommand defined. * Return TRUE when there is an CmdUndefined autocommand defined.
*/ */
@@ -2256,6 +2266,7 @@ apply_autocmds_group(
|| event == EVENT_CMDWINLEAVE || event == EVENT_CMDWINLEAVE
|| event == EVENT_CMDUNDEFINED || event == EVENT_CMDUNDEFINED
|| event == EVENT_FUNCUNDEFINED || event == EVENT_FUNCUNDEFINED
|| event == EVENT_KEYINPUTPRE
|| event == EVENT_REMOTEREPLY || event == EVENT_REMOTEREPLY
|| event == EVENT_SPELLFILEMISSING || event == EVENT_SPELLFILEMISSING
|| event == EVENT_QUICKFIXCMDPRE || event == EVENT_QUICKFIXCMDPRE

View File

@@ -96,6 +96,9 @@ static void closescript(void);
static void updatescript(int c); static void updatescript(int c);
static int vgetorpeek(int); static int vgetorpeek(int);
static int inchar(char_u *buf, int maxlen, long wait_time); static int inchar(char_u *buf, int maxlen, long wait_time);
#ifdef FEAT_EVAL
static int do_key_input_pre(int c);
#endif
/* /*
* Free and clear a buffer. * Free and clear a buffer.
@@ -2130,6 +2133,10 @@ vgetc(void)
} }
#endif #endif
#ifdef FEAT_EVAL
c = do_key_input_pre(c);
#endif
// Need to process the character before we know it's safe to do something // Need to process the character before we know it's safe to do something
// else. // else.
if (c != K_IGNORE) if (c != K_IGNORE)
@@ -2138,6 +2145,74 @@ vgetc(void)
return c; return c;
} }
#ifdef FEAT_EVAL
/*
* Handle the InsertCharPre autocommand.
* "c" is the character that was typed.
* Return new input character.
*/
static int
do_key_input_pre(int c)
{
int res = c;
char_u buf[MB_MAXBYTES + 1];
char_u curr_mode[MODE_MAX_LENGTH];
int save_State = State;
save_v_event_T save_v_event;
dict_T *v_event;
// Return quickly when there is nothing to do.
if (!has_keyinputpre())
return res;
if (IS_SPECIAL(c))
{
buf[0] = K_SPECIAL;
buf[1] = KEY2TERMCAP0(c);
buf[2] = KEY2TERMCAP1(c);
buf[3] = NUL;
}
else
buf[(*mb_char2bytes)(c, buf)] = NUL;
get_mode(curr_mode);
// Lock the text to avoid weird things from happening.
++textlock;
set_vim_var_string(VV_CHAR, buf, -1); // set v:char
v_event = get_v_event(&save_v_event);
(void)dict_add_bool(v_event, "typed", KeyTyped);
if (apply_autocmds(EVENT_KEYINPUTPRE, curr_mode, curr_mode, FALSE, curbuf)
&& STRCMP(buf, get_vim_var_str(VV_CHAR)) != 0)
{
// Get the value of v:char. It may be empty or more than one
// character. Only use it when changed, otherwise continue with the
// original character.
char_u *v_char;
v_char = get_vim_var_str(VV_CHAR);
// Convert special bytes when it is special string.
if (STRLEN(v_char) >= 3 && v_char[0] == K_SPECIAL)
res = TERMCAP2KEY(v_char[1], v_char[2]);
else if (STRLEN(v_char) > 0)
res = PTR2CHAR(v_char);
}
restore_v_event(v_event, &save_v_event);
set_vim_var_string(VV_CHAR, NULL, -1); // clear v:char
--textlock;
// Restore the State, it may have been changed.
State = save_State;
return res;
}
#endif
/* /*
* Like vgetc(), but never return a NUL when called recursively, get a key * Like vgetc(), but never return a NUL when called recursively, get a key
* directly from the user (ignoring typeahead). * directly from the user (ignoring typeahead).

View File

@@ -26,6 +26,7 @@ int has_textchanged(void);
int has_textchangedI(void); int has_textchangedI(void);
int has_textchangedP(void); int has_textchangedP(void);
int has_insertcharpre(void); int has_insertcharpre(void);
int has_keyinputpre(void);
int has_cmdundefined(void); int has_cmdundefined(void);
int has_textyankpost(void); int has_textyankpost(void);
int has_completechanged(void); int has_completechanged(void);

View File

@@ -4752,4 +4752,74 @@ func Test_BufEnter_botline()
set hidden&vim set hidden&vim
endfunc endfunc
func Test_KeyInputPre()
" Consume previous keys
call feedkeys('', 'ntx')
" KeyInputPre can record input keys.
let s:keys = []
au KeyInputPre n call add(s:keys, v:char)
call feedkeys('jkjkjjj', 'ntx')
call assert_equal(
\ ['j', 'k', 'j', 'k', 'j', 'j', 'j'],
\ s:keys)
unlet s:keys
au! KeyInputPre
" KeyInputPre can handle multibyte.
let s:keys = []
au KeyInputPre * call add(s:keys, v:char)
edit Xxx1
call feedkeys("iあ\<ESC>", 'ntx')
call assert_equal(['i', "あ", "\<ESC>"], s:keys)
bwipe! Xxx1
unlet s:keys
au! KeyInputPre
" KeyInputPre can change input keys.
au KeyInputPre i if v:char ==# 'a' | let v:char = 'b' | endif
edit Xxx1
call feedkeys("iaabb\<ESC>", 'ntx')
call assert_equal(getline('.'), 'bbbb')
bwipe! Xxx1
au! KeyInputPre
" KeyInputPre returns multiple characters.
au KeyInputPre i if v:char ==# 'a' | let v:char = 'cccc' | endif
edit Xxx1
call feedkeys("iaabb\<ESC>", 'ntx')
call assert_equal(getline('.'), 'ccbb')
bwipe! Xxx1
au! KeyInputPre
" KeyInputPre can use special keys.
au KeyInputPre i if v:char ==# 'a' | let v:char = "\<Ignore>" | endif
edit Xxx1
call feedkeys("iaabb\<ESC>", 'ntx')
call assert_equal(getline('.'), 'bb')
bwipe! Xxx1
au! KeyInputPre
" Test for v:event.typed
au KeyInputPre n call assert_true(v:event.typed)
call feedkeys('j', 'ntx')
au! KeyInputPre
au KeyInputPre n call assert_false(v:event.typed)
call feedkeys('j', 'nx')
au! KeyInputPre
endfunc
" vim: shiftwidth=2 sts=2 expandtab " vim: shiftwidth=2 sts=2 expandtab

View File

@@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
563,
/**/ /**/
562, 562,
/**/ /**/

View File

@@ -1397,6 +1397,7 @@ enum auto_event
EVENT_INSERTENTER, // when entering Insert mode EVENT_INSERTENTER, // when entering Insert mode
EVENT_INSERTLEAVEPRE, // just before leaving Insert mode EVENT_INSERTLEAVEPRE, // just before leaving Insert mode
EVENT_INSERTLEAVE, // just after leaving Insert mode EVENT_INSERTLEAVE, // just after leaving Insert mode
EVENT_KEYINPUTPRE, // before key input
EVENT_MENUPOPUP, // just before popup menu is displayed EVENT_MENUPOPUP, // just before popup menu is displayed
EVENT_MODECHANGED, // after changing the mode EVENT_MODECHANGED, // after changing the mode
EVENT_OPTIONSET, // option was set EVENT_OPTIONSET, // option was set