Skip to content

fix(windows): resync caps lock state when Keyman keyboard is activated - #16423

Open
MattGyverLee wants to merge 6 commits into
keymanapp:masterfrom
MattGyverLee:fix/windows/16422-caps-lock-state-on-keyboard-switch
Open

fix(windows): resync caps lock state when Keyman keyboard is activated#16423
MattGyverLee wants to merge 6 commits into
keymanapp:masterfrom
MattGyverLee:fix/windows/16422-caps-lock-state-on-keyboard-switch

Conversation

@MattGyverLee

@MattGyverLee MattGyverLee commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Here's a proposed fix for #16422 .

Full disclosure, Claude built this minimal fix. I have reviewed the result and tested it by inserting a rebuilt keyman32 and keyman64 DLLs in place. It's just displacing code, nothing new. Rereading the state of the system's locks on keyboard load makes sense to me.

I tested moving with Win+Space and via mouse between the Windows US English and Keyman Cameroon Keyboard. CAPS was detected when the Cameroon Keyboard activated and the first output letter was a capital. It worked well. I noted that switching to yoruba8 ignored the existing CAPS state without disabling it on the system, but this is expected since that keyboard doesn't have CAPS rules.

From Claude:

The Caps Lock and Num Lock flags in Globals::ShiftState() are updated only as key events pass through the engine, so they go stale when the toggle is changed while a non-Keyman layout is active. The existing resync in GetCapsAndNumlockState() runs on window focus change, which a keyboard switch does not trigger, so the core processor was told Caps Lock was off until the user toggled it twice.

Extract the toggle resync as RefreshToggleState() and call it from TIPActivateKeyboard(), which is the profile activation path for both Win+Space and the Windows language selector.

Fixes: #16422
Build-bot: release:windows

The Caps Lock and Num Lock flags in Globals::ShiftState() are updated
only as key events pass through the engine, so they go stale when the
toggle is changed while a non-Keyman layout is active. The existing
resync in GetCapsAndNumlockState() runs on window focus change, which a
keyboard switch does not trigger, so the core processor was told Caps
Lock was off until the user toggled it twice.

Extract the toggle resync as RefreshToggleState() and call it from
TIPActivateKeyboard(), which is the profile activation path for both
Win+Space and the Windows language selector.

Fixes keymanapp#16422

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011GdFpFi5eqJP6C1YjuQytY
@github-project-automation github-project-automation Bot moved this to Todo in Keyman Aug 21, 2026
@keymanapp-test-bot keymanapp-test-bot Bot added the user-test-missing User tests have not yet been defined for the PR label Aug 21, 2026
@keymanapp-test-bot

keymanapp-test-bot Bot commented Aug 21, 2026

Copy link
Copy Markdown

User Test Results

Test specification and instructions

  • TEST_RESYNC_CAPS_TEST (OPEN)

⬜ SUITE_CAPSLOCK:

  • ⬜ GROUP_WIN11:

    • TEST_CAPSLOCK-1 (OPEN)
    • TEST_CAPSLOCK-2 (OPEN)
    • TEST_CAPSLOCK-3 (OPEN)
    • TEST_CAPSLOCK-4 (OPEN)
    • TEST_CAPSLOCK-5 (OPEN)
    • TEST_CAPSOFF-1 (OPEN)
    • TEST_CAPSOFF-2 (OPEN)
    • TEST_CAPSOFF-3 (OPEN)
    • TEST_CAPSOFF-4 (OPEN)
    • TEST_CAPSOFF-5 (OPEN)
    • TEST_CAPSONLY-1 (OPEN)
    • TEST_CAPSONLY-2 (OPEN)
    • TEST_CAPSONLY-3 (OPEN)
    • TEST_CAPSONLY-4 (OPEN)
    • TEST_CAPSONLY-5 (OPEN)
    • TEST_CAPSONLY-6 (OPEN)
  • ⬜ GROUP_WIN10:

    • TEST_CAPSLOCK-1 (OPEN)
    • TEST_CAPSLOCK-2 (OPEN)
    • TEST_CAPSLOCK-3 (OPEN)
    • TEST_CAPSLOCK-4 (OPEN)
    • TEST_CAPSLOCK-5 (OPEN)
    • TEST_CAPSOFF-1 (OPEN)
    • TEST_CAPSOFF-2 (OPEN)
    • TEST_CAPSOFF-3 (OPEN)
    • TEST_CAPSOFF-4 (OPEN)
    • TEST_CAPSOFF-5 (OPEN)
    • TEST_CAPSONLY-1 (OPEN)
    • TEST_CAPSONLY-2 (OPEN)
    • TEST_CAPSONLY-3 (OPEN)
    • TEST_CAPSONLY-4 (OPEN)
    • TEST_CAPSONLY-5 (OPEN)
    • TEST_CAPSONLY-6 (OPEN)
