patch 8.2.0839: dropping modifier when putting a character back in typeahead

Problem:    Dropping modifier when putting a character back in typeahead.
Solution:   Add modifier to ins_char_typebuf(). (closes #6158)
diff --git a/src/getchar.c b/src/getchar.c
index e9eef25..312f3c1 100644
--- a/src/getchar.c
+++ b/src/getchar.c
@@ -1101,18 +1101,29 @@
  * the char.
  */
     void
-ins_char_typebuf(int c)
+ins_char_typebuf(int c, int modifier)
 {
-    char_u	buf[MB_MAXBYTES + 1];
-    if (IS_SPECIAL(c))
+    char_u	buf[MB_MAXBYTES + 4];
+    int		idx = 0;
+
+    if (modifier != 0)
     {
 	buf[0] = K_SPECIAL;
-	buf[1] = K_SECOND(c);
-	buf[2] = K_THIRD(c);
+	buf[1] = KS_MODIFIER;
+	buf[2] = modifier;
 	buf[3] = NUL;
+	idx = 3;
+    }
+    if (IS_SPECIAL(c))
+    {
+	buf[idx] = K_SPECIAL;
+	buf[idx + 1] = K_SECOND(c);
+	buf[idx + 2] = K_THIRD(c);
+	buf[idx + 3] = NUL;
+	idx += 3;
     }
     else
-	buf[(*mb_char2bytes)(c, buf)] = NUL;
+	buf[(*mb_char2bytes)(c, buf + idx) + idx] = NUL;
     (void)ins_typebuf(buf, KeyNoremap, 0, !KeyTyped, cmd_silent);
 }
 
@@ -1640,8 +1651,11 @@
     }
     else
     {
-	mod_mask = 0x0;
+	mod_mask = 0;
+	vgetc_mod_mask = 0;
+	vgetc_char = 0;
 	last_recorded_len = 0;
+
 	for (;;)		// this is done twice if there are modifiers
 	{
 	    int did_inc = FALSE;
@@ -1835,9 +1849,15 @@
 	    }
 
 	    if (!no_reduce_keys)
+	    {
 		// A modifier was not used for a mapping, apply it to ASCII
 		// keys.  Shift would already have been applied.
+		// Remember the character and mod_mask from before, in some
+		// cases they are put back in the typeahead buffer.
+		vgetc_mod_mask = mod_mask;
+		vgetc_char = c;
 		c = merge_modifyOtherKeys(c);
+	    }
 
 	    break;
 	}
@@ -2192,7 +2212,7 @@
     // If the current window or buffer changed we need to bail out of the
     // waiting loop.  E.g. when a job exit callback closes the terminal window.
     if (curwin->w_id != old_curwin_id || curbuf->b_fnum != old_curbuf_fnum)
-	ins_char_typebuf(K_IGNORE);
+	ins_char_typebuf(K_IGNORE, 0);
 
     --entered;
 }
diff --git a/src/globals.h b/src/globals.h
index f0716c5..387c62e 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -120,7 +120,12 @@
  * When vgetc() is called, it sets mod_mask to the set of modifiers that are
  * held down based on the MOD_MASK_* symbols that are read first.
  */
-EXTERN int	mod_mask INIT(= 0x0);		// current key modifiers
+EXTERN int	mod_mask INIT(= 0);		// current key modifiers
+
+// The value of "mod_mask" and the unomdified character before calling
+// merge_modifyOtherKeys().
+EXTERN int	vgetc_mod_mask INIT(= 0);
+EXTERN int	vgetc_char INIT(= 0);
 
 /*
  * Cmdline_row is the row where the command line starts, just below the
diff --git a/src/message.c b/src/message.c
index 04dc401..45217e2 100644
--- a/src/message.c
+++ b/src/message.c
@@ -1258,7 +1258,7 @@
 	{
 	    // Put the character back in the typeahead buffer.  Don't use the
 	    // stuff buffer, because lmaps wouldn't work.
-	    ins_char_typebuf(c);
+	    ins_char_typebuf(vgetc_char, vgetc_mod_mask);
 	    do_redraw = TRUE;	    // need a redraw even though there is
 				    // typeahead
 	}
@@ -3712,7 +3712,7 @@
 		if (c == ':' && ex_cmd)
 		{
 		    retval = dfltbutton;
-		    ins_char_typebuf(':');
+		    ins_char_typebuf(':', 0);
 		    break;
 		}
 
diff --git a/src/normal.c b/src/normal.c
index 690bb00..48e1c71 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -595,7 +595,7 @@
 	// restart automatically.
 	// Insert the typed character in the typeahead buffer, so that it can
 	// be mapped in Insert mode.  Required for ":lmap" to work.
-	ins_char_typebuf(c);
+	ins_char_typebuf(vgetc_char, vgetc_mod_mask);
 	if (restart_edit != 0)
 	    c = 'd';
 	else
diff --git a/src/proto/getchar.pro b/src/proto/getchar.pro
index 9ff6620..57d78b5 100644
--- a/src/proto/getchar.pro
+++ b/src/proto/getchar.pro
@@ -25,7 +25,7 @@
 void stop_redo_ins(void);
 int noremap_keys(void);
 int ins_typebuf(char_u *str, int noremap, int offset, int nottyped, int silent);
-void ins_char_typebuf(int c);
+void ins_char_typebuf(int c, int modifier);
 int typebuf_changed(int tb_change_cnt);
 int typebuf_typed(void);
 int typebuf_maplen(void);
diff --git a/src/terminal.c b/src/terminal.c
index 52f8105..59bf039 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -3467,7 +3467,7 @@
 	redraw_statuslines();
 
 	// Need to break out of vgetc().
-	ins_char_typebuf(K_IGNORE);
+	ins_char_typebuf(K_IGNORE, 0);
 	typebuf_was_filled = TRUE;
 
 	term = curbuf->b_term;
diff --git a/src/testdir/test_messages.vim b/src/testdir/test_messages.vim
index e076241..b74ad2c 100644
--- a/src/testdir/test_messages.vim
+++ b/src/testdir/test_messages.vim
@@ -2,6 +2,7 @@
 
 source shared.vim
 source term_util.vim
+source view_util.vim
 
 func Test_messages()
   let oldmore = &more
@@ -305,4 +306,12 @@
   endif
 endfunc
 
+func Test_mapping_at_hit_return_prompt()
+  nnoremap <C-B> :echo "hit ctrl-b"<CR>
+  call feedkeys(":ls\<CR>", "xt")
+  call feedkeys("\<C-B>", "xt")
+  call assert_match('hit ctrl-b', Screenline(&lines - 1))
+  nunmap <C-B>
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index f038324..a1b6a7d 100644
--- a/src/version.c
+++ b/src/version.c
@@ -747,6 +747,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    839,
+/**/
     838,
 /**/
     837,