[BUG] Mods: Pane Button hotkeys depend on the active input source — bind them to the physical key so a mod works the same in any input language

Status Open
Reported on v2.1.300
Maintainer reply None cached
Activity 0 comments · opened Oct 15, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Summary

A mod's keyboard controls should work the same way whatever input language the user currently has on. Today a Pane Button's hotkey is matched against the character the active input source produces, not the key the user pressed. So the same mod responds to d with the ABC layout on, and ignores it after the user switches the input source.

Korean is the example here: with the Korean input source on, the physical a / d / r keys produce ㅁ / ㅇ / ㄱ, and none of the Pane's hotkeys fire. Users who switch languages during the day (to write commit messages, prompts or comments in their own language) find the mod's keys working or not depending on the last language they typed in. To use the mod, they have to remember to switch back to English first.

The goal is not "support Korean characters as hotkeys". The goal is that a plugin author declares hotkey="d" once, and the user presses that same key in every input language and gets the same action.

A plugin can't provide that consistency itself:

  • the API has no way to bind a physical key position
  • hotkey accepts only "one digit or one lowercase letter … anything else is refused", so a plugin can't even list per-layout characters (and making every plugin author maintain a per-language table would defeat the purpose anyway)
  • Client's onKey receives the typed character, not the physical key, and only after a mouse click gives it focus

Related, but about Ctrl-based engine shortcuts rather than plugin hotkeys: #77386, #93113. Those analyses suggest the same mechanism: the terminal reports the key's codepoint for the current layout, not the physical key.

Environment

  • Claude Code 2.1.300
  • macOS (Darwin 24.6.0)
  • Terminal: [ ]
  • Input source: Korean [2-Set / 두벌식 — confirm]

Reproduction

  1. A plugin opens a Pane with:

``tsx
<Button plain key="next" hotkey="d" label="next" onPress={...} />
``

  1. Open the pane with focus: true (or ctrl+x tab into it).
  2. With the input source set to ABC/US, press d. The button fires. ✅
  3. Switch the input source to Korean and press the same physical key (ㅇ). Nothing happens. ❌

Expected

A Pane hotkey is bound to a physical key, and pressing that key fires it whatever input source is active, the way shortcuts behave in most desktop apps and editors. hotkey="d" means "the key labelled D on a US layout", in every input language.

Possible fix

Match hotkeys on the base-layout / physical key when the terminal reports it, e.g. the kitty keyboard protocol's base-layout key (flag 4, "report alternate keys"). Fall back to the typed character only when the terminal can't report the physical key.

Per-language workarounds (mapping Korean jamo to QWERTY, or letting plugins list extra characters per layout) would fix Korean but not the general problem. Each input language would need its own handling, and the experience would still differ between them.

Why it matters

Single-letter hotkeys are the main way to drive a plugin pane. When they depend on the input source, the same mod feels broken or working depending on what the user last typed, with no visible cause. This affects anyone who switches input languages: Korean, Japanese, Chinese, Russian, Thai, Greek, Hebrew and so on.

What Should Happen?

A mod's keys should behave the same regardless of the user's current input language. A Pane Button with hotkey="d" should fire whenever the user presses the physical d key, whether the active input source is ABC, Korean or any other layout. For example, with the Korean input source on, the physical d key (which types ㅇ) should press the same Button it presses under ABC/US.

The plugin author should only have to declare the key once. Handling each input language separately should not fall on the plugin or the user.

Error Messages/Logs

Steps to Reproduce

  1. On macOS, add the Korean input source (System Settings → Keyboard → Input Sources → Korean, 2-Set) next to ABC.
  2. Create a minimal plugin folder hotkey-repro/ with these three files:

hotkey-repro/.claude-plugin/plugin.json
``json
{ "name": "hotkey-repro", "version": "0.0.1" }
``

hotkey-repro/hooks/hooks.json
``json
{ "modules": ["./register.tsx"] }
``

hotkey-repro/hooks/register.tsx
```tsx
import type { Register } from 'claude-code'

export const register: Register = on => {
on('session.start', async ($, e, next) => {
await $.command.register({ name: 'hotkey-repro', description: 'Open a pane with a hotkey Button' })
return next(e)
})

on('command.run', { command: 'hotkey-repro' }, async $ => {
await $.ui.open({ id: 'hotkey-repro', title: 'hotkey repro', focus: true, closeOnEscape: true })
return { text: 'opened' }
})

on('ui.render', { component: 'Pane', requestId: 'hotkey-repro' }, async ($, e) => {
const { Box, Text, Button } = $.ui.resolve(e)
return (
<Box flexDirection="column">
<Text>Press d. A toast "pressed" should appear.</Text>
<Button plain key="press" hotkey="d" label="press" onPress={() => $.ui.toast('pressed')} />
</Box>
)
})
}
```

  1. Run claude --plugin-dir ./hotkey-repro, then type /hotkey-repro. The pane opens with focus.
  2. With the input source on ABC, press d. The toast pressed appears. ✅
  3. Switch the input source to Korean (the pane keeps focus; use ctrl+x tab to refocus it if needed) and press the same physical d key, which types ㅇ. No toast appears. ❌
  4. Switch back to ABC and press d again. The toast appears again.

The same physical key, in the same focused pane, works or doesn't depending only on which input source was last active. Korean is just the example used here; any input source whose d key produces a different character behaves the same.

Claude Model

_No response_

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.300 (Claude Code)

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

IntelliJ IDEA terminal

Additional Information

_No response_

View original on GitHub ↗