Results Template
# Test Results

* **TEST_RESYNC_CAPS_TEST (OPEN):** notes

## SUITE_CAPSLOCK: 

### GROUP_WIN11: 

* **TEST_CAPSLOCK-1 (OPEN):** notes
* **TEST_CAPSLOCK-2 (OPEN):** notes
* **TEST_CAPSLOCK-3 (OPEN):** notes
* **TEST_CAPSLOCK-4 (OPEN):** notes
* **TEST_CAPSLOCK-5 (OPEN):** notes
* **TEST_CAPSOFF-1 (OPEN):** notes
* **TEST_CAPSOFF-2 (OPEN):** notes
* **TEST_CAPSOFF-3 (OPEN):** notes
* **TEST_CAPSOFF-4 (OPEN):** notes
* **TEST_CAPSOFF-5 (OPEN):** notes
* **TEST_CAPSONLY-1 (OPEN):** notes
* **TEST_CAPSONLY-2 (OPEN):** notes
* **TEST_CAPSONLY-3 (OPEN):** notes
* **TEST_CAPSONLY-4 (OPEN):** notes
* **TEST_CAPSONLY-5 (OPEN):** notes
* **TEST_CAPSONLY-6 (OPEN):** notes

### GROUP_WIN10: 

* **TEST_CAPSLOCK-1 (OPEN):** notes
* **TEST_CAPSLOCK-2 (OPEN):** notes
* **TEST_CAPSLOCK-3 (OPEN):** notes
* **TEST_CAPSLOCK-4 (OPEN):** notes
* **TEST_CAPSLOCK-5 (OPEN):** notes
* **TEST_CAPSOFF-1 (OPEN):** notes
* **TEST_CAPSOFF-2 (OPEN):** notes
* **TEST_CAPSOFF-3 (OPEN):** notes
* **TEST_CAPSOFF-4 (OPEN):** notes
* **TEST_CAPSOFF-5 (OPEN):** notes
* **TEST_CAPSONLY-1 (OPEN):** notes
* **TEST_CAPSONLY-2 (OPEN):** notes
* **TEST_CAPSONLY-3 (OPEN):** notes
* **TEST_CAPSONLY-4 (OPEN):** notes
* **TEST_CAPSONLY-5 (OPEN):** notes
* **TEST_CAPSONLY-6 (OPEN):** notes

@keymanapp-test-bot keymanapp-test-bot Bot added this to the A19S36 milestone Aug 21, 2026
@keyman-server

Copy link
Copy Markdown
Collaborator

This pull request is from an external repo and will not automatically be built. The build must still be passed before it can be merged. Ask one of the team members to make a manual build of this PR.

@mcdurdin mcdurdin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your contribution. This looks pretty straightforward and clean. We will need to test this in conjunction with the caps lock stores, in particular &CapsAlwaysOff, to ensure that we get a consistent result, and I would like @rc-swag to sign off on the change.

Comment thread windows/src/engine/keyman32/appint/aiTIP.cpp Outdated
Comment thread windows/src/engine/keyman32/capsstate.cpp Outdated
Comment thread windows/src/engine/keyman32/capsstate.cpp Outdated
Comment thread windows/src/engine/keyman32/capsstate.cpp Outdated
@mcdurdin
mcdurdin requested a review from rc-swag August 22, 2026 06:50
@mcdurdin

Copy link
Copy Markdown
Member

@rc-swag can you write up some user tests for this also?

