summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/getchar.c19
-rw-r--r--src/globals.h2
-rw-r--r--src/libvterm/include/vterm.h1
-rw-r--r--src/libvterm/src/keyboard.c11
-rw-r--r--src/libvterm/src/state.c5
-rw-r--r--src/libvterm/src/vterm_internal.h1
-rw-r--r--src/term.c189
-rw-r--r--src/terminal.c20
-rw-r--r--src/version.c2
9 files changed, 185 insertions, 65 deletions
diff --git a/src/getchar.c b/src/getchar.c
index 85ceddeb4..ecd6bdcd0 100644
--- a/src/getchar.c
+++ b/src/getchar.c
@@ -1733,6 +1733,25 @@ vgetc(void)
case K_XRIGHT: c = K_RIGHT; break;
}
+ if (!no_reduce_keys)
+ {
+ // A modifier was not used for a mapping, apply it to ASCII
+ // keys.
+ if ((mod_mask & MOD_MASK_CTRL)
+ && ((c >= '`' && c <= 0x7f)
+ || (c >= '@' && c <= '_')))
+ {
+ c &= 0x1f;
+ mod_mask &= ~MOD_MASK_CTRL;
+ }
+ if ((mod_mask & (MOD_MASK_META | MOD_MASK_ALT))
+ && c >= 0 && c <= 127)
+ {
+ c += 0x80;
+ mod_mask &= ~MOD_MASK_META;
+ }
+ }
+
// For a multi-byte character get all the bytes and return the
// converted character.
// Note: This will loop until enough bytes are received!
diff --git a/src/globals.h b/src/globals.h
index 2611266a7..d790c82e7 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -1006,6 +1006,8 @@ EXTERN int no_mapping INIT(= FALSE); // currently no mapping allowed
EXTERN int no_zero_mapping INIT(= 0); // mapping zero not allowed
EXTERN int allow_keys INIT(= FALSE); // allow key codes when no_mapping
// is set
+EXTERN int no_reduce_keys INIT(= FALSE); // do not apply Ctrl, Shift and Alt
+ // to the key
EXTERN int no_u_sync INIT(= 0); // Don't call u_sync()
#ifdef FEAT_EVAL
EXTERN int u_sync_once INIT(= 0); // Call u_sync() once when evaluating
diff --git a/src/libvterm/include/vterm.h b/src/libvterm/include/vterm.h
index 02ea91cd5..28d0a10f5 100644
--- a/src/libvterm/include/vterm.h
+++ b/src/libvterm/include/vterm.h
@@ -200,6 +200,7 @@ size_t vterm_output_get_buffer_remaining(const VTerm *vt);
size_t vterm_output_read(VTerm *vt, char *buffer, size_t len);
+int vterm_is_modify_other_keys(VTerm *vt);
void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod);
void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod);
diff --git a/src/libvterm/src/keyboard.c b/src/libvterm/src/keyboard.c
index 62338c638..95b962ed6 100644
--- a/src/libvterm/src/keyboard.c
+++ b/src/libvterm/src/keyboard.c
@@ -4,10 +4,21 @@
#include "utf8.h"
+int vterm_is_modify_other_keys(VTerm *vt)
+{
+ return vt->state->mode.modify_other_keys;
+}
+
+
void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod)
{
int needs_CSIu;
+ if (vt->state->mode.modify_other_keys && mod != 0) {
+ vterm_push_output_sprintf_ctrl(vt, C1_CSI, "27;%d;%d~", mod+1, c);
+ return;
+ }
+
// The shift modifier is never important for Unicode characters
// apart from Space
if(c != ' ')
diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c
index 1f7ac02de..6b2583af9 100644
--- a/src/libvterm/src/state.c
+++ b/src/libvterm/src/state.c
@@ -1334,6 +1334,11 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha
vterm_state_setpen(state, args, argcount);
break;
+ case LEADER('>', 0x6d): // xterm resource modifyOtherKeys
+ if (argcount == 2 && args[0] == 4)
+ state->mode.modify_other_keys = args[1] == 2;
+ break;
+
case 0x6e: // DSR - ECMA-48 8.3.35
case LEADER('?', 0x6e): // DECDSR
val = CSI_ARG_OR(args[0], 0);
diff --git a/src/libvterm/src/vterm_internal.h b/src/libvterm/src/vterm_internal.h
index 5b6198bdc..e2b8b159b 100644
--- a/src/libvterm/src/vterm_internal.h
+++ b/src/libvterm/src/vterm_internal.h
@@ -124,6 +124,7 @@ struct VTermState
unsigned int leftrightmargin:1;
unsigned int bracketpaste:1;
unsigned int report_focus:1;
+ unsigned int modify_other_keys:1;
} mode;
VTermEncodingInstance encoding[4], encoding_utf8;
diff --git a/src/term.c b/src/term.c
index f021a17ff..27def15c6 100644
--- a/src/term.c
+++ b/src/term.c
@@ -4199,6 +4199,99 @@ is_mouse_topline(win_T *wp)
#endif
/*
+ * Put "string[new_slen]" in typebuf, or in "buf[bufsize]" if "buf" is not NULL.
+ * Remove "slen" bytes.
+ * Returns FAIL for error.
+ */
+ static int
+put_string_in_typebuf(
+ int offset,
+ int slen,
+ char_u *string,
+ int new_slen,
+ char_u *buf,
+ int bufsize,
+ int *buflen)
+{
+ int extra = new_slen - slen;
+
+ string[new_slen] = NUL;
+ if (buf == NULL)
+ {
+ if (extra < 0)
+ // remove matched chars, taking care of noremap
+ del_typebuf(-extra, offset);
+ else if (extra > 0)
+ // insert the extra space we need
+ ins_typebuf(string + slen, REMAP_YES, offset, FALSE, FALSE);
+
+ // Careful: del_typebuf() and ins_typebuf() may have reallocated
+ // typebuf.tb_buf[]!
+ mch_memmove(typebuf.tb_buf + typebuf.tb_off + offset, string,
+ (size_t)new_slen);
+ }
+ else
+ {
+ if (extra < 0)
+ // remove matched characters
+ mch_memmove(buf + offset, buf + offset - extra,
+ (size_t)(*buflen + offset + extra));
+ else if (extra > 0)
+ {
+ // Insert the extra space we need. If there is insufficient
+ // space return -1.
+ if (*buflen + extra + new_slen >= bufsize)
+ return FAIL;
+ mch_memmove(buf + offset + extra, buf + offset,
+ (size_t)(*buflen - offset));
+ }
+ mch_memmove(buf + offset, string, (size_t)new_slen);
+ *buflen = *buflen + extra + new_slen;
+ }
+ return OK;
+}
+
+/*
+ * Decode a modifier number as xterm provides it into MOD_MASK bits.
+ */
+ static int
+decode_modifiers(int n)
+{
+ int code = n - 1;
+ int modifiers = 0;
+
+ if (code & 1)
+ modifiers |= MOD_MASK_SHIFT;
+ if (code & 2)
+ modifiers |= MOD_MASK_ALT;
+ if (code & 4)
+ modifiers |= MOD_MASK_CTRL;
+ if (code & 8)
+ modifiers |= MOD_MASK_META;
+ return modifiers;
+}
+
+ static int
+modifiers2keycode(int modifiers, int *key, char_u *string)
+{
+ int new_slen = 0;
+
+ if (modifiers != 0)
+ {
+ // Some keys have the modifier included. Need to handle that here to
+ // make mappings work.
+ *key = simplify_key(*key, &modifiers);
+ if (modifiers != 0)
+ {
+ string[new_slen++] = K_SPECIAL;
+ string[new_slen++] = (int)KS_MODIFIER;
+ string[new_slen++] = modifiers;
+ }
+ }
+ return new_slen;
+}
+
+/*
* Check if typebuf.tb_buf[] contains a terminal key code.
* Check from typebuf.tb_buf[typebuf.tb_off] to typebuf.tb_buf[typebuf.tb_off
* + max_offset].
@@ -4229,8 +4322,7 @@ check_termcode(
int modifiers;
char_u *modifiers_start = NULL;
int key;
- int new_slen;
- int extra;
+ int new_slen; // Length of what will replace the termcode
char_u string[MAX_KEY_CODE_LEN + 1];
int i, j;
int idx = 0;
@@ -4401,16 +4493,9 @@ check_termcode(
modifiers_start = tp + slen - 2;
- /* Match! Convert modifier bits. */
- n = atoi((char *)modifiers_start) - 1;
- if (n & 1)
- modifiers |= MOD_MASK_SHIFT;
- if (n & 2)
- modifiers |= MOD_MASK_ALT;
- if (n & 4)
- modifiers |= MOD_MASK_CTRL;
- if (n & 8)
- modifiers |= MOD_MASK_META;
+ // Match! Convert modifier bits.
+ n = atoi((char *)modifiers_start);
+ modifiers |= decode_modifiers(n);
slen = j;
}
@@ -4751,9 +4836,32 @@ not_enough:
winpos_status.tr_progress = STATUS_GOT;
}
- // TODO: key with modifier:
+ // Key with modifier:
// {lead}27;{modifier};{key}~
// {lead}{key};{modifier}u
+ else if ((arg[0] == 27 && argc == 3 && trail == '~')
+ || (argc == 2 && trail == 'u'))
+ {
+ if (trail == 'u')
+ key = arg[0];
+ else
+ key = arg[2];
+
+ // insert modifiers with KS_MODIFIER
+ modifiers = decode_modifiers(arg[1]);
+ new_slen = modifiers2keycode(modifiers, &key, string);
+ slen = csi_len;
+
+ if (has_mbyte)
+ new_slen += (*mb_char2bytes)(key, string + new_slen);
+ else
+ string[new_slen++] = key;
+
+ if (put_string_in_typebuf(offset, slen, string, new_slen,
+ buf, bufsize, buflen) == FAIL)
+ return -1;
+ return len + new_slen - slen + offset;
+ }
// else: Unknown CSI sequence. We could drop it, but then the
// user can't create a map for it.
@@ -5138,19 +5246,7 @@ not_enough:
/*
* Add any modifier codes to our string.
*/
- new_slen = 0; /* Length of what will replace the termcode */
- if (modifiers != 0)
- {
- /* Some keys have the modifier included. Need to handle that here
- * to make mappings work. */
- key = simplify_key(key, &modifiers);
- if (modifiers != 0)
- {
- string[new_slen++] = K_SPECIAL;
- string[new_slen++] = (int)KS_MODIFIER;
- string[new_slen++] = modifiers;
- }
- }
+ new_slen = modifiers2keycode(modifiers, &key, string);
/* Finally, add the special key code to our string */
key_name[0] = KEY2TERMCAP0(key);
@@ -5176,43 +5272,10 @@ not_enough:
string[new_slen++] = key_name[0];
string[new_slen++] = key_name[1];
}
- string[new_slen] = NUL;
- extra = new_slen - slen;
- if (buf == NULL)
- {
- if (extra < 0)
- /* remove matched chars, taking care of noremap */
- del_typebuf(-extra, offset);
- else if (extra > 0)
- /* insert the extra space we need */
- ins_typebuf(string + slen, REMAP_YES, offset, FALSE, FALSE);
-
- /*
- * Careful: del_typebuf() and ins_typebuf() may have reallocated
- * typebuf.tb_buf[]!
- */
- mch_memmove(typebuf.tb_buf + typebuf.tb_off + offset, string,
- (size_t)new_slen);
- }
- else
- {
- if (extra < 0)
- /* remove matched characters */
- mch_memmove(buf + offset, buf + offset - extra,
- (size_t)(*buflen + offset + extra));
- else if (extra > 0)
- {
- /* Insert the extra space we need. If there is insufficient
- * space return -1. */
- if (*buflen + extra + new_slen >= bufsize)
- return -1;
- mch_memmove(buf + offset + extra, buf + offset,
- (size_t)(*buflen - offset));
- }
- mch_memmove(buf + offset, string, (size_t)new_slen);
- *buflen = *buflen + extra + new_slen;
- }
- return retval == 0 ? (len + extra + offset) : retval;
+ if (put_string_in_typebuf(offset, slen, string, new_slen,
+ buf, bufsize, buflen) == FAIL)
+ return -1;
+ return retval == 0 ? (len + new_slen - slen + offset) : retval;
}
#ifdef FEAT_TERMRESPONSE
diff --git a/src/terminal.c b/src/terminal.c
index 42a80cd7d..a992b444d 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -1371,11 +1371,13 @@ term_convert_key(term_T *term, int c, char *buf)
break;
}
+ // add modifiers for the typed key
+ mod |= mod_mask;
+
/*
* Convert special keys to vterm keys:
* - Write keys to vterm: vterm_keyboard_key()
* - Write output to channel.
- * TODO: use mod_mask
*/
if (key != VTERM_KEY_NONE)
/* Special key, let vterm convert it. */
@@ -1902,15 +1904,21 @@ term_vgetc()
{
int c;
int save_State = State;
+ int modify_other_keys =
+ vterm_is_modify_other_keys(curbuf->b_term->tl_vterm);
State = TERMINAL;
got_int = FALSE;
#ifdef MSWIN
ctrl_break_was_pressed = FALSE;
#endif
+ if (modify_other_keys)
+ ++no_reduce_keys;
c = vgetc();
got_int = FALSE;
State = save_State;
+ if (modify_other_keys)
+ --no_reduce_keys;
return c;
}
@@ -2255,6 +2263,7 @@ term_win_entered()
terminal_loop(int blocking)
{
int c;
+ int raw_c;
int termwinkey = 0;
int ret;
#ifdef UNIX
@@ -2307,6 +2316,13 @@ terminal_loop(int blocking)
if (c == K_IGNORE)
continue;
+ // vgetc may not include CTRL in the key when modify_other_keys is set.
+ raw_c = c;
+ if ((mod_mask & MOD_MASK_CTRL)
+ && ((c >= '`' && c <= 0x7f)
+ || (c >= '@' && c <= '_')))
+ c &= 0x1f;
+
#ifdef UNIX
/*
* The shell or another program may change the tty settings. Getting
@@ -2417,7 +2433,7 @@ terminal_loop(int blocking)
c = wc;
}
# endif
- if (send_keys_to_term(curbuf->b_term, c, TRUE) != OK)
+ if (send_keys_to_term(curbuf->b_term, raw_c, TRUE) != OK)
{
if (c == K_MOUSEMOVE)
/* We are sure to come back here, don't reset the cursor color
diff --git a/src/version.c b/src/version.c
index acbcc2d25..7289c9bb6 100644
--- a/src/version.c
+++ b/src/version.c
@@ -754,6 +754,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2134,
+/**/
2133,
/**/
2132,