diff --git a/src/testFixtures/kotlin/org/jetbrains/plugins/ideavim/VimTestCase.kt b/src/testFixtures/kotlin/org/jetbrains/plugins/ideavim/VimTestCase.kt
index 200533359..f3e0b9ae8 100644
--- a/src/testFixtures/kotlin/org/jetbrains/plugins/ideavim/VimTestCase.kt
+++ b/src/testFixtures/kotlin/org/jetbrains/plugins/ideavim/VimTestCase.kt
@@ -73,7 +73,6 @@ import com.maddyhome.idea.vim.options.helpers.GuiCursorOptionHelper
 import com.maddyhome.idea.vim.options.helpers.GuiCursorType
 import com.maddyhome.idea.vim.state.mode.Mode
 import com.maddyhome.idea.vim.state.mode.inBlockSelection
-import com.maddyhome.idea.vim.state.mode.mode
 import com.maddyhome.idea.vim.ui.ex.ExEntryPanel
 import com.maddyhome.idea.vim.vimscript.model.CommandLineVimLContext
 import com.maddyhome.idea.vim.vimscript.model.datatypes.VimFuncref
@@ -119,6 +118,7 @@ abstract class VimTestCase {
     if (editor != null) {
       KeyHandler.getInstance().fullReset(editor.vim)
     }
+    KeyHandler.getInstance().keyState.reset(Mode.NORMAL())
     VimPlugin.getOptionGroup().resetAllOptionsForTesting()
     VimPlugin.getKey().resetKeyMappings()
     VimPlugin.getSearch().resetState()
diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/KeyHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/KeyHandler.kt
index be54dc46c..e25133ddc 100644
--- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/KeyHandler.kt
+++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/KeyHandler.kt
@@ -34,6 +34,7 @@ import com.maddyhome.idea.vim.key.CommandNode
 import com.maddyhome.idea.vim.key.CommandPartNode
 import com.maddyhome.idea.vim.key.KeyStack
 import com.maddyhome.idea.vim.key.Node
+import com.maddyhome.idea.vim.state.KeyHandlerState
 import com.maddyhome.idea.vim.state.VimStateMachine
 import com.maddyhome.idea.vim.state.mode.Mode
 import com.maddyhome.idea.vim.state.mode.ReturnTo
@@ -48,6 +49,7 @@ import javax.swing.KeyStroke
  * actions. This is a singleton.
  */
 public class KeyHandler {
+  public val keyState: KeyHandlerState = KeyHandlerState()
 
   private var handleKeyRecursionCount = 0
 
diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/impl/state/VimStateMachineImpl.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/impl/state/VimStateMachineImpl.kt
index 07ced4921..9f0bc19da 100644
--- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/impl/state/VimStateMachineImpl.kt
+++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/impl/state/VimStateMachineImpl.kt
@@ -7,8 +7,8 @@
  */
 package com.maddyhome.idea.vim.impl.state
 
+import com.maddyhome.idea.vim.KeyHandler
 import com.maddyhome.idea.vim.api.VimEditor
-import com.maddyhome.idea.vim.api.injector
 import com.maddyhome.idea.vim.command.Command
 import com.maddyhome.idea.vim.command.CommandBuilder
 import com.maddyhome.idea.vim.command.CommandFlags
@@ -27,10 +27,10 @@ import javax.swing.KeyStroke
  * Used to maintain state before and while entering a Vim command (operator, motion, text object, etc.)
  */
 public class VimStateMachineImpl : VimStateMachine {
-  override val commandBuilder: CommandBuilder = CommandBuilder(injector.keyGroup.getKeyRoot(MappingMode.NORMAL))
+  override val commandBuilder: CommandBuilder = KeyHandler.getInstance().keyState.commandBuilder
   override var mode: Mode = Mode.NORMAL()
-  override val mappingState: MappingState = MappingState()
-  override val digraphSequence: DigraphSequence = DigraphSequence()
+  override val mappingState: MappingState = KeyHandler.getInstance().keyState.mappingState
+  override val digraphSequence: DigraphSequence = KeyHandler.getInstance().keyState.digraphSequence
   override var isDotRepeatInProgress: Boolean = false
   override var isRegisterPending: Boolean = false
   override var isReplaceCharacter: Boolean = false
diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/state/KeyHandlerState.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/state/KeyHandlerState.kt
new file mode 100644
index 000000000..ab72f86ec
--- /dev/null
+++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/state/KeyHandlerState.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2003-2024 The IdeaVim authors
+ *
+ * Use of this source code is governed by an MIT-style
+ * license that can be found in the LICENSE.txt file or at
+ * https://opensource.org/licenses/MIT.
+ */
+
+package com.maddyhome.idea.vim.state
+
+import com.maddyhome.idea.vim.api.injector
+import com.maddyhome.idea.vim.command.CommandBuilder
+import com.maddyhome.idea.vim.command.MappingMode
+import com.maddyhome.idea.vim.command.MappingState
+import com.maddyhome.idea.vim.common.DigraphSequence
+import com.maddyhome.idea.vim.impl.state.toMappingMode
+import com.maddyhome.idea.vim.state.mode.Mode
+
+public class KeyHandlerState {
+  public val mappingState: MappingState = MappingState()
+  public val digraphSequence: DigraphSequence = DigraphSequence()
+  public val commandBuilder: CommandBuilder = CommandBuilder(injector.keyGroup.getKeyRoot(MappingMode.NORMAL))
+
+  public fun partialReset(mode: Mode) {
+    digraphSequence.reset()
+    mappingState.resetMappingSequence()
+    commandBuilder.resetInProgressCommandPart(injector.keyGroup.getKeyRoot(mode.toMappingMode()))
+  }
+
+  public fun reset(mode: Mode) {
+    digraphSequence.reset()
+    mappingState.resetMappingSequence()
+    commandBuilder.resetAll(injector.keyGroup.getKeyRoot(mode.toMappingMode()))
+  }
+}
\ No newline at end of file