MattGyverLee and others added 4 commits August 22, 2026 10:25
Co-authored-by: Marc Durdin <marc@durdin.net>
Co-authored-by: Marc Durdin <marc@durdin.net>
Co-authored-by: Marc Durdin <marc@durdin.net>
Co-authored-by: Marc Durdin <marc@durdin.net>
@rc-swag

rc-swag commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

User Testing

TEST_RESYNC_CAPS_TEST

  • Install Keyman Cameroon sil_cameroon_qwerty
  • Use a any text input application like the Word or Notepade or the attached text editor
  • Select a Windows keyboard such as English press CAPS LOCK
  • Press A and observe a capital A is output
  • Use Win+Space to select the Cameroon qwerty keyboard
  • Press S and obeserve a captial S is output
  • CAPS LOCK
  • Press S and obeserve a lowercase s is output.

Regresion Tests

Taken from #15771
On Windows 11
Compliant
Test in both Notepad, Word, Firefox for compliant applications

Non-compliant
Use Texteditor64 and Texteditor32 for non-compliant applications

On Windows 10 Test

Test in Word, Firefox for compliant applications

Non-compliant
Use Notepad, Texteditor64 and Texteditor32 for non-compliant applications

SUITE_CAPSLOCK:

  • GROUP_WIN11
  • GROUP_WIN10

Caps Lock

The test keyboard layouts are found in the keyman repo at app/windows/src/test/manual-tests/caps-lock-stores. There is a project file for the 3 keyboards used in this test. The project file can be used to build the keyboard packages, but you can conveniently use the .kmp file zipped and included respectively below.

The test cases below expect the usage of the capslock.kmp.zip keyboard. That keyboard outputs pass or fail if following the test cases.

Prerequisites before each test

  • System keyboard layout is en-US
  • Install a keyboard that doesn't use any of the caps lock stores, e.g. capslock.kmp.
  • CapsLock is currently on
  • Currently active keyboard is the capslock.kmp keyboard

Test cases

