keymanapp / keymanapp/keyman

bug(windows): VSCode can receive events out-of-order when an extension binds backspace key

Open
#14,936 1 comment 1 reaction 0 assignees View on GitHub
bug compatibility windows/
Dominant language
Pascal
Stars
534
Forks
143
Avg merge
2d 10h
Merged PRs (30d)
113

Description

Original report: https://community.software.sil.org/t/some-ipa-key-combinations-not-working-in-vs-code/10768

When any VSCode extension has a keybinding for the Bksp key, even if the extension does nothing but call `commands.executeCommand('deleteLeft')` (i.e. default behavior), the command may be executed out of order -- a subsequent keystroke received may be processed before the `deleteLeft` event. While the original reporter experienced this when using a Keyman keyboard, it is easily reproducible without Keyman being involved.

This is reliably reproducible on Windows. I have not tested on other platforms.

This appears to be a race condition between the system input queue and extension keybinding processing within VSCode. I don't know if there are ways to mitigate this within the extension itself -- I could not find any?

# Setup test

* clone [vscode-ext-backspace-bug repo](https://github.com/mcdurdin/vscode-ext-backspace-bug) and load it in VSCode
* `npm install`
* Press F5 to start a new VSCode instance with this extension loaded

# Testing with Keyman (reproducing original report)

* Install the [sil_ipa](https://keyman.com/keyboards/sil_ipa) keyboard in Keyman
* Switch to VSCode (extension running instance)
* Create a new file (Plain Text format is fine)
* Switch to the SIL IPA keyboard using the Windows Language Selector
* Type the key sequence p=. This should result in `ʘ`. Sometimes, you'll get the expected output, but other times, the `ʘ` will very briefly appear, and then be deleted, leaving `p`. (Background, Keyman will emit the `p` first, then delete it when = is pressed, and emit `ʘ`).

# Minimal repro without Keyman

To verify that Keyman is not involved in this, you can use the tiny sample 'emit' app, which simply generates a Bksp = ten times in a row using the Windows `SendInput` API. The output should be `==========`.

* Make sure that Keyman is _not_ running and that your default Windows keyboard is selected.
* Build and run src/emit/emit.vcxproj (or use src/emit/emit.exe)
* Make sure that the target application (i.e. VSCode with the extension running) is ready:
* Switch to VSCode
* Create a new file (Plain Text format is fine)
* Click on the emit window, and immediately click back into the VSCode edit window.
* After 3 seconds, emit will send the key events to VSCode.

The output should always be `==========`, but when the extension is active, you'll (probably) see `a=a=a=a=a=`. You can test this against VSCode without this extension running, or e.g. in Notepad.

The following [log](https://github.com/microsoft/vscode/wiki/Keybinding-Issues#basic-troubleshooting) shows the broken state (first 3 keystrokes only, a Bksp =):

```log
2025-10-09 13:05:01.615 [info] [Window] [KeybindingService]: / Soft dispatching keyboard event
2025-10-09 13:05:01.625 [info] [Window] [KeybindingService]: | Resolving A
2025-10-09 13:05:01.625 [info] [Window] [KeybindingService]: \ No keybinding entries.
2025-10-09 13:05:01.626 [info] [Window] [KeybindingService]: / Received keydown event - modifiers: [], code: KeyA, keyCode: 65, key: a
2025-10-09 13:05:01.626 [info] [Window] [KeybindingService]: | Converted keydown event - modifiers: [], code: KeyA, keyCode: 31 ('A')
2025-10-09 13:05:01.627 [info] [Window] [KeybindingService]: | Resolving A
2025-10-09 13:05:01.627 [info] [Window] [KeybindingService]: \ No keybinding entries.

2025-10-09 13:05:01.630 [info] [Window] [KeybindingService]: / Soft dispatching keyboard event
2025-10-09 13:05:01.634 [info] [Window] [KeybindingService]: | Resolving Backspace
2025-10-09 13:05:01.635 [info] [Window] [KeybindingService]: \ From 3 keybinding entries, matched markdown.extension.onBackspaceKey, when: editorTextFocus && !editorReadonly, source: user extension mcdurdin.markdown-keyman-backspace-bug.
2025-10-09 13:05:01.637 [info] [Window] [KeybindingService]: / Received keydown event - modifiers: [], code: Backspace, keyCode: 8, key: Backspace
2025-10-09 13:05:01.637 [info] [Window] [KeybindingService]: | Converted keydown event - modifiers: [], code: Backspace, keyCode: 1 ('Backspace')
2025-10-09 13:05:01.637 [info] [Window] [KeybindingService]: | Resolving Backspace
2025-10-09 13:05:01.637 [info] [Window] [KeybindingService]: \ From 3 keybinding entries, matched markdown.extension.onBackspaceKey, when: editorTextFocus && !editorReadonly, source: user extension mcdurdin.markdown-keyman-backspace-bug.
2025-10-09 13:05:01.639 [info] [Window] [KeybindingService]: + Invoking command markdown.extension.onBackspaceKey.

2025-10-09 13:05:01.639 [info] [Window] [KeybindingService]: / Soft dispatching keyboard event
2025-10-09 13:05:01.639 [info] [Window] [KeybindingService]: | Resolving =
2025-10-09 13:05:01.640 [info] [Window] [KeybindingService]: \ No keybinding entries.
2025-10-09 13:05:01.640 [info] [Window] [KeybindingService]: / Received keydown event - modifiers: [], code: Equal, keyCode: 187, key: =
2025-10-09 13:05:01.640 [info] [Window] [KeybindingService]: | Converted keydown event - modifiers: [], code: Equal, keyCode: 86 ('=')
2025-10-09 13:05:01.641 [info] [Window] [KeybindingService]: | Resolving =
2025-10-09 13:05:01.642 [info] [Window] [KeybindingService]: \ No keybinding entries.

2025-10-09 13:05:01.659 [info] [Window] [KeybindingService]: / Soft dispatching keyboard event
2025-10-09 13:05:01.659 [info] [Window] [KeybindingService]: | Resolving A
2025-10-09 13:05:01.660 [info] [Window] [KeybindingService]: \ No keybinding entries.
2025-10-09 13:05:01.660 [info] [Window] [KeybindingService]: / Received keydown event - modifiers: [], code: KeyA, keyCode: 65, key: a
2025-10-09 13:05:01.660 [info] [Window] [KeybindingService]: | Converted keydown event - modifiers: [], code: KeyA, keyCode: 31 ('A')
2025-10-09 13:05:01.660 [info] [Window] [KeybindingService]: | Resolving A
2025-10-09 13:05:01.660 [info] [Window] [KeybindingService]: \ No keybinding entries.

2025-10-09 13:05:01.665 [info] [Window] [KeybindingService]: / Soft dispatching keyboard event
2025-10-09 13:05:01.666 [info] [Window] [KeybindingService]: | Resolving Backspace
2025-10-09 13:05:01.666 [info] [Window] [KeybindingService]: \ From 3 keybinding entries, matched markdown.extension.onBackspaceKey, when: editorTextFocus && !editorReadonly, source: user extension mcdurdin.markdown-keyman-backspace-bug.
2025-10-09 13:05:01.666 [info] [Window] [KeybindingService]: / Received keydown event - modifiers: [], code: Backspace, keyCode: 8, key: Backspace
2025-10-09 13:05:01.666 [info] [Window] [KeybindingService]: | Converted keydown event - modifiers: [], code: Backspace, keyCode: 1 ('Backspace')
2025-10-09 13:05:01.666 [info] [Window] [KeybindingService]: | Resolving Backspace
2025-10-09 13:05:01.666 [info] [Window] [KeybindingService]: \ From 3 keybinding entries, matched markdown.extension.onBackspaceKey, when: editorTextFocus && !editorReadonly, source: user extension mcdurdin.markdown-keyman-backspace-bug.
2025-10-09 13:05:01.666 [info] [Window] [KeybindingService]: + Invoking command markdown.extension.onBackspaceKey.

2025-10-09 13:05:01.667 [info] [Window] [KeybindingService]: / Soft dispatching keyboard event
2025-10-09 13:05:01.667 [info] [Window] [KeybindingService]: | Resolving =
2025-10-09 13:05:01.667 [info] [Window] [KeybindingService]: \ No keybinding entries.
2025-10-09 13:05:01.667 [info] [Window] [KeybindingService]: / Received keydown event - modifiers: [], code: Equal, keyCode: 187, key: =
2025-10-09 13:05:01.667 [info] [Window] [KeybindingService]: | Converted keydown event - modifiers: [], code: Equal, keyCode: 86 ('=')
2025-10-09 13:05:01.667 [info] [Window] [KeybindingService]: | Resolving =
2025-10-09 13:05:01.667 [info] [Window] [KeybindingService]: \ No keybinding entries.
```

# References

* https://vscode-docs.readthedocs.io/en/stable/customization/keybindings/
* https://github.com/microsoft/vscode/wiki/Keybinding-Issues
* https://github.com/microsoft/vscode/issues/270731
*
# Potentially related bug reports

* https://github.com/Microsoft/vscode/issues/76488
* https://github.com/microsoft/vscode/issues/71238
* https://github.com/Microsoft/vscode/issues/4955

# Screencaps

## Incorrect output, when extension is active in VSCode

https://github.com/user-attachments/assets/110bb50c-d75a-4d82-b44a-b3e601e18262

## Correct output, when extension is inactive in VSCode

https://github.com/user-attachments/assets/981a14f1-93ca-485b-aa55-987147270cf7

## Correct output, in Notepad

https://github.com/user-attachments/assets/fe26f46c-857b-4c43-bff6-318c4ebae405

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.