Skip to content

fix(tui): prevent AltGr from swallowing @/#/$/!/%/ characters in composer#2867

Merged
Hmbown merged 2 commits into
Hmbown:codex/v0.9.0-stewardshipfrom
ousamabenyounes:fix/azerty-altgr-at-key-conflict
Jun 6, 2026
Merged

fix(tui): prevent AltGr from swallowing @/#/$/!/%/ characters in composer#2867
Hmbown merged 2 commits into
Hmbown:codex/v0.9.0-stewardshipfrom
ousamabenyounes:fix/azerty-altgr-at-key-conflict

Conversation

@ousamabenyounes
Copy link
Copy Markdown

@ousamabenyounes ousamabenyounes commented Jun 6, 2026

Problem

On Windows, AltGr is delivered as Ctrl+Alt by crossterm. European keyboard layouts use AltGr to type common characters:

  • French AZERTY: @ = AltGr+0, # = AltGr+3
  • German QWERTZ: @ = AltGr+Q
  • UK QWERTY: # = AltGr+3

The sidebar-focus shortcuts (Alt+@, Alt+!, Alt+#, Alt+$, Alt+%), Alt+)) were matching on key.modifiers.contains(KeyModifiers::ALT) alone — so when a European user pressed AltGr to type @, the TUI interpreted it as the Alt+@ sidebar shortcut and focused the sidebar instead of inserting the character.

Closes #2863.

Fix

Added && !key.modifiers.contains(KeyModifiers::CONTROL) to five sidebar-focus shortcut guards (!, @, #, $/%, )). When AltGr produces Ctrl+Alt+char, the shortcut no longer fires and the character falls through to the KeyCode::Char(c) catch-all, which inserts it as text.

This is consistent with the existing codebase philosophy in key_hint.rs, where has_ctrl_or_alt() and is_altgr() already treat Ctrl+Alt as AltGr on Windows — trading the rare ability to bind Ctrl+Alt+<char> shortcuts for not swallowing European keyboard input.

Testing

  • Existing behavior preserved: Alt+@ (without Ctrl) still focuses the Tasks sidebar on all platforms.
  • AltGr fix: Ctrl+Alt+@ (AltGr+0 on French AZERTY) now inserts @ as text instead of triggering the sidebar shortcut.
  • The Alt+0 / Ctrl+Alt+0 shortcut is untouched — apply_alt_0_shortcut already handles Ctrl internally, and AltGr+0 on French AZERTY produces @ (not 0), so it doesn't conflict.

Greptile Summary

This PR fixes a bug where European keyboard users on Windows could not type @, #, $, !, or ) in the composer because AltGr (delivered as Ctrl+Alt by crossterm) was incorrectly matching the sidebar-focus shortcuts. The fix adds && !key.modifiers.contains(KeyModifiers::CONTROL) to five match guards so that Ctrl+Alt+<char> events fall through to the KeyCode::Char(c) catch-all and are inserted as text.

  • Five sidebar shortcuts patched (!, @, #, $/%, )): adding !CONTROL to each guard prevents AltGr-produced characters from triggering focus changes on Windows while leaving plain Alt+<char> shortcuts fully intact.
  • Catch-all path confirmed safe: KeyCode::Char(c) => { app.insert_char(c); } at the end of the match has no modifier guard, so the rejected Ctrl+Alt+@ event is correctly handed off to character insertion.
  • Adjacent shortcuts unaffected: Alt+0 and Alt+1/2/3/4 already inspect or delegate KeyModifiers::CONTROL internally and are not touched by this change.

Confidence Score: 5/5

Safe to merge — the change is a minimal, targeted guard addition with no regressions on the happy path.

The five changed guards each gain one additional condition that rejects events carrying both ALT and CONTROL. The downstream catch-all has no modifier guard, so rejected events are correctly routed to character insertion. Adjacent shortcuts already handle or delegate CONTROL internally and are untouched. The tradeoff that Ctrl+Alt+char no longer fires sidebar shortcuts on any platform is explicitly documented in both the PR description and the inline comment.

No files require special attention.

Important Files Changed

Filename Overview
crates/tui/src/tui/ui.rs Five sidebar-focus match guards updated to exclude Ctrl, preventing AltGr characters from being swallowed; the change is surgical and the fall-through to insert_char is verified correct.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Key Event received] --> B{Char is one of ! @ # $ percent close-paren}
    B -- no --> C[Other key handlers]
    B -- yes --> D{ALT modifier present?}
    D -- no --> E[Char catch-all: app.insert_char]
    D -- yes --> F{CONTROL modifier also present? Ctrl+Alt = AltGr on Windows}
    F -- yes --> E
    F -- no --> G[set_sidebar_focus and update status_message]
Loading

Reviews (2): Last reviewed commit: "style(tui): format AltGr sidebar shortcu..." | Re-trigger Greptile

…oser

On Windows, AltGr is delivered as Ctrl+Alt by crossterm. European keyboard
layouts (French AZERTY, German QWERTZ, etc.) use AltGr to type characters
like @ (AltGr+0), # (AltGr+3), etc. The sidebar-focus shortcuts for
Alt+@/Alt+!/Alt+#/Alt+$/Alt+%) were matching on "contains ALT" alone,
swallowing these AltGr-typed characters instead of inserting them into
the composer.

Exclude the Ctrl modifier from these sidebar-focus shortcut guards so
AltGr-typed glyphs fall through to the  catch-all and
are inserted as text. This is consistent with the has_ctrl_or_alt /
is_altgr philosophy in key_hint.rs, which already treats Ctrl+Alt as
AltGr to preserve European keyboard input.

Closes Hmbown#2863
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 6, 2026

Thanks @ousamabenyounes for taking the time to contribute.

This repository is currently observing a maintainer-managed contribution gate in dry-run mode, so this pull request is staying open. When enforcement is enabled, pull requests from contributors who are not listed in .github/APPROVED_CONTRIBUTORS will be closed automatically.

Please read CONTRIBUTING.md for the expected contribution shape. A maintainer can grant PR access by commenting /lgtm on a pull request.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request updates the event loop in crates/tui/src/tui/ui.rs to ensure that sidebar focus shortcuts using the Alt key are not triggered when the Control key is also pressed. This change prevents AltGr-typed characters on European keyboards (which emit Ctrl+Alt on Windows) from being swallowed. The review feedback points out a minor typo in the added explanatory comment, suggesting a correction to list all the sidebar focus shortcuts accurately.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread crates/tui/src/tui/ui.rs
continue;
}
KeyCode::Char('!') if key.modifiers.contains(KeyModifiers::ALT) => {
// Sidebar focus via Alt+! / Alt+@ / Alt+# / Alt+$ / Alt+%)
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.

medium

There is a minor typo in the comment: Alt+%) should be Alt+% / Alt+) to correctly list all the sidebar focus shortcuts handled by these match arms.

                // Sidebar focus via Alt+! / Alt+@ / Alt+# / Alt+$ / Alt+% / Alt+)

Comment thread crates/tui/src/tui/ui.rs Outdated
Comment on lines +2876 to +2882
// Sidebar focus via Alt+! / Alt+@ / Alt+# / Alt+$ / Alt+%)
// AltGr on European keyboards emits Ctrl+Alt on Windows, so
// exclude Ctrl to avoid swallowing AltGr-typed characters
// like @ (AltGr+0 on French AZERTY) and # (AltGr+3). This
// matches the has_ctrl_or_alt / is_altgr philosophy in
// key_hint.rs: treat Ctrl+Alt as AltGr, not a shortcut.
KeyCode::Char('!') if key.modifiers.contains(KeyModifiers::ALT) && !key.modifiers.contains(KeyModifiers::CONTROL) => {
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.

P2 The comment says this fix "matches the has_ctrl_or_alt / is_altgr philosophy in key_hint.rs", but the actual guard uses a raw !key.modifiers.contains(KeyModifiers::CONTROL) check instead of calling is_altgr. is_altgr is #[cfg(windows)]-gated and always returns false on Linux/macOS, so calling it here would preserve the (undocumented) ability for Ctrl+Alt+@ to fire the sidebar shortcut on non-Windows hosts. Using a raw CONTROL check unconditionally suppresses that combo on every platform. That may be the intended tradeoff — the PR description is explicit about trading Ctrl+Alt+char bindings — but then the comment overstates the alignment with is_altgr and may mislead future maintainers.

Suggested change
// Sidebar focus via Alt+! / Alt+@ / Alt+# / Alt+$ / Alt+%)
// AltGr on European keyboards emits Ctrl+Alt on Windows, so
// exclude Ctrl to avoid swallowing AltGr-typed characters
// like @ (AltGr+0 on French AZERTY) and # (AltGr+3). This
// matches the has_ctrl_or_alt / is_altgr philosophy in
// key_hint.rs: treat Ctrl+Alt as AltGr, not a shortcut.
KeyCode::Char('!') if key.modifiers.contains(KeyModifiers::ALT) && !key.modifiers.contains(KeyModifiers::CONTROL) => {
// Sidebar focus via Alt+! / Alt+@ / Alt+# / Alt+$ / Alt+%)
// AltGr on European keyboards emits Ctrl+Alt on Windows, so
// exclude Ctrl to avoid swallowing AltGr-typed characters
// like @ (AltGr+0 on French AZERTY) and # (AltGr+3).
// Note: this guard is platform-unconditional (unlike
// is_altgr in key_hint.rs), intentionally trading the ability
// to bind Ctrl+Alt+<char> shortcuts on any platform.
KeyCode::Char('!') if key.modifiers.contains(KeyModifiers::ALT) && !key.modifiers.contains(KeyModifiers::CONTROL) => {

Fix in Codex Fix in Claude Code Fix in Cursor

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Jun 6, 2026

Want your agent to iterate on Greptile's feedback? Try greploops.

@Hmbown Hmbown changed the base branch from main to codex/v0.9.0-stewardship June 6, 2026 17:36
@Hmbown Hmbown merged commit 461c22f into Hmbown:codex/v0.9.0-stewardship Jun 6, 2026
10 checks passed
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.

French AZERTY @ key conflicts with Alt-@ sidebar shortcut in TUI composer

2 participants