click to expand
  • TEST_CAPSLOCK-1: uppercase with virtual key

    • press and release a

    Expected result:

    • pass. (with other keyboards uppercase A)
  • TEST_CAPSLOCK-2: lowercase with virtual key

    • press and hold 'Shift'
    • press and release b
    • release Shift

    Expected result:

    • pass. (with other keyboards lowercase b)
  • TEST_CAPSLOCK-3: capslock ignored for numbers

    • press and hold 'Shift'
    • press and release 3
    • release Shift

    Expected result:

    • pass. (with other keyboards #)
  • TEST_CAPSLOCK-4: uppercase

    • press and release c

    Expected result:

    • pass. (with other keyboards uppercase C)
  • TEST_CAPSLOCK-5: lowercase

    • press and hold 'Shift'
    • press and release d
    • release Shift

    Expected result:

    • pass. (with other keyboards lowercase d)

CapsAlwaysOff

For these tests, use a keyboard with the caps_always_off.kmp.zip store set. We call this keyboard capsalwaysoff below.

Any keyboard with that store set will work; if you don't have one at hand you can use the caps_always_off.kmp keyboard. The caps_always_off.kmp keyboard will prevent switching caps lock on. As a sanity check to verify that Keyman is actually active, pressing the key a will output ncaps_little_a, and Shift+a will output ncaps_shift_A.

Note: When testing in a virtual machine, use an on-screen keyboard (in VirtualBox: Input/Keyboard/Soft Keyboard) and observe the caps lock indicator of the on-screen keyboard. Using the hardware keyboard might show side effects with caps lock.

Prerequisites before each test

  • Install a keyboard that has CapsAlwaysOff store set, e.g. caps_always_off.kmp.
  • CapsLock is currently off
  • Currently active keyboard is a non-Keyman keyboard

Test cases

click to expand
  • TEST_CAPSOFF-1: sanity check

    • switch to capsalwaysoff keyboard
    • press and release a

    Expected result:

    • output: ncaps_little_a
  • TEST_CAPSOFF-2: caps lock stays off

    • switch to capsalwaysoff keyboard
    • press and release CapsLock key
    • press and release a

    Expected result:

    • caps lock indicator is off
    • output: ncaps_little_a
  • TEST_CAPSOFF-3: no caps lock while holding capslock key

    • switch to capsalwaysoff keyboard
    • press and hold CapsLock key (the indicator will momentarily be on)
    • press and release a
    • release CapsLock key

    Expected result:

    • caps lock indicator is off (it does not stay on)
    • output: ncaps_little_a
  • TEST_CAPSOFF-4: no caps lock while holding capslock key

    • switch to capsalwaysoff keyboard
    • press and hold CapsLock key
    • press and hold Shift key
    • press and release a
    • release CapsLock and Shift keys

    Expected result:

    • output: ncaps_shift_A
  • TEST_CAPSOFF-5: switching turns off caps lock

    • turn on caps lock
    • switch to capsalwaysoff keyboard
    • press and release a

    Expected result:

    • caps lock indicator turned off
    • output: ncaps_little_a

SHIFT: CapsOnOnly/ShiftFreesCaps

For these tests, use a keyboard with the CapsOnOnly and ShiftFreesCaps stores set. We call this keyboard shift_frees_caps below.

Any keyboard with these stores set will work; if you don't have one at hand you can use the shift_frees_caps.kmp.zip keyboard.

The shift_frees_caps.kmp keyboard will enable caps lock by pressing the CapsLock key, and will turn capslock off by pressing the Shift key. The keyboard outputs pass or fail if following the test cases.

Note: When testing in a virtual machine, use an on-screen keyboard (in VirtualBox: Input/Keyboard/Soft Keyboard) and observe the caps lock indicator of the on-screen keyboard. Using the hardware keyboard might show side effects with caps lock. Except for TEST_CAPSONLY-5 which can only be reliably tested on a hardware keyboard on host OS (not a VM). For windows 10 and windows 11 with a virtual box vm-onscreen keyboard, the following happens. The VM soft keyboard does NOT actually send the Shift Shift Key Stroke through but rather will change the keys pressed for example if an a is pressed the soft keyboard itself will change that key to a A. This means we can't Test TEST_CAPONLY-5 on a soft keyboard.

Prerequisites before each test

  • Install a keyboard that has the CapsOnOnly and ShiftFreesCaps stores set, e.g.
    shift_frees_caps.kmp.
  • CapsLock is currently off
  • Currently active keyboard is shift_frees_caps keyboard

Test cases

click to expand
  • TEST_CAPSONLY-1: no caps

    • press and release 1

    Expected result:

    • output: pass.
  • TEST_CAPSONLY-2: caps

    • press and release CapsLock
    • press and release 2

    Expected result:

    • caps lock indicator turned on
    • output: pass.
  • TEST_CAPSONLY-3: caps doesn't toggle

    • press and release CapsLock
    • press and release CapsLock
    • press and release 6

    Expected result:

    • caps lock indicator turned on
    • output: pass.
  • TEST_CAPSONLY-4: shift turns off

    • press and release CapsLock
    • press and hold Shift
    • press and release 3
    • release Shift

    Expected result:

    • caps lock indicator turned off
    • output: pass.
  • TEST_CAPSONLY-5: shift by itself turns off
    Be aware of limitations when testing this on virtual machines as noted above.

    • press and release CapsLock
    • press and release Shift

    Expected result:

    • caps lock indicator turned off
    • (no output)
  • TEST_CAPSONLY-6: press CapsLock multiple times
    Be aware of limitations when testing this on virtual machines as noted above.

    • press and release CapsLock
    • press and release CapsLock
    • press and release CapsLock
    • press and release CapsLock
    • press and release Shift

    Expected result:

    • caps lock indicator stays on after each CapsLock press, momentarily turning off is expected as the key is pressed and released however is should then stay on.

    • caps lock indicator turned off after Shift Pressed

    • (no output)

@keymanapp-test-bot keymanapp-test-bot Bot added has-user-test user-test-required User tests have not been completed and removed user-test-missing User tests have not yet been defined for the PR labels Aug 24, 2026
Comment thread windows/src/engine/keyman32/capsstate.cpp Outdated

@rc-swag rc-swag left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a suggestion for the comment.

LGTM

Co-authored-by: rc-swag <58423624+rc-swag@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

bug(windows): Caps Lock state ignored when switching from MS to KM keyboard

4 participants