Skip to content

feat: support configured Windows keyboard layouts - #1905

Open
yuxuanchen1997 wants to merge 3 commits into
rime:masterfrom
yuxuanchen1997:feature/hkl-keyboard-layouts
Open

feat: support configured Windows keyboard layouts#1905
yuxuanchen1997 wants to merge 3 commits into
rime:masterfrom
yuxuanchen1997:feature/hkl-keyboard-layouts

Conversation

@yuxuanchen1997

@yuxuanchen1997 yuxuanchen1997 commented Jul 31, 2026

Copy link
Copy Markdown

Windows TSF presents QWERTY-oriented key events to IMEs even when the user uses another keyboard layout. Unlike Rime frontends on macOS and Linux, Weasel therefore cannot always follow the system keyboard setting.

Add a keyboard_layout option that accepts either a registered Windows layout name, such as Colemak or United States-Dvorak, or an explicit KLID. An empty value preserves existing behavior.

Resolve and load the configured layout without activating it for the current thread, then translate physical scan codes with MapVirtualKeyEx and ToUnicodeEx. Apply the layout consistently to both Rime composition and direct ASCII input while preserving shortcuts, special keys, and key-release events.

Assisted-By: Codex GPT 5.6 Sol

Windows TSF presents QWERTY-oriented key events to IMEs even when the user types with another installed layout. Unlike Rime frontends on macOS and Linux, Weasel therefore cannot simply follow the system keyboard setting.

Resolve the configured keyboard layout through its Windows KLID and translate physical scan codes with MapVirtualKeyEx and ToUnicodeEx. Apply the layout consistently to Rime composition and direct ASCII input while preserving shortcuts, special keys, and key-release events.

Assisted-By: Codex GPT 5.6 Sol
Windows keyboard layout identifiers are difficult to discover and may vary between installations. Allow keyboard_layout to use the case-insensitive Layout Text of any system-registered layout while retaining explicit KLID support.

Load a resolved layout when needed without activating it for the current thread, and reject missing or ambiguous names.

Assisted-By: Codex GPT 5.6 Sol
@yuxuanchen1997
yuxuanchen1997 marked this pull request as ready for review July 31, 2026 02:11
@Bobo-alcazar

Copy link
Copy Markdown

Thanks for working on configurable Windows keyboard layouts. The HKL-based approach is a much better direction than hard-coding a small set of layouts in Weasel.

However, because the purpose of this PR is to support configured/custom Windows keyboard layouts, I do not think US/ASCII-style behavior should be the implicit compatibility target. For many non-US layouts, AltGr and dead keys are normal parts of the layout, not unusual edge cases. A user who selects such an HKL should reasonably expect Weasel to obtain the same text result that the Windows layout would produce.

There are two issues worth addressing or at least documenting clearly.

1. AltGr and dead-key handling are part of layout support

ConvertKeyEvent() copies the current keyboard state, but then clears both VK_CONTROL and VK_MENU before calling ToUnicodeEx():

table[VK_CONTROL] = 0;
table[VK_MENU] = 0;

AltGr is a distinct layout modifier layer, analogous to the Shift layer: it selects an additional set of characters for a physical key rather than being merely an application shortcut. For layouts whose AltGr level is represented by Ctrl+Alt / Right Alt, clearing those states can prevent ToUnicodeEx() from selecting that layout layer and its AltGr mapping. I understand the motivation may be to avoid treating ordinary Ctrl/Alt shortcuts as text input, but that distinction should be handled separately from the keyboard state supplied to the layout translator. Otherwise, support for a configured non-US layout is incomplete by design.

Dead keys deserve the same treatment. ToUnicodeEx() returns a negative value for the dead-key stroke and retains state for the next key. The current code only accepts ret == 1, so it has no explicit handling for the first dead-key event, a dead-key sequence, or output containing more than one UTF-16 code unit. Since dead keys are a standard feature of many international layouts, could this PR add end-to-end tests for at least one AltGr layout and one dead-key layout, and adjust the handling as needed?

2. Non-ASCII layout output exposes a separate librime limitation

Once non-US layouts are supported, ToUnicodeEx() can legitimately return non-ASCII characters. This PR passes a single result to librime as a KeyEvent, but the current Speller::ProcessKeyEvent() rejects ch >= 0x7f. Therefore those characters cannot become Rime composition input or be used for table lookup, even though the frontend correctly obtained them from the Windows layout.

I do not expect this PR to solve that larger librime issue. It would still be helpful to document the boundary and track a follow-up librime issue: supporting non-ASCII input codes requires changes to the key-event, speller, and input-code/lookup path, not only the Weasel frontend.

In short, the HKL-based direction is promising, but AltGr and dead keys should be treated as core compatibility requirements for non-US/custom layouts. Non-ASCII input-code lookup can be handled as a separate downstream librime task.

@yuxuanchen1997

Copy link
Copy Markdown
Author

Thanks for identifying these limitations. I agree that complete support for arbitrary Windows layouts ultimately needs correct AltGr, dead-key, multi-code-unit, and non-ASCII input handling.

I would prefer to keep this PR scoped to selecting a configured HKL and applying it consistently through Weasel’s existing key-event pipeline. The Ctrl/Alt clearing and single-character handling predate this change, while non-ASCII composition is also constrained by librime’s current speller/input-code path. Addressing only part of that stack here could introduce inconsistent behavior without providing end-to-end support.

These downstream limitations are not specific to this HKL implementation and may also affect other Rime frontends where system layouts already work, such as Squirrel on macOS and ibus-rime or fcitx-rime on Linux. I think they are better tracked separately across Weasel and librime. I can document that boundary here, but would prefer not to expand this patch into general international-layout input support.

Apply the repository clang-format rules and normalize the new lines to match their surrounding files.

Assisted-By: Codex GPT 5.6 Sol
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants