Patch 8.1.2145
Problem:    Cannot map <C-H> when modifyOtherKeys is enabled.
Solution:   Add the <C-H> mapping twice, both with modifier and as 0x08.  Use
            only the first one when modifyOtherKeys has been detected.
Files:      src/term.c, src/eval.c, src/getchar.c, src/globals.h,
            src/gui_mac.c, src/gui_w32.c, src/highlight.c, src/if_ole.cpp,
            src/main.c, src/map.c, src/menu.c, src/misc2.c, src/option.c,
            src/proto/misc2.pro, src/proto/term.pro,
            src/testdir/test_termcodes.vim, src/structs.h, src/terminal.c,
            src/usercmd.c, src/vim.h


*** ../vim-8.1.2144/src/term.c  2019-10-12 21:08:37.002660427 +0200
--- src/term.c  2019-10-13 16:32:33.182348952 +0200
***************
*** 4845,4850 ****
--- 4845,4851 ----
                else if ((arg[0] == 27 && argc == 3 && trail == '~')
                        || (argc == 2 && trail == 'u'))
                {
+                   seenModifyOtherKeys = TRUE;
                    if (trail == 'u')
                        key = arg[0];
                    else
***************
*** 4853,4865 ****
                    modifiers = decode_modifiers(arg[1]);
  
                    // Some keys already have Shift included, pass them as
!                   // normal keys.
                    if (modifiers == MOD_MASK_SHIFT
                            && ((key >= '@' && key <= 'Z')
                                || key == '^' || key == '_'
                                || (key >= '{' && key <= '~')))
                        modifiers = 0;
  
                    // insert modifiers with KS_MODIFIER
                    new_slen = modifiers2keycode(modifiers, &key, string);
                    slen = csi_len;
--- 4854,4873 ----
                    modifiers = decode_modifiers(arg[1]);
  
                    // Some keys already have Shift included, pass them as
!                   // normal keys.  Not when Ctrl is also used, because <C-H>
!                   // and <C-S-H> are different.
                    if (modifiers == MOD_MASK_SHIFT
                            && ((key >= '@' && key <= 'Z')
                                || key == '^' || key == '_'
                                || (key >= '{' && key <= '~')))
                        modifiers = 0;
  
+                   // When used with Ctrl we always make a letter upper case,
+                   // so that mapping <C-H> and <C-h> are the same.  Typing
+                   // <C-S-H> also uses "H" but modifier is different.
+                   if ((modifiers & MOD_MASK_CTRL) && ASCII_ISALPHA(key))
+                       key = TOUPPER_ASC(key);
+ 
                    // insert modifiers with KS_MODIFIER
                    new_slen = modifiers2keycode(modifiers, &key, string);
                    slen = csi_len;
***************
*** 5340,5357 ****
   * pointer to it is returned. If something fails *bufp is set to NULL and from
   * is returned.
   *
!  * CTRL-V characters are removed.  When "from_part" is TRUE, a trailing CTRL-V
!  * is included, otherwise it is removed (for ":map xx ^V", maps xx to
!  * nothing).  When 'cpoptions' does not contain 'B', a backslash can be used
!  * instead of a CTRL-V.
   */
      char_u *
  replace_termcodes(
      char_u    *from,
      char_u    **bufp,
!     int               from_part,
!     int               do_lt,          /* also translate <lt> */
!     int               special)        /* always accept <key> notation */
  {
      int               i;
      int               slen;
--- 5348,5373 ----
   * pointer to it is returned. If something fails *bufp is set to NULL and from
   * is returned.
   *
!  * CTRL-V characters are removed.  When "flags" has REPTERM_FROM_PART, a
!  * trailing CTRL-V is included, otherwise it is removed (for ":map xx ^V", 
maps
!  * xx to nothing).  When 'cpoptions' does not contain 'B', a backslash can be
!  * used instead of a CTRL-V.
!  *
!  * Flags:
!  *  REPTERM_FROM_PART see above
!  *  REPTERM_DO_LT     also translate <lt>
!  *  REPTERM_SPECIAL   always accept <key> notation
!  *  REPTERM_NO_SIMPLIFY       do not simplify <C-H> to 0x08 and set 8th bit 
for <A-x>
!  *
!  * "did_simplify" is set when some <C-H> or <A-x> code was simplified, unless
!  * it is NULL.
   */
      char_u *
  replace_termcodes(
      char_u    *from,
      char_u    **bufp,
!     int               flags,
!     int               *did_simplify)
  {
      int               i;
      int               slen;
***************
*** 5364,5370 ****
      char_u    *result;        /* buffer for resulting string */
  
      do_backslash = (vim_strchr(p_cpo, CPO_BSLASH) == NULL);
!     do_special = (vim_strchr(p_cpo, CPO_SPECI) == NULL) || special;
      do_key_code = (vim_strchr(p_cpo, CPO_KEYCODE) == NULL);
  
      /*
--- 5380,5387 ----
      char_u    *result;        /* buffer for resulting string */
  
      do_backslash = (vim_strchr(p_cpo, CPO_BSLASH) == NULL);
!     do_special = (vim_strchr(p_cpo, CPO_SPECI) == NULL)
!                                                 || (flags & REPTERM_SPECIAL);
      do_key_code = (vim_strchr(p_cpo, CPO_KEYCODE) == NULL);
  
      /*
***************
*** 5383,5389 ****
      /*
       * Check for #n at start only: function key n
       */
!     if (from_part && src[0] == '#' && VIM_ISDIGIT(src[1]))  /* function key */
      {
        result[dlen++] = K_SPECIAL;
        result[dlen++] = 'k';
--- 5400,5406 ----
      /*
       * Check for #n at start only: function key n
       */
!     if ((flags & REPTERM_FROM_PART) && src[0] == '#' && VIM_ISDIGIT(src[1]))
      {
        result[dlen++] = K_SPECIAL;
        result[dlen++] = 'k';
***************
*** 5403,5409 ****
         * If 'cpoptions' does not contain '<', check for special key codes,
         * like "<C-S-LeftMouse>"
         */
!       if (do_special && (do_lt || STRNCMP(src, "<lt>", 4) != 0))
        {
  #ifdef FEAT_EVAL
            /*
--- 5420,5427 ----
         * If 'cpoptions' does not contain '<', check for special key codes,
         * like "<C-S-LeftMouse>"
         */
!       if (do_special && ((flags & REPTERM_DO_LT)
!                                             || STRNCMP(src, "<lt>", 4) != 0))
        {
  #ifdef FEAT_EVAL
            /*
***************
*** 5429,5435 ****
            }
  #endif
  
!           slen = trans_special(&src, result + dlen, TRUE, FALSE);
            if (slen)
            {
                dlen += slen;
--- 5447,5454 ----
            }
  #endif
  
!           slen = trans_special(&src, result + dlen, TRUE, FALSE,
!                            (flags & REPTERM_NO_SIMPLIFY) == 0, did_simplify);
            if (slen)
            {
                dlen += slen;
***************
*** 5509,5515 ****
            ++src;                              /* skip CTRL-V or backslash */
            if (*src == NUL)
            {
!               if (from_part)
                    result[dlen++] = key;
                break;
            }
--- 5528,5534 ----
            ++src;                              /* skip CTRL-V or backslash */
            if (*src == NUL)
            {
!               if (flags & REPTERM_FROM_PART)
                    result[dlen++] = key;
                break;
            }
*** ../vim-8.1.2144/src/eval.c  2019-10-06 22:00:08.293244132 +0200
--- src/eval.c  2019-10-12 22:54:09.036941168 +0200
***************
*** 3526,3532 ****
                          break;
  
                            /* Special key, e.g.: "\<C-W>" */
!               case '<': extra = trans_special(&p, name, TRUE, TRUE);
                          if (extra != 0)
                          {
                              name += extra;
--- 3526,3533 ----
                          break;
  
                            /* Special key, e.g.: "\<C-W>" */
!               case '<': extra = trans_special(&p, name, TRUE, TRUE,
!                                                                  TRUE, NULL);
                          if (extra != 0)
                          {
                              name += extra;
*** ../vim-8.1.2144/src/getchar.c       2019-10-10 21:49:24.974264458 +0200
--- src/getchar.c       2019-10-13 16:30:20.398643743 +0200
***************
*** 52,58 ****
   */
  static int    block_redo = FALSE;
  
! static int            KeyNoremap = 0;     /* remapping flags */
  
  /*
   * Variables used by vgetorpeek() and flush_buffers().
--- 52,58 ----
   */
  static int    block_redo = FALSE;
  
! static int    KeyNoremap = 0;     // remapping flags
  
  /*
   * Variables used by vgetorpeek() and flush_buffers().
***************
*** 1771,1777 ****
            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 <= '_')))
--- 1771,1777 ----
            if (!no_reduce_keys)
            {
                // A modifier was not used for a mapping, apply it to ASCII
!               // keys.  Shift would already have been applied.
                if ((mod_mask & MOD_MASK_CTRL)
                        && ((c >= '`' && c <= 0x7f)
                            || (c >= '@' && c <= '_')))
***************
*** 2240,2245 ****
--- 2240,2246 ----
            // Skip ":lmap" mappings if keys were mapped.
            if (mp->m_keys[0] == tb_c1
                    && (mp->m_mode & local_State)
+                   && !(mp->m_simplified && seenModifyOtherKeys)
                    && ((mp->m_mode & LANGMAP) == 0 || typebuf.tb_maplen == 0))
            {
  #ifdef FEAT_LANGMAP
*** ../vim-8.1.2144/src/globals.h       2019-10-10 21:13:59.962360351 +0200
--- src/globals.h       2019-10-12 21:30:03.017623342 +0200
***************
*** 1002,1007 ****
--- 1002,1011 ----
  EXTERN int reg_recording INIT(= 0);   // register for recording  or zero
  EXTERN int reg_executing INIT(= 0);   // register being executed or zero
  
+ // Set when a modifyOtherKeys sequence was seen, then simplified mappings will
+ // no longer be used.
+ EXTERN int seenModifyOtherKeys INIT(= FALSE);
+ 
  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
*** ../vim-8.1.2144/src/gui_mac.c       2019-06-14 21:36:51.014437500 +0200
--- src/gui_mac.c       2019-10-12 22:52:04.457341368 +0200
***************
*** 2177,2183 ****
            key_char = simplify_key(key_char, (int *)&vimModifiers);
  
            /* Interpret META, include SHIFT, etc. */
!           key_char = extract_modifiers(key_char, (int *)&vimModifiers);
            if (key_char == CSI)
                key_char = K_CSI;
  
--- 2177,2184 ----
            key_char = simplify_key(key_char, (int *)&vimModifiers);
  
            /* Interpret META, include SHIFT, etc. */
!           key_char = extract_modifiers(key_char, (int *)&vimModifiers,
!                   TRUE, NULL);
            if (key_char == CSI)
                key_char = K_CSI;
  
***************
*** 4772,4778 ****
        char_u      *p_actext;
  
        p_actext = menu->actext;
!       key = find_special_key(&p_actext, &modifiers, FALSE, FALSE, FALSE);
        if (*p_actext != 0)
            key = 0; /* error: trailing text */
        /* find_special_key() returns a keycode with as many of the
--- 4773,4780 ----
        char_u      *p_actext;
  
        p_actext = menu->actext;
!       key = find_special_key(&p_actext, &modifiers, FALSE, FALSE, FALSE,
!                                                                  TRUE, NULL);
        if (*p_actext != 0)
            key = 0; /* error: trailing text */
        /* find_special_key() returns a keycode with as many of the
*** ../vim-8.1.2144/src/gui_w32.c       2019-09-21 23:09:00.975830710 +0200
--- src/gui_w32.c       2019-10-12 22:50:19.669659794 +0200
***************
*** 850,856 ****
        modifiers &= ~MOD_MASK_SHIFT;
  
      /* Interpret the ALT key as making the key META, include SHIFT, etc. */
!     ch = extract_modifiers(ch, &modifiers);
      if (ch == CSI)
        ch = K_CSI;
  
--- 850,856 ----
        modifiers &= ~MOD_MASK_SHIFT;
  
      /* Interpret the ALT key as making the key META, include SHIFT, etc. */
!     ch = extract_modifiers(ch, &modifiers, TRUE, NULL);
      if (ch == CSI)
        ch = K_CSI;
  
*** ../vim-8.1.2144/src/highlight.c     2019-10-06 22:00:08.297244105 +0200
--- src/highlight.c     2019-10-12 22:54:29.120874876 +0200
***************
*** 1417,1423 ****
                 */
                for (p = arg, off = 0; off < 100 - 6 && *p; )
                {
!                   len = trans_special(&p, buf + off, FALSE, FALSE);
                    if (len > 0)            // recognized special char
                        off += len;
                    else                    // copy as normal char
--- 1417,1424 ----
                 */
                for (p = arg, off = 0; off < 100 - 6 && *p; )
                {
!                   len = trans_special(&p, buf + off, FALSE, FALSE,
!                                                                  TRUE, NULL);
                    if (len > 0)            // recognized special char
                        off += len;
                    else                    // copy as normal char
*** ../vim-8.1.2144/src/if_ole.cpp      2019-05-25 20:21:24.677951017 +0200
--- src/if_ole.cpp      2019-10-12 21:53:01.919597212 +0200
***************
*** 330,336 ****
      }
  
      /* Translate key codes like <Esc> */
!     str = replace_termcodes((char_u *)buffer, &ptr, FALSE, TRUE, FALSE);
  
      /* If ptr was set, then a new buffer was allocated,
       * so we can free the old one.
--- 330,336 ----
      }
  
      /* Translate key codes like <Esc> */
!     str = replace_termcodes((char_u *)buffer, &ptr, REPTERM_DO_LT, NULL);
  
      /* If ptr was set, then a new buffer was allocated,
       * so we can free the old one.
*** ../vim-8.1.2144/src/main.c  2019-09-25 21:43:07.275251603 +0200
--- src/main.c  2019-10-12 21:46:49.873275123 +0200
***************
*** 4339,4345 ****
       *  <lt> sequence is recognised - needed for a real backslash.
       */
      p_cpo = (char_u *)"Bk";
!     str = replace_termcodes((char_u *)str, &ptr, FALSE, TRUE, FALSE);
      p_cpo = cpo_save;
  
      if (*ptr != NUL)  /* trailing CTRL-V results in nothing */
--- 4339,4345 ----
       *  <lt> sequence is recognised - needed for a real backslash.
       */
      p_cpo = (char_u *)"Bk";
!     str = replace_termcodes((char_u *)str, &ptr, REPTERM_DO_LT, NULL);
      p_cpo = cpo_save;
  
      if (*ptr != NUL)  /* trailing CTRL-V results in nothing */
*** ../vim-8.1.2144/src/map.c   2019-09-03 22:08:13.673035035 +0200
--- src/map.c   2019-10-13 15:33:19.963928416 +0200
***************
*** 256,273 ****
      char_u    *p;
      int               n;
      int               len = 0;        // init for GCC
-     char_u    *newstr;
      int               hasarg;
      int               haskey;
!     int               did_it = FALSE;
!     int               did_local = FALSE;
!     int               round;
      char_u    *keys_buf = NULL;
      char_u    *arg_buf = NULL;
      int               retval = 0;
      int               do_backslash;
-     int               hash;
-     int               new_hash;
      mapblock_T        **abbr_table;
      mapblock_T        **map_table;
      int               unique = FALSE;
--- 256,270 ----
      char_u    *p;
      int               n;
      int               len = 0;        // init for GCC
      int               hasarg;
      int               haskey;
!     int               do_print;
!     int               keyround;
      char_u    *keys_buf = NULL;
+     char_u    *alt_keys_buf = NULL;
      char_u    *arg_buf = NULL;
      int               retval = 0;
      int               do_backslash;
      mapblock_T        **abbr_table;
      mapblock_T        **map_table;
      int               unique = FALSE;
***************
*** 277,282 ****
--- 274,280 ----
  #ifdef FEAT_EVAL
      int               expr = FALSE;
  #endif
+     int               did_simplify = FALSE;
      int               noremap;
      char_u      *orig_rhs;
  
***************
*** 375,380 ****
--- 373,379 ----
      rhs = p;
      hasarg = (*rhs != NUL);
      haskey = (*keys != NUL);
+     do_print = !haskey || (maptype != 1 && !hasarg);
  
      // check for :unmap without argument
      if (maptype == 1 && !haskey)
***************
*** 389,761 ****
      // replace_termcodes() may move the result to allocated memory, which
      // needs to be freed later (*keys_buf and *arg_buf).
      // replace_termcodes() also removes CTRL-Vs and sometimes backslashes.
      if (haskey)
!       keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, special);
      orig_rhs = rhs;
      if (hasarg)
      {
        if (STRICMP(rhs, "<nop>") == 0)     // "<Nop>" means nothing
            rhs = (char_u *)"";
        else
!           rhs = replace_termcodes(rhs, &arg_buf, FALSE, TRUE, special);
      }
  
!     // check arguments and translate function keys
!     if (haskey)
      {
!       len = (int)STRLEN(keys);
!       if (len > MAXMAPLEN)            // maximum length of MAXMAPLEN chars
        {
!           retval = 1;
!           goto theend;
        }
  
!       if (abbrev && maptype != 1)
        {
!           // If an abbreviation ends in a keyword character, the
!           // rest must be all keyword-char or all non-keyword-char.
!           // Otherwise we won't be able to find the start of it in a
!           // vi-compatible way.
!           if (has_mbyte)
            {
!               int     first, last;
!               int     same = -1;
  
!               first = vim_iswordp(keys);
!               last = first;
!               p = keys + (*mb_ptr2len)(keys);
!               n = 1;
!               while (p < keys + len)
!               {
!                   ++n;                        // nr of (multi-byte) chars
!                   last = vim_iswordp(p);      // type of last char
!                   if (same == -1 && last != first)
!                       same = n - 1;           // count of same char type
!                   p += (*mb_ptr2len)(p);
!               }
!               if (last && n > 2 && same >= 0 && same < n - 1)
                {
!                   retval = 1;
!                   goto theend;
                }
!           }
!           else if (vim_iswordc(keys[len - 1]))  // ends in keyword char
                    for (n = 0; n < len - 2; ++n)
                        if (vim_iswordc(keys[n]) != vim_iswordc(keys[len - 2]))
                        {
                            retval = 1;
                            goto theend;
                        }
!           // An abbreviation cannot contain white space.
!           for (n = 0; n < len; ++n)
!               if (VIM_ISWHITE(keys[n]))
!               {
!                   retval = 1;
!                   goto theend;
!               }
        }
-     }
  
!     if (haskey && hasarg && abbrev)   // if we will add an abbreviation
!       no_abbr = FALSE;                // reset flag that indicates there are
                                        // no abbreviations
  
!     if (!haskey || (maptype != 1 && !hasarg))
!       msg_start();
  
!     // Check if a new local mapping wasn't already defined globally.
!     if (map_table == curbuf->b_maphash && haskey && hasarg && maptype != 1)
!     {
!       // need to loop over all global hash lists
!       for (hash = 0; hash < 256 && !got_int; ++hash)
        {
!           if (abbrev)
!           {
!               if (hash != 0)  // there is only one abbreviation list
!                   break;
!               mp = first_abbr;
!           }
!           else
!               mp = maphash[hash];
!           for ( ; mp != NULL && !got_int; mp = mp->m_next)
            {
!               // check entries with the same mode
!               if ((mp->m_mode & mode) != 0
!                       && mp->m_keylen == len
!                       && unique
!                       && STRNCMP(mp->m_keys, keys, (size_t)len) == 0)
                {
!                   if (abbrev)
!                       semsg(_("E224: global abbreviation already exists for 
%s"),
!                               mp->m_keys);
!                   else
!                       semsg(_("E225: global mapping already exists for %s"),
!                               mp->m_keys);
!                   retval = 5;
!                   goto theend;
                }
            }
        }
-     }
  
!     // When listing global mappings, also list buffer-local ones here.
!     if (map_table != curbuf->b_maphash && !hasarg && maptype != 1)
!     {
!       // need to loop over all global hash lists
!       for (hash = 0; hash < 256 && !got_int; ++hash)
        {
!           if (abbrev)
!           {
!               if (hash != 0)  // there is only one abbreviation list
!                   break;
!               mp = curbuf->b_first_abbr;
!           }
!           else
!               mp = curbuf->b_maphash[hash];
!           for ( ; mp != NULL && !got_int; mp = mp->m_next)
            {
!               // check entries with the same mode
!               if ((mp->m_mode & mode) != 0)
                {
!                   if (!haskey)                    // show all entries
!                   {
!                       showmap(mp, TRUE);
!                       did_local = TRUE;
!                   }
!                   else
                    {
!                       n = mp->m_keylen;
!                       if (STRNCMP(mp->m_keys, keys,
!                                           (size_t)(n < len ? n : len)) == 0)
                        {
                            showmap(mp, TRUE);
                            did_local = TRUE;
                        }
                    }
                }
            }
        }
-     }
  
!     // Find an entry in the maphash[] list that matches.
!     // For :unmap we may loop two times: once to try to unmap an entry with a
!     // matching 'from' part, a second time, if the first fails, to unmap an
!     // entry with a matching 'to' part. This was done to allow ":ab foo bar"
!     // to be unmapped by typing ":unab foo", where "foo" will be replaced by
!     // "bar" because of the abbreviation.
!     for (round = 0; (round == 0 || maptype == 1) && round <= 1
!                                             && !did_it && !got_int; ++round)
!     {
!       // need to loop over all hash lists
!       for (hash = 0; hash < 256 && !got_int; ++hash)
        {
!           if (abbrev)
!           {
!               if (hash > 0)   // there is only one abbreviation list
!                   break;
!               mpp = abbr_table;
!           }
!           else
!               mpp = &(map_table[hash]);
!           for (mp = *mpp; mp != NULL && !got_int; mp = *mpp)
            {
! 
!               if (!(mp->m_mode & mode))   // skip entries with wrong mode
!               {
!                   mpp = &(mp->m_next);
!                   continue;
!               }
!               if (!haskey)                // show all entries
                {
!                   showmap(mp, map_table != maphash);
!                   did_it = TRUE;
                }
!               else                        // do we have a match?
                {
!                   if (round)      // second round: Try unmap "rhs" string
                    {
!                       n = (int)STRLEN(mp->m_str);
!                       p = mp->m_str;
                    }
!                   else
                    {
!                       n = mp->m_keylen;
!                       p = mp->m_keys;
                    }
!                   if (STRNCMP(p, keys, (size_t)(n < len ? n : len)) == 0)
                    {
!                       if (maptype == 1)       // delete entry
                        {
!                           // Only accept a full match.  For abbreviations we
!                           // ignore trailing space when matching with the
!                           // "lhs", since an abbreviation can't have
!                           // trailing space.
!                           if (n != len && (!abbrev || round || n > len
                                               || *skipwhite(keys + n) != NUL))
                            {
                                mpp = &(mp->m_next);
                                continue;
                            }
!                           // We reset the indicated mode bits. If nothing is
!                           // left the entry is deleted below.
!                           mp->m_mode &= ~mode;
!                           did_it = TRUE;      // remember we did something
!                       }
!                       else if (!hasarg)       // show matching entry
!                       {
!                           showmap(mp, map_table != maphash);
!                           did_it = TRUE;
!                       }
!                       else if (n != len)      // new entry is ambiguous
!                       {
!                           mpp = &(mp->m_next);
!                           continue;
!                       }
!                       else if (unique)
!                       {
!                           if (abbrev)
!                               semsg(_("E226: abbreviation already exists for 
%s"),
!                                                                          p);
                            else
-                               semsg(_("E227: mapping already exists for %s"), 
p);
-                           retval = 5;
-                           goto theend;
-                       }
-                       else                    // new rhs for existing entry
-                       {
-                           mp->m_mode &= ~mode;        // remove mode bits
-                           if (mp->m_mode == 0 && !did_it) // reuse entry
                            {
!                               newstr = vim_strsave(rhs);
!                               if (newstr == NULL)
                                {
!                                   retval = 4;         // no mem
!                                   goto theend;
!                               }
!                               vim_free(mp->m_str);
!                               mp->m_str = newstr;
!                               vim_free(mp->m_orig_str);
!                               mp->m_orig_str = vim_strsave(orig_rhs);
!                               mp->m_noremap = noremap;
!                               mp->m_nowait = nowait;
!                               mp->m_silent = silent;
!                               mp->m_mode = mode;
  #ifdef FEAT_EVAL
!                               mp->m_expr = expr;
!                               mp->m_script_ctx = current_sctx;
!                               mp->m_script_ctx.sc_lnum += sourcing_lnum;
  #endif
!                               did_it = TRUE;
                            }
-                       }
-                       if (mp->m_mode == 0)    // entry can be deleted
-                       {
-                           map_free(mpp);
-                           continue;           // continue with *mpp
-                       }
  
!                       // May need to put this entry into another hash list.
!                       new_hash = MAP_HASH(mp->m_mode, mp->m_keys[0]);
!                       if (!abbrev && new_hash != hash)
!                       {
!                           *mpp = mp->m_next;
!                           mp->m_next = map_table[new_hash];
!                           map_table[new_hash] = mp;
  
!                           continue;           // continue with *mpp
                        }
                    }
                }
-               mpp = &(mp->m_next);
            }
        }
-     }
  
!     if (maptype == 1)                     // delete entry
!     {
!       if (!did_it)
!           retval = 2;                     // no match
!       else if (*keys == Ctrl_C)
        {
!           // If CTRL-C has been unmapped, reuse it for Interrupting.
!           if (map_table == curbuf->b_maphash)
!               curbuf->b_mapped_ctrl_c &= ~mode;
!           else
!               mapped_ctrl_c &= ~mode;
        }
-       goto theend;
-     }
  
!     if (!haskey || !hasarg)               // print entries
!     {
!       if (!did_it && !did_local)
        {
!           if (abbrev)
!               msg(_("No abbreviation found"));
!           else
!               msg(_("No mapping found"));
        }
-       goto theend;                        // listing finished
-     }
  
!     if (did_it)                       // have added the new entry already
!       goto theend;
  
!     // Get here when adding a new entry to the maphash[] list or abbrlist.
!     mp = ALLOC_ONE(mapblock_T);
!     if (mp == NULL)
!     {
!       retval = 4;         // no mem
!       goto theend;
!     }
  
!     // If CTRL-C has been mapped, don't always use it for Interrupting.
!     if (*keys == Ctrl_C)
!     {
!       if (map_table == curbuf->b_maphash)
!           curbuf->b_mapped_ctrl_c |= mode;
!       else
!           mapped_ctrl_c |= mode;
!     }
  
!     mp->m_keys = vim_strsave(keys);
!     mp->m_str = vim_strsave(rhs);
!     mp->m_orig_str = vim_strsave(orig_rhs);
!     if (mp->m_keys == NULL || mp->m_str == NULL)
!     {
!       vim_free(mp->m_keys);
!       vim_free(mp->m_str);
!       vim_free(mp->m_orig_str);
!       vim_free(mp);
!       retval = 4;     // no mem
!       goto theend;
!     }
!     mp->m_keylen = (int)STRLEN(mp->m_keys);
!     mp->m_noremap = noremap;
!     mp->m_nowait = nowait;
!     mp->m_silent = silent;
!     mp->m_mode = mode;
  #ifdef FEAT_EVAL
!     mp->m_expr = expr;
!     mp->m_script_ctx = current_sctx;
!     mp->m_script_ctx.sc_lnum += sourcing_lnum;
  #endif
  
!     // add the new entry in front of the abbrlist or maphash[] list
!     if (abbrev)
!     {
!       mp->m_next = *abbr_table;
!       *abbr_table = mp;
!     }
!     else
!     {
!       n = MAP_HASH(mp->m_mode, mp->m_keys[0]);
!       mp->m_next = map_table[n];
!       map_table[n] = mp;
      }
  
  theend:
      vim_free(keys_buf);
      vim_free(arg_buf);
      return retval;
  }
--- 388,814 ----
      // replace_termcodes() may move the result to allocated memory, which
      // needs to be freed later (*keys_buf and *arg_buf).
      // replace_termcodes() also removes CTRL-Vs and sometimes backslashes.
+     // If something like <C-H> is simplified to 0x08 then mark it as 
simplified
+     // and also add a n entry with a modifier, which will work when
+     // modifyOtherKeys is working.
      if (haskey)
!     {
!       char_u  *new_keys;
!       int     flags = REPTERM_FROM_PART | REPTERM_DO_LT;
! 
!       if (special)
!           flags |= REPTERM_SPECIAL;
!       new_keys = replace_termcodes(keys, &keys_buf, flags, &did_simplify);
!       if (did_simplify)
!           (void)replace_termcodes(keys, &alt_keys_buf,
!                                           flags | REPTERM_NO_SIMPLIFY, NULL);
!       keys = new_keys;
!     }
      orig_rhs = rhs;
      if (hasarg)
      {
        if (STRICMP(rhs, "<nop>") == 0)     // "<Nop>" means nothing
            rhs = (char_u *)"";
        else
!           rhs = replace_termcodes(rhs, &arg_buf,
!                       REPTERM_DO_LT | (special ? REPTERM_SPECIAL : 0), NULL);
      }
  
!     /*
!      * The following is done twice if we have two versions of keys:
!      * "alt_keys_buf" is not NULL.
!      */
!     for (keyround = 1; keyround <= 2; ++keyround)
      {
!       int     did_it = FALSE;
!       int     did_local = FALSE;
!       int     round;
!       int     hash;
!       int     new_hash;
! 
!       if (keyround == 2)
        {
!           if (alt_keys_buf == NULL)
!               break;
!           keys = alt_keys_buf;
        }
+       else if (alt_keys_buf != NULL && do_print)
+           // when printing always use the not-simplified map
+           keys = alt_keys_buf;
  
!       // check arguments and translate function keys
!       if (haskey)
        {
!           len = (int)STRLEN(keys);
!           if (len > MAXMAPLEN)        // maximum length of MAXMAPLEN chars
            {
!               retval = 1;
!               goto theend;
!           }
  
!           if (abbrev && maptype != 1)
!           {
!               // If an abbreviation ends in a keyword character, the
!               // rest must be all keyword-char or all non-keyword-char.
!               // Otherwise we won't be able to find the start of it in a
!               // vi-compatible way.
!               if (has_mbyte)
                {
!                   int first, last;
!                   int same = -1;
! 
!                   first = vim_iswordp(keys);
!                   last = first;
!                   p = keys + (*mb_ptr2len)(keys);
!                   n = 1;
!                   while (p < keys + len)
!                   {
!                       ++n;                    // nr of (multi-byte) chars
!                       last = vim_iswordp(p);  // type of last char
!                       if (same == -1 && last != first)
!                           same = n - 1;       // count of same char type
!                       p += (*mb_ptr2len)(p);
!                   }
!                   if (last && n > 2 && same >= 0 && same < n - 1)
!                   {
!                       retval = 1;
!                       goto theend;
!                   }
                }
!               else if (vim_iswordc(keys[len - 1]))
!                   // ends in keyword char
                    for (n = 0; n < len - 2; ++n)
                        if (vim_iswordc(keys[n]) != vim_iswordc(keys[len - 2]))
                        {
                            retval = 1;
                            goto theend;
                        }
!               // An abbreviation cannot contain white space.
!               for (n = 0; n < len; ++n)
!                   if (VIM_ISWHITE(keys[n]))
!                   {
!                       retval = 1;
!                       goto theend;
!                   }
!           }
        }
  
!       if (haskey && hasarg && abbrev) // if we will add an abbreviation
!           no_abbr = FALSE;            // reset flag that indicates there are
                                        // no abbreviations
  
!       if (do_print)
!           msg_start();
  
!       // Check if a new local mapping wasn't already defined globally.
!       if (map_table == curbuf->b_maphash && haskey && hasarg && maptype != 1)
        {
!           // need to loop over all global hash lists
!           for (hash = 0; hash < 256 && !got_int; ++hash)
            {
!               if (abbrev)
                {
!                   if (hash != 0)      // there is only one abbreviation list
!                       break;
!                   mp = first_abbr;
!               }
!               else
!                   mp = maphash[hash];
!               for ( ; mp != NULL && !got_int; mp = mp->m_next)
!               {
!                   // check entries with the same mode
!                   if ((mp->m_mode & mode) != 0
!                           && mp->m_keylen == len
!                           && unique
!                           && STRNCMP(mp->m_keys, keys, (size_t)len) == 0)
!                   {
!                       if (abbrev)
!                           semsg(_(
!                           "E224: global abbreviation already exists for %s"),
!                                   mp->m_keys);
!                       else
!                           semsg(_(
!                                "E225: global mapping already exists for %s"),
!                                   mp->m_keys);
!                       retval = 5;
!                       goto theend;
!                   }
                }
            }
        }
  
!       // When listing global mappings, also list buffer-local ones here.
!       if (map_table != curbuf->b_maphash && !hasarg && maptype != 1)
        {
!           // need to loop over all global hash lists
!           for (hash = 0; hash < 256 && !got_int; ++hash)
            {
!               if (abbrev)
                {
!                   if (hash != 0)      // there is only one abbreviation list
!                       break;
!                   mp = curbuf->b_first_abbr;
!               }
!               else
!                   mp = curbuf->b_maphash[hash];
!               for ( ; mp != NULL && !got_int; mp = mp->m_next)
!               {
!                   // check entries with the same mode
!                   if ((mp->m_mode & mode) != 0)
                    {
!                       if (!haskey)                // show all entries
                        {
                            showmap(mp, TRUE);
                            did_local = TRUE;
                        }
+                       else
+                       {
+                           n = mp->m_keylen;
+                           if (STRNCMP(mp->m_keys, keys,
+                                            (size_t)(n < len ? n : len)) == 0)
+                           {
+                               showmap(mp, TRUE);
+                               did_local = TRUE;
+                           }
+                       }
                    }
                }
            }
        }
  
!       // Find an entry in the maphash[] list that matches.
!       // For :unmap we may loop two times: once to try to unmap an entry with
!       // a matching 'from' part, a second time, if the first fails, to unmap
!       // an entry with a matching 'to' part. This was done to allow ":ab foo
!       // bar" to be unmapped by typing ":unab foo", where "foo" will be
!       // replaced by "bar" because of the abbreviation.
!       for (round = 0; (round == 0 || maptype == 1) && round <= 1
!                                              && !did_it && !got_int; ++round)
        {
!           // need to loop over all hash lists
!           for (hash = 0; hash < 256 && !got_int; ++hash)
            {
!               if (abbrev)
                {
!                   if (hash > 0)       // there is only one abbreviation list
!                       break;
!                   mpp = abbr_table;
                }
!               else
!                   mpp = &(map_table[hash]);
!               for (mp = *mpp; mp != NULL && !got_int; mp = *mpp)
                {
! 
!                   if (!(mp->m_mode & mode))   // skip entries with wrong mode
                    {
!                       mpp = &(mp->m_next);
!                       continue;
                    }
!                   if (!haskey)        // show all entries
                    {
!                       showmap(mp, map_table != maphash);
!                       did_it = TRUE;
                    }
!                   else        // do we have a match?
                    {
!                       if (round)      // second round: Try unmap "rhs" string
                        {
!                           n = (int)STRLEN(mp->m_str);
!                           p = mp->m_str;
!                       }
!                       else
!                       {
!                           n = mp->m_keylen;
!                           p = mp->m_keys;
!                       }
!                       if (STRNCMP(p, keys, (size_t)(n < len ? n : len)) == 0)
!                       {
!                           if (maptype == 1)
!                           {
!                               // Delete entry.
!                               // Only accept a full match.  For abbreviations
!                               // we ignore trailing space when matching with
!                               // the "lhs", since an abbreviation can't have
!                               // trailing space.
!                               if (n != len && (!abbrev || round || n > len
                                               || *skipwhite(keys + n) != NUL))
+                               {
+                                   mpp = &(mp->m_next);
+                                   continue;
+                               }
+                               // We reset the indicated mode bits. If nothing
+                               // is left the entry is deleted below.
+                               mp->m_mode &= ~mode;
+                               did_it = TRUE;  // remember we did something
+                           }
+                           else if (!hasarg)   // show matching entry
+                           {
+                               showmap(mp, map_table != maphash);
+                               did_it = TRUE;
+                           }
+                           else if (n != len)  // new entry is ambiguous
                            {
                                mpp = &(mp->m_next);
                                continue;
                            }
!                           else if (unique)
!                           {
!                               if (abbrev)
!                                   semsg(_(
!                                  "E226: abbreviation already exists for %s"),
!                                           p);
!                               else
!                                   semsg(_(
!                                       "E227: mapping already exists for %s"),
!                                           p);
!                               retval = 5;
!                               goto theend;
!                           }
                            else
                            {
!                               // new rhs for existing entry
!                               mp->m_mode &= ~mode;    // remove mode bits
!                               if (mp->m_mode == 0 && !did_it) // reuse entry
                                {
!                                   char_u *newstr = vim_strsave(rhs);
! 
!                                   if (newstr == NULL)
!                                   {
!                                       retval = 4;             // no mem
!                                       goto theend;
!                                   }
!                                   vim_free(mp->m_str);
!                                   mp->m_str = newstr;
!                                   vim_free(mp->m_orig_str);
!                                   mp->m_orig_str = vim_strsave(orig_rhs);
!                                   mp->m_noremap = noremap;
!                                   mp->m_nowait = nowait;
!                                   mp->m_silent = silent;
!                                   mp->m_mode = mode;
!                                   mp->m_simplified =
!                                                did_simplify && keyround == 1;
  #ifdef FEAT_EVAL
!                                   mp->m_expr = expr;
!                                   mp->m_script_ctx = current_sctx;
!                                   mp->m_script_ctx.sc_lnum += sourcing_lnum;
  #endif
!                                   did_it = TRUE;
!                               }
!                           }
!                           if (mp->m_mode == 0)  // entry can be deleted
!                           {
!                               map_free(mpp);
!                               continue;       // continue with *mpp
                            }
  
!                           // May need to put this entry into another hash
!                           // list.
!                           new_hash = MAP_HASH(mp->m_mode, mp->m_keys[0]);
!                           if (!abbrev && new_hash != hash)
!                           {
!                               *mpp = mp->m_next;
!                               mp->m_next = map_table[new_hash];
!                               map_table[new_hash] = mp;
  
!                               continue;       // continue with *mpp
!                           }
                        }
                    }
+                   mpp = &(mp->m_next);
                }
            }
        }
  
!       if (maptype == 1)
        {
!           // delete entry
!           if (!did_it)
!               retval = 2;     // no match
!           else if (*keys == Ctrl_C)
!           {
!               // If CTRL-C has been unmapped, reuse it for Interrupting.
!               if (map_table == curbuf->b_maphash)
!                   curbuf->b_mapped_ctrl_c &= ~mode;
!               else
!                   mapped_ctrl_c &= ~mode;
!           }
!           continue;
        }
  
!       if (!haskey || !hasarg)
        {
!           // print entries
!           if (!did_it && !did_local)
!           {
!               if (abbrev)
!                   msg(_("No abbreviation found"));
!               else
!                   msg(_("No mapping found"));
!           }
!           goto theend;    // listing finished
        }
  
!       if (did_it)
!           continue;   // have added the new entry already
  
!       // Get here when adding a new entry to the maphash[] list or abbrlist.
!       mp = ALLOC_ONE(mapblock_T);
!       if (mp == NULL)
!       {
!           retval = 4;     // no mem
!           goto theend;
!       }
  
!       // If CTRL-C has been mapped, don't always use it for Interrupting.
!       if (*keys == Ctrl_C)
!       {
!           if (map_table == curbuf->b_maphash)
!               curbuf->b_mapped_ctrl_c |= mode;
!           else
!               mapped_ctrl_c |= mode;
!       }
  
!       mp->m_keys = vim_strsave(keys);
!       mp->m_str = vim_strsave(rhs);
!       mp->m_orig_str = vim_strsave(orig_rhs);
!       if (mp->m_keys == NULL || mp->m_str == NULL)
!       {
!           vim_free(mp->m_keys);
!           vim_free(mp->m_str);
!           vim_free(mp->m_orig_str);
!           vim_free(mp);
!           retval = 4; // no mem
!           goto theend;
!       }
!       mp->m_keylen = (int)STRLEN(mp->m_keys);
!       mp->m_noremap = noremap;
!       mp->m_nowait = nowait;
!       mp->m_silent = silent;
!       mp->m_mode = mode;
!       mp->m_simplified = did_simplify && keyround == 1;
  #ifdef FEAT_EVAL
!       mp->m_expr = expr;
!       mp->m_script_ctx = current_sctx;
!       mp->m_script_ctx.sc_lnum += sourcing_lnum;
  #endif
  
!       // add the new entry in front of the abbrlist or maphash[] list
!       if (abbrev)
!       {
!           mp->m_next = *abbr_table;
!           *abbr_table = mp;
!       }
!       else
!       {
!           n = MAP_HASH(mp->m_mode, mp->m_keys[0]);
!           mp->m_next = map_table[n];
!           map_table[n] = mp;
!       }
      }
  
  theend:
      vim_free(keys_buf);
+     vim_free(alt_keys_buf);
      vim_free(arg_buf);
      return retval;
  }
***************
*** 934,940 ****
      char_u    *buf;
      int               retval;
  
!     rhs = replace_termcodes(str, &buf, FALSE, TRUE, FALSE);
  
      retval = map_to_exists_mode(rhs, mode_str2flags(modechars), abbr);
      vim_free(buf);
--- 987,993 ----
      char_u    *buf;
      int               retval;
  
!     rhs = replace_termcodes(str, &buf, REPTERM_DO_LT, NULL);
  
      retval = map_to_exists_mode(rhs, mode_str2flags(modechars), abbr);
      vim_free(buf);
***************
*** 2036,2042 ****
  
      mode = get_map_mode(&which, 0);
  
!     keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
      rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
      vim_free(keys_buf);
  
--- 2089,2096 ----
  
      mode = get_map_mode(&which, 0);
  
!     keys = replace_termcodes(keys, &keys_buf,
!                                     REPTERM_FROM_PART | REPTERM_DO_LT, NULL);
      rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
      vim_free(keys_buf);
  
*** ../vim-8.1.2144/src/menu.c  2019-08-20 20:13:40.326821952 +0200
--- src/menu.c  2019-10-12 21:51:21.328038913 +0200
***************
*** 372,378 ****
        else if (modes & MENU_TIP_MODE)
            map_buf = NULL;     /* Menu tips are plain text. */
        else
!           map_to = replace_termcodes(map_to, &map_buf, FALSE, TRUE, special);
        menuarg.modes = modes;
  #ifdef FEAT_TOOLBAR
        menuarg.iconfile = icon;
--- 372,379 ----
        else if (modes & MENU_TIP_MODE)
            map_buf = NULL;     /* Menu tips are plain text. */
        else
!           map_to = replace_termcodes(map_to, &map_buf,
!                       REPTERM_DO_LT | (special ? REPTERM_SPECIAL : 0), NULL);
        menuarg.modes = modes;
  #ifdef FEAT_TOOLBAR
        menuarg.iconfile = icon;
*** ../vim-8.1.2144/src/misc2.c 2019-10-12 16:12:50.968492825 +0200
--- src/misc2.c 2019-10-13 15:57:54.153813986 +0200
***************
*** 2696,2707 ****
      char_u    **srcp,
      char_u    *dst,
      int               keycode,    // prefer key code, e.g. K_DEL instead of 
DEL
!     int               in_string)  // TRUE when inside a double quoted string
  {
      int               modifiers = 0;
      int               key;
  
!     key = find_special_key(srcp, &modifiers, keycode, FALSE, in_string);
      if (key == 0)
        return 0;
  
--- 2696,2710 ----
      char_u    **srcp,
      char_u    *dst,
      int               keycode,    // prefer key code, e.g. K_DEL instead of 
DEL
!     int               in_string,  // TRUE when inside a double quoted string
!     int               simplify,       // simplify <C-H> and <A-x>
!     int               *did_simplify)  // found <C-H> or <A-x>
  {
      int               modifiers = 0;
      int               key;
  
!     key = find_special_key(srcp, &modifiers, keycode, FALSE, in_string,
!                                                      simplify, did_simplify);
      if (key == 0)
        return 0;
  
***************
*** 2753,2761 ****
  find_special_key(
      char_u    **srcp,
      int               *modp,
!     int               keycode,     /* prefer key code, e.g. K_DEL instead of 
DEL */
!     int               keep_x_key,  /* don't translate xHome to Home key */
!     int               in_string)   /* TRUE in string, double quote is escaped 
*/
  {
      char_u    *last_dash;
      char_u    *end_of_name;
--- 2756,2766 ----
  find_special_key(
      char_u    **srcp,
      int               *modp,
!     int               keycode,        // prefer key code, e.g. K_DEL instead 
of DEL
!     int               keep_x_key,     // don't translate xHome to Home key
!     int               in_string,      // TRUE in string, double quote is 
escaped
!     int               simplify,       // simplify <C-H> and <A-x>
!     int               *did_simplify)  // found <C-H> or <A-x>
  {
      char_u    *last_dash;
      char_u    *end_of_name;
***************
*** 2835,2841 ****
                                                 && VIM_ISDIGIT(last_dash[6]))
            {
                /* <Char-123> or <Char-033> or <Char-0x33> */
!               vim_str2nr(last_dash + 6, NULL, &l, STR2NR_ALL, NULL, &n, 0, 
TRUE);
                if (l == 0)
                {
                    emsg(_(e_invarg));
--- 2840,2847 ----
                                                 && VIM_ISDIGIT(last_dash[6]))
            {
                /* <Char-123> or <Char-033> or <Char-0x33> */
!               vim_str2nr(last_dash + 6, NULL, &l, STR2NR_ALL, NULL,
!                                                                 &n, 0, TRUE);
                if (l == 0)
                {
                    emsg(_(e_invarg));
***************
*** 2885,2895 ****
                        key = DEL;
                }
  
!               /*
!                * Normal Key with modifier: Try to make a single byte code.
!                */
                if (!IS_SPECIAL(key))
!                   key = extract_modifiers(key, &modifiers);
  
                *modp = modifiers;
                *srcp = end_of_name;
--- 2891,2900 ----
                        key = DEL;
                }
  
!               // Normal Key with modifier: Try to make a single byte code.
                if (!IS_SPECIAL(key))
!                   key = extract_modifiers(key, &modifiers,
!                                                      simplify, did_simplify);
  
                *modp = modifiers;
                *srcp = end_of_name;
***************
*** 2903,2928 ****
  /*
   * Try to include modifiers in the key.
   * Changes "Shift-a" to 'A', "Alt-A" to 0xc0, etc.
   */
      int
! extract_modifiers(int key, int *modp)
  {
      int       modifiers = *modp;
  
  #ifdef MACOS_X
!     /* Command-key really special, no fancynest */
      if (!(modifiers & MOD_MASK_CMD))
  #endif
      if ((modifiers & MOD_MASK_SHIFT) && ASCII_ISALPHA(key))
      {
        key = TOUPPER_ASC(key);
!       modifiers &= ~MOD_MASK_SHIFT;
      }
!     if ((modifiers & MOD_MASK_CTRL)
  #ifdef EBCDIC
!           /* * TODO: EBCDIC Better use:
!            * && (Ctrl_chr(key) || key == '?')
!            * ???  */
            && strchr("?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_", key)
                                                       != NULL
  #else
--- 2908,2944 ----
  /*
   * Try to include modifiers in the key.
   * Changes "Shift-a" to 'A', "Alt-A" to 0xc0, etc.
+  * When "simplify" is FALSE don't do Ctrl and Alt.
+  * When "simplify" is TRUE and Ctrl or Alt is removed from modifiers set
+  * "did_simplify" when it's not NULL.
   */
      int
! extract_modifiers(int key, int *modp, int simplify, int *did_simplify)
  {
      int       modifiers = *modp;
  
  #ifdef MACOS_X
!     // Command-key really special, no fancynest
      if (!(modifiers & MOD_MASK_CMD))
  #endif
      if ((modifiers & MOD_MASK_SHIFT) && ASCII_ISALPHA(key))
      {
        key = TOUPPER_ASC(key);
!       // With <C-S-a> and <A-S-a> we keep the shift modifier.
!       // With <S-a> and <S-A> we don't keep the shift modifier.
!       if (simplify || modifiers == MOD_MASK_SHIFT)
!           modifiers &= ~MOD_MASK_SHIFT;
      }
! 
!     // <C-H> and <C-h> mean the same thing, always use "H"
!     if ((modifiers & MOD_MASK_CTRL) && ASCII_ISALPHA(key))
!       key = TOUPPER_ASC(key);
! 
!     if (simplify && (modifiers & MOD_MASK_CTRL)
  #ifdef EBCDIC
!           // TODO: EBCDIC Better use:
!           // && (Ctrl_chr(key) || key == '?')
!           // ???
            && strchr("?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_", key)
                                                       != NULL
  #else
***************
*** 2935,2950 ****
        /* <C-@> is <Nul> */
        if (key == 0)
            key = K_ZERO;
      }
  #ifdef MACOS_X
      /* Command-key really special, no fancynest */
      if (!(modifiers & MOD_MASK_CMD))
  #endif
!     if ((modifiers & MOD_MASK_ALT) && key < 0x80
            && !enc_dbcs)               // avoid creating a lead byte
      {
        key |= 0x80;
        modifiers &= ~MOD_MASK_ALT;     /* remove the META modifier */
      }
  
      *modp = modifiers;
--- 2951,2971 ----
        /* <C-@> is <Nul> */
        if (key == 0)
            key = K_ZERO;
+       if (did_simplify != NULL)
+           *did_simplify = TRUE;
      }
+ 
  #ifdef MACOS_X
      /* Command-key really special, no fancynest */
      if (!(modifiers & MOD_MASK_CMD))
  #endif
!     if (simplify && (modifiers & MOD_MASK_ALT) && key < 0x80
            && !enc_dbcs)               // avoid creating a lead byte
      {
        key |= 0x80;
        modifiers &= ~MOD_MASK_ALT;     /* remove the META modifier */
+       if (did_simplify != NULL)
+           *did_simplify = TRUE;
      }
  
      *modp = modifiers;
*** ../vim-8.1.2144/src/option.c        2019-10-05 21:35:12.228950931 +0200
--- src/option.c        2019-10-12 22:53:38.777040254 +0200
***************
*** 4495,4501 ****
      {
        --arg;                      /* put arg at the '<' */
        modifiers = 0;
!       key = find_special_key(&arg, &modifiers, TRUE, TRUE, FALSE);
        if (modifiers)              /* can't handle modifiers here */
            key = 0;
      }
--- 4495,4501 ----
      {
        --arg;                      /* put arg at the '<' */
        modifiers = 0;
!       key = find_special_key(&arg, &modifiers, TRUE, TRUE, FALSE, TRUE, NULL);
        if (modifiers)              /* can't handle modifiers here */
            key = 0;
      }
*** ../vim-8.1.2144/src/proto/misc2.pro 2019-09-21 20:46:14.728275744 +0200
--- src/proto/misc2.pro 2019-10-12 22:55:37.116647113 +0200
***************
*** 67,76 ****
  int simplify_key(int key, int *modifiers);
  int handle_x_keys(int key);
  char_u *get_special_key_name(int c, int modifiers);
! int trans_special(char_u **srcp, char_u *dst, int keycode, int in_string);
  int special_to_buf(int key, int modifiers, int keycode, char_u *dst);
! int find_special_key(char_u **srcp, int *modp, int keycode, int keep_x_key, 
int in_string);
! int extract_modifiers(int key, int *modp);
  int find_special_key_in_table(int c);
  int get_special_key_code(char_u *name);
  char_u *get_key_name(int i);
--- 67,76 ----
  int simplify_key(int key, int *modifiers);
  int handle_x_keys(int key);
  char_u *get_special_key_name(int c, int modifiers);
! int trans_special(char_u **srcp, char_u *dst, int keycode, int in_string, int 
simplify, int *did_simplify);
  int special_to_buf(int key, int modifiers, int keycode, char_u *dst);
! int find_special_key(char_u **srcp, int *modp, int keycode, int keep_x_key, 
int in_string, int simplify, int *did_simplify);
! int extract_modifiers(int key, int *modp, int simplify, int *did_simplify);
  int find_special_key_in_table(int c);
  int get_special_key_code(char_u *name);
  char_u *get_key_name(int i);
*** ../vim-8.1.2144/src/proto/term.pro  2019-09-23 21:16:51.387544361 +0200
--- src/proto/term.pro  2019-10-12 21:47:56.652964165 +0200
***************
*** 67,73 ****
  int check_termcode(int max_offset, char_u *buf, int bufsize, int *buflen);
  void term_get_fg_color(char_u *r, char_u *g, char_u *b);
  void term_get_bg_color(char_u *r, char_u *g, char_u *b);
! char_u *replace_termcodes(char_u *from, char_u **bufp, int from_part, int 
do_lt, int special);
  void show_termcodes(void);
  int show_one_termcode(char_u *name, char_u *code, int printit);
  char_u *translate_mapping(char_u *str);
--- 67,73 ----
  int check_termcode(int max_offset, char_u *buf, int bufsize, int *buflen);
  void term_get_fg_color(char_u *r, char_u *g, char_u *b);
  void term_get_bg_color(char_u *r, char_u *g, char_u *b);
! char_u *replace_termcodes(char_u *from, char_u **bufp, int flags, int 
*did_simplify);
  void show_termcodes(void);
  int show_one_termcode(char_u *name, char_u *code, int printit);
  char_u *translate_mapping(char_u *str);
*** ../vim-8.1.2144/src/testdir/test_termcodes.vim      2019-10-12 
18:22:46.957511288 +0200
--- src/testdir/test_termcodes.vim      2019-10-13 16:37:26.833546697 +0200
***************
*** 862,868 ****
  " The mode doesn't need to be enabled, the codes are always detected.
  func RunTest_modifyOtherKeys(func)
    new
!   set timeoutlen=20
  
    " Shift-X is send as 'X' with the shift modifier
    call feedkeys('a' .. a:func('X', 2) .. "\<Esc>", 'Lx!')
--- 862,868 ----
  " The mode doesn't need to be enabled, the codes are always detected.
  func RunTest_modifyOtherKeys(func)
    new
!   set timeoutlen=10
  
    " Shift-X is send as 'X' with the shift modifier
    call feedkeys('a' .. a:func('X', 2) .. "\<Esc>", 'Lx!')
***************
*** 902,912 ****
    set timeoutlen&
  endfunc
  
! func Test_modifyOtherKeys_CSI27()
    call RunTest_modifyOtherKeys(function('GetEscCodeCSI27'))
- endfunc
- 
- func Test_modifyOtherKeys_CSIu()
    call RunTest_modifyOtherKeys(function('GetEscCodeCSIu'))
  endfunc
  
--- 902,909 ----
    set timeoutlen&
  endfunc
  
! func Test_modifyOtherKeys_basic()
    call RunTest_modifyOtherKeys(function('GetEscCodeCSI27'))
    call RunTest_modifyOtherKeys(function('GetEscCodeCSIu'))
  endfunc
  
***************
*** 928,934 ****
  
  func RunTest_mapping_works_with_shift(func)
    new
!   set timeoutlen=20
  
    call RunTest_mapping_shift('@', a:func)
    call RunTest_mapping_shift('A', a:func)
--- 925,931 ----
  
  func RunTest_mapping_works_with_shift(func)
    new
!   set timeoutlen=10
  
    call RunTest_mapping_shift('@', a:func)
    call RunTest_mapping_shift('A', a:func)
***************
*** 944,950 ****
    set timeoutlen&
  endfunc
  
! func Test_mapping_works_with_shift()
    call RunTest_mapping_works_with_shift(function('GetEscCodeCSI27'))
    call RunTest_mapping_works_with_shift(function('GetEscCodeCSIu'))
  endfunc
--- 941,1028 ----
    set timeoutlen&
  endfunc
  
! func Test_mapping_works_with_shift_plain()
    call RunTest_mapping_works_with_shift(function('GetEscCodeCSI27'))
    call RunTest_mapping_works_with_shift(function('GetEscCodeCSIu'))
  endfunc
+ 
+ func RunTest_mapping_mods(map, key, func, code)
+   call setline(1, '')
+   exe 'inoremap ' .. a:map .. ' xyz'
+   call feedkeys('a' .. a:func(a:key, a:code) .. "\<Esc>", 'Lx!')
+   call assert_equal("xyz", getline(1))
+   exe 'iunmap ' .. a:map
+ endfunc
+ 
+ func RunTest_mapping_works_with_mods(func, mods, code)
+   new
+   set timeoutlen=10
+ 
+   if a:mods !~ 'S'
+     " Shift by itself has no effect
+     call RunTest_mapping_mods('<' .. a:mods .. '-@>', '@', a:func, a:code)
+   endif
+   call RunTest_mapping_mods('<' .. a:mods .. '-A>', 'A', a:func, a:code)
+   call RunTest_mapping_mods('<' .. a:mods .. '-Z>', 'Z', a:func, a:code)
+   if a:mods !~ 'S'
+     " with Shift code is always upper case
+     call RunTest_mapping_mods('<' .. a:mods .. '-a>', 'a', a:func, a:code)
+     call RunTest_mapping_mods('<' .. a:mods .. '-z>', 'z', a:func, a:code)
+   endif
+   if a:mods != 'A'
+     " with Alt code is not in upper case
+     call RunTest_mapping_mods('<' .. a:mods .. '-a>', 'A', a:func, a:code)
+     call RunTest_mapping_mods('<' .. a:mods .. '-z>', 'Z', a:func, a:code)
+   endif
+   call RunTest_mapping_mods('<' .. a:mods .. '-á>', 'á', a:func, a:code)
+   if a:mods !~ 'S'
+     " Shift by itself has no effect
+     call RunTest_mapping_mods('<' .. a:mods .. '-^>', '^', a:func, a:code)
+     call RunTest_mapping_mods('<' .. a:mods .. '-_>', '_', a:func, a:code)
+     call RunTest_mapping_mods('<' .. a:mods .. '-{>', '{', a:func, a:code)
+     call RunTest_mapping_mods('<' .. a:mods .. '-\|>', '|', a:func, a:code)
+     call RunTest_mapping_mods('<' .. a:mods .. '-}>', '}', a:func, a:code)
+     call RunTest_mapping_mods('<' .. a:mods .. '-~>', '~', a:func, a:code)
+   endif
+ 
+   bwipe!
+   set timeoutlen&
+ endfunc
+ 
+ func Test_mapping_works_with_shift()
+   call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'S', 2)
+   call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'S', 2)
+ endfunc
+   
+ func Test_mapping_works_with_ctrl()
+   call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C', 5)
+   call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C', 5)
+ endfunc
+ 
+ func Test_mapping_works_with_shift_ctrl()
+   call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C-S', 6)
+   call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C-S', 6)
+ endfunc
+ 
+ " Below we also test the "u" code with Alt, This works, but libvterm would not
+ " send the Alt key like this but by prefixing an Esc.
+   
+ func Test_mapping_works_with_alt()
+   call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'A', 3)
+   call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'A', 3)
+ endfunc
+ 
+ func Test_mapping_works_with_shift_alt()
+   call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'S-A', 4)
+   call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'S-A', 4)
+ endfunc
+ 
+ func Test_mapping_works_with_ctrl_alt()
+   call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C-A', 7)
+   call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C-A', 7)
+ endfunc
+ 
+ func Test_mapping_works_with_shift_ctrl_alt()
+   call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C-S-A', 
8)
+   call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C-S-A', 8)
+ endfunc
*** ../vim-8.1.2144/src/structs.h       2019-10-09 22:01:20.599438001 +0200
--- src/structs.h       2019-10-13 12:42:34.776055302 +0200
***************
*** 1172,1177 ****
--- 1172,1179 ----
      char_u    *m_orig_str;    // rhs as entered by the user
      int               m_keylen;       // strlen(m_keys)
      int               m_mode;         // valid mode
+     int               m_simplified;   // m_keys was simplified, do not use 
this map
+                               // if seenModifyOtherKeys is TRUE
      int               m_noremap;      // if non-zero no re-mapping for m_str
      char      m_silent;       // <silent> used, don't echo commands
      char      m_nowait;       // <nowait> used
*** ../vim-8.1.2144/src/terminal.c      2019-10-10 21:13:59.962360351 +0200
--- src/terminal.c      2019-10-13 13:46:43.253595570 +0200
***************
*** 772,778 ****
  
            p = skiptowhite(cmd);
            *p = NUL;
!           keys = replace_termcodes(ep + 1, &buf, TRUE, TRUE, TRUE);
            opt.jo_set2 |= JO2_EOF_CHARS;
            opt.jo_eof_chars = vim_strsave(keys);
            vim_free(buf);
--- 772,779 ----
  
            p = skiptowhite(cmd);
            *p = NUL;
!           keys = replace_termcodes(ep + 1, &buf,
!                   REPTERM_FROM_PART | REPTERM_DO_LT | REPTERM_SPECIAL, NULL);
            opt.jo_set2 |= JO2_EOF_CHARS;
            opt.jo_eof_chars = vim_strsave(keys);
            vim_free(buf);
***************
*** 1372,1378 ****
      }
  
      // add modifiers for the typed key
!     mod |= mod_mask;
  
      /*
       * Convert special keys to vterm keys:
--- 1373,1384 ----
      }
  
      // add modifiers for the typed key
!     if (mod_mask & MOD_MASK_SHIFT)
!       mod |= VTERM_MOD_SHIFT;
!     if (mod_mask & MOD_MASK_CTRL)
!       mod |= VTERM_MOD_CTRL;
!     if (mod_mask & (MOD_MASK_ALT | MOD_MASK_META))
!       mod |= VTERM_MOD_ALT;
  
      /*
       * Convert special keys to vterm keys:
*** ../vim-8.1.2144/src/usercmd.c       2019-08-18 22:25:54.669447972 +0200
--- src/usercmd.c       2019-10-12 21:52:36.699707297 +0200
***************
*** 868,874 ****
      char_u    *rep_buf = NULL;
      garray_T  *gap;
  
!     replace_termcodes(rep, &rep_buf, FALSE, FALSE, FALSE);
      if (rep_buf == NULL)
      {
        // Can't replace termcodes - try using the string as is
--- 868,874 ----
      char_u    *rep_buf = NULL;
      garray_T  *gap;
  
!     replace_termcodes(rep, &rep_buf, 0, NULL);
      if (rep_buf == NULL)
      {
        // Can't replace termcodes - try using the string as is
*** ../vim-8.1.2144/src/vim.h   2019-09-21 20:46:14.728275744 +0200
--- src/vim.h   2019-10-12 21:47:07.149194164 +0200
***************
*** 2633,2636 ****
--- 2633,2642 ----
  
  #define CLIP_ZINDEX 32000
  
+ // Flags for replace_termcodes()
+ #define REPTERM_FROM_PART     1
+ #define REPTERM_DO_LT         2
+ #define REPTERM_SPECIAL               4
+ #define REPTERM_NO_SIMPLIFY   8
+ 
  #endif // VIM__H
*** ../vim-8.1.2144/src/version.c       2019-10-12 21:08:37.006660412 +0200
--- src/version.c       2019-10-13 16:40:35.672957071 +0200
***************
*** 755,756 ****
--- 755,758 ----
  {   /* Add new patch number below this line */
+ /**/
+     2145,
  /**/

-- 
Kisses may last for as much as, but no more than, five minutes.
                [real standing law in Iowa, United States of America]

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/201910131444.x9DEiC6V027985%40masaka.moolenaar.net.

Raspunde prin e-mail lui