keymap: Support <D-...> (super/command key).

Adds support for:
  - api:vim_input("<D-a>")
  - ":nnoremap <C-D-S-...>" and permutations thereof

UIs must capture the modifier and send it as "<D-...>" to vim_input().

Note: Before this commit, any arbitrary ":nnoremap <{foo}-{bar}>"
mapping could already be invoked with feedkeys("\<{foo}-{bar}>"). This
commit supports "D-" as a modifier that can be combined with "C-", "A-",
"S-" in any order.

For non-GUI (terminal) support, user must:
  :set <D-a>={CSI sequence}
then send the {CSI sequence} from their terminal. But this does not work
yet (regression #2204).

Closes #2190
This commit is contained in:
Justin M. Keyes 2016-02-20 17:09:15 -05:00
parent 9403ce82bc
commit 99d4c8c29c
6 changed files with 54 additions and 41 deletions

View File

@ -452,7 +452,7 @@ notation meaning equivalent decimal value(s) ~
<C-...> control-key *control* *ctrl* *<C-*
<M-...> alt-key or meta-key *meta* *alt* *<M-*
<A-...> same as <M-...> *<A-*
<D-...> command-key (Macintosh only) *<D-*
<D-...> command-key or "super" key *<D-*
<t_xx> key with "xx" entry in termcap
-----------------------------------------------------------------------

View File

@ -4947,15 +4947,10 @@ int get_literal(void)
return cc;
}
/*
* Insert character, taking care of special keys and mod_mask
*/
static void
insert_special (
int c,
int allow_modmask,
int ctrlv /* c was typed after CTRL-V */
)
/// Insert character, taking care of special keys and mod_mask
///
/// @param ctrlv `c` was typed after CTRL-V
static void insert_special(int c, int allow_modmask, int ctrlv)
{
char_u *p;
int len;
@ -4967,6 +4962,9 @@ insert_special (
* Only use mod_mask for special keys, to avoid things like <S-Space>,
* unless 'allow_modmask' is TRUE.
*/
if (mod_mask & MOD_MASK_CMD) { // Command-key never produces a normal key.
allow_modmask = true;
}
if (IS_SPECIAL(c) || (mod_mask && allow_modmask)) {
p = get_special_key_name(c, mod_mask);
len = (int)STRLEN(p);

View File

@ -1,8 +1,3 @@
/*
* functions that use lookup tables for various things, generally to do with
* special key codes.
*/
#include <assert.h>
#include <inttypes.h>
#include <limits.h>
@ -39,7 +34,8 @@ static struct modmasktable {
{MOD_MASK_MULTI_CLICK, MOD_MASK_2CLICK, (char_u)'2'},
{MOD_MASK_MULTI_CLICK, MOD_MASK_3CLICK, (char_u)'3'},
{MOD_MASK_MULTI_CLICK, MOD_MASK_4CLICK, (char_u)'4'},
/* 'A' must be the last one */
{MOD_MASK_CMD, MOD_MASK_CMD, (char_u)'D'},
// 'A' must be the last one
{MOD_MASK_ALT, MOD_MASK_ALT, (char_u)'A'},
{0, 0, NUL}
};
@ -658,9 +654,11 @@ static int extract_modifiers(int key, int *modp)
{
int modifiers = *modp;
if ((modifiers & MOD_MASK_SHIFT) && ASCII_ISALPHA(key)) {
key = TOUPPER_ASC(key);
modifiers &= ~MOD_MASK_SHIFT;
if (!(modifiers & MOD_MASK_CMD)) { // Command-key is special
if ((modifiers & MOD_MASK_SHIFT) && ASCII_ISALPHA(key)) {
key = TOUPPER_ASC(key);
modifiers &= ~MOD_MASK_SHIFT;
}
}
if ((modifiers & MOD_MASK_CTRL)
&& ((key >= '?' && key <= '_') || ASCII_ISALPHA(key))) {

View File

@ -112,11 +112,11 @@
#define TO_SPECIAL(a, b) ((a) == KS_SPECIAL ? K_SPECIAL : (a) == \
KS_ZERO ? K_ZERO : TERMCAP2KEY(a, b))
/*
* Codes for keys that do not have a termcap name.
*
* K_SPECIAL KS_EXTRA KE_xxx
*/
// Codes for keys that do not have a termcap name.
//
// K_SPECIAL KS_EXTRA KE_xxx
//
// Entries must be in the range 0x02-0x7f (see comment at K_SPECIAL).
enum key_extra {
KE_NAME = 3 /* name of this terminal entry */
@ -436,11 +436,12 @@ enum key_extra {
/* 0x01 cannot be used, because the modifier must be 0x02 or higher */
#define MOD_MASK_SHIFT 0x02
#define MOD_MASK_CTRL 0x04
#define MOD_MASK_ALT 0x08 /* aka META */
#define MOD_MASK_META 0x10 /* META when it's different from ALT */
#define MOD_MASK_2CLICK 0x20 /* use MOD_MASK_MULTI_CLICK */
#define MOD_MASK_3CLICK 0x40 /* use MOD_MASK_MULTI_CLICK */
#define MOD_MASK_4CLICK 0x60 /* use MOD_MASK_MULTI_CLICK */
#define MOD_MASK_ALT 0x08 // aka META
#define MOD_MASK_META 0x10 // META when it's different from ALT
#define MOD_MASK_2CLICK 0x20 // use MOD_MASK_MULTI_CLICK
#define MOD_MASK_3CLICK 0x40 // use MOD_MASK_MULTI_CLICK
#define MOD_MASK_4CLICK 0x60 // use MOD_MASK_MULTI_CLICK
#define MOD_MASK_CMD 0x80 // "super" key (OSX/Mac: command-key)
#define MOD_MASK_MULTI_CLICK (MOD_MASK_2CLICK|MOD_MASK_3CLICK| \
MOD_MASK_4CLICK)
@ -451,14 +452,13 @@ enum key_extra {
*/
#define MAX_KEY_NAME_LEN 25
/* Maximum length of a special key event as tokens. This includes modifiers.
* The longest event is something like <M-C-S-T-4-LeftDrag> which would be the
* following string of tokens:
*
* <K_SPECIAL> <KS_MODIFIER> bitmask <K_SPECIAL> <KS_EXTRA> <KT_LEFTDRAG>.
*
* This is a total of 6 tokens, and is currently the longest one possible.
*/
// Maximum length of a special key event as tokens. This includes modifiers.
// The longest event is something like <M-C-S-T-4-LeftDrag> which would be the
// following string of tokens:
//
// <K_SPECIAL> <KS_MODIFIER> bitmask <K_SPECIAL> <KS_EXTRA> <KE_LEFTDRAG>.
//
// This is a total of 6 tokens, and is currently the longest one possible.
#define MAX_KEY_CODE_LEN 6

View File

@ -144,15 +144,23 @@ describe('vim_* functions', function()
describe('replace_termcodes', function()
it('escapes K_SPECIAL as K_SPECIAL KS_SPECIAL KE_FILLER', function()
eq(helpers.nvim('replace_termcodes', '\128', true, true, true), '\128\254X')
eq('\128\254X', helpers.nvim('replace_termcodes', '\128', true, true, true))
end)
it('leaves non K_SPECIAL string unchanged', function()
eq(helpers.nvim('replace_termcodes', 'abc', true, true, true), 'abc')
it('leaves non-K_SPECIAL string unchanged', function()
eq('abc', helpers.nvim('replace_termcodes', 'abc', true, true, true))
end)
it('converts <expressions>', function()
eq(helpers.nvim('replace_termcodes', '<Leader>', true, true, true), '\\')
eq('\\', helpers.nvim('replace_termcodes', '<Leader>', true, true, true))
end)
it('converts <LeftMouse> to K_SPECIAL KS_EXTRA KE_LEFTMOUSE', function()
-- K_SPECIAL KS_EXTRA KE_LEFTMOUSE
-- 0x80 0xfd 0x2c
-- 128 253 44
eq('\128\253\44', helpers.nvim('replace_termcodes',
'<LeftMouse>', true, true, true))
end)
end)

View File

@ -25,6 +25,9 @@ describe('mappings', function()
add_mapping('<s-up>', '<s-up>')
add_mapping('<c-s-up>', '<c-s-up>')
add_mapping('<c-s-a-up>', '<c-s-a-up>')
add_mapping('<c-s-a-d-up>', '<c-s-a-d-up>')
add_mapping('<c-d-a>', '<c-d-a>')
add_mapping('<d-1>', '<d-1>')
end)
it('ok', function()
@ -37,6 +40,12 @@ describe('mappings', function()
check_mapping('<s-a-c-up>', '<c-s-a-up>')
check_mapping('<a-c-s-up>', '<c-s-a-up>')
check_mapping('<a-s-c-up>', '<c-s-a-up>')
check_mapping('<c-s-a-d-up>', '<c-s-a-d-up>')
check_mapping('<s-a-d-c-up>', '<c-s-a-d-up>')
check_mapping('<d-s-a-c-up>', '<c-s-a-d-up>')
check_mapping('<c-d-a>', '<c-d-a>')
check_mapping('<d-c-a>', '<c-d-a>')
check_mapping('<d-1>', '<d-1>')
end)
end)