diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py
index 0953d32..f2bc579 100644
--- a/IPython/terminal/interactiveshell.py
+++ b/IPython/terminal/interactiveshell.py
@@ -12,8 +12,19 @@ from IPython.utils.py3compat import input
 from IPython.utils.terminal import toggle_set_term_title, set_term_title, restore_term_title
 from IPython.utils.process import abbrev_cwd
 from traitlets import (
-    Bool, Unicode, Dict, Integer, observe, Instance, Type, default, Enum, Union,
-    Any, validate
+    Bool,
+    Unicode,
+    Dict,
+    Integer,
+    observe,
+    Instance,
+    Type,
+    default,
+    Enum,
+    Union,
+    Any,
+    validate,
+    Float,
 )
 
 from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
@@ -142,6 +153,25 @@ class TerminalInteractiveShell(InteractiveShell):
         help="Add shortcuts from 'emacs' insert mode to 'vi' insert mode.",
     ).tag(config=True)
 
+    modal_cursor = Bool(
+        True,
+        help="""
+       Cursor shape changes depending on vi mode: beam in vi insert mode,
+       block in nav mode, underscore in replace mode.""",
+    ).tag(config=True)
+
+    ttimeoutlen = Float(
+        0.01,
+        help="""The time in milliseconds that is waited for a key code
+       to complete.""",
+    ).tag(config=True)
+
+    timeoutlen = Float(
+        0.5,
+        help="""The time in milliseconds that is waited for a mapped key
+       sequence to complete.""",
+    ).tag(config=True)
+
     autoformatter = Unicode(None,
         help="Autoformatter to reformat Terminal code. Can be `'black'` or `None`",
         allow_none=True
diff --git a/IPython/terminal/shortcuts.py b/IPython/terminal/shortcuts.py
index ed35b2a..f92babd 100644
--- a/IPython/terminal/shortcuts.py
+++ b/IPython/terminal/shortcuts.py
@@ -19,6 +19,7 @@ from prompt_toolkit.filters import (has_focus, has_selection, Condition,
 from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline
 from prompt_toolkit.key_binding import KeyBindings
 from prompt_toolkit.key_binding.bindings import named_commands as nc
+from prompt_toolkit.key_binding.vi_state import InputMode, ViState
 
 from IPython.utils.decorators import undoc
 
@@ -160,6 +161,32 @@ def create_ipython_shortcuts(shell):
     for keys, cmd in keys_cmd_dict.items():
         kb.add(*keys, filter=focused_insert & ebivim)(cmd)
 
+    def get_input_mode(self):
+        if sys.version_info[0] == 3:
+            app = get_app()
+            app.ttimeoutlen = shell.ttimeoutlen
+            app.timeoutlen = shell.timeoutlen
+
+        return self._input_mode
+
+    def set_input_mode(self, mode):
+        shape = {InputMode.NAVIGATION: 2, InputMode.REPLACE: 4}.get(mode, 6)
+        cursor = "\x1b[{} q".format(shape)
+
+        if hasattr(sys.stdout, "_cli"):
+            write = sys.stdout._cli.output.write_raw
+        else:
+            write = sys.stdout.write
+
+        write(cursor)
+        sys.stdout.flush()
+
+        self._input_mode = mode
+
+    if shell.editing_mode == "vi" and shell.modal_cursor:
+        ViState._input_mode = InputMode.INSERT
+        ViState.input_mode = property(get_input_mode, set_input_mode)
+
     return kb
 
 
@@ -341,4 +368,4 @@ if sys.platform == 'win32':
                 return
         except ClipboardEmpty:
             return
-        event.current_buffer.insert_text(text.replace('\t', ' ' * 4))
+        event.current_buffer.insert_text(text.replace("\t", " " * 4))
diff --git a/docs/autogen_shortcuts.py b/docs/autogen_shortcuts.py
index 2cd9019..38af9b1 100755
--- a/docs/autogen_shortcuts.py
+++ b/docs/autogen_shortcuts.py
@@ -41,12 +41,14 @@ def multi_filter_str(flt):
 log_filters = {'_AndList': 'And', '_OrList': 'Or'}
 log_invert =  {'_Invert'}
 
-class _DummyTerminal(object):
+class _DummyTerminal:
     """Used as a buffer to get prompt_toolkit bindings
     """
     handle_return = None
     input_transformer_manager = None
     display_completions = None
+    editing_mode = "emacs"
+
 
 ipy_bindings = create_ipython_shortcuts(_DummyTerminal()).bindings