Skip to content

AltGr dead key types an extra base character in a --remote session #3948

Closed

Description

@albertotb

Is this a reproducible bug?

  • I confirm this is a reproducible bug, not a feature request, idea, question, contribution proposal, or direction check.
  • I reproduced this bug on the version and environment reported below using the exact steps provided.

Current behavior

On a Spanish ISO layout ~ is a dead key: AltGr+4 then Space. In a session attached with herdr --remote <host> this types 4~ — the key's base character leaks in alongside the tilde.

Same Windows herdr client, same physical keystroke:

Context Result
herdr local session (no --remote) ~
herdr --remote <host> 4~
Windows Terminal on its own ~
plain ssh <host> in Windows Terminal, no herdr ~

No custom Windows Terminal keybindings are configured.

Expected behavior

AltGr+4 then Space should type a single ~, as it does in a local herdr session.

Reproduction

  1. Windows client with a Spanish ISO keyboard layout, in Windows Terminal.
  2. Run herdr --remote <host> (--remote-keybindings left at its default, local).
  3. In any pane, press AltGr+4, then Space.

Result: 4~. Expected: ~.

Impact

~ is needed constantly for paths (~/.config/...) and shell expansion. Every one has to be deleted and retyped or pasted. It affects every pane in any --remote session

Environment

  • Herdr version: 0.9.0
  • Update channel (stable or preview): stable
  • Operating system: client Windows 10 Pro 19045; remote host Linux
  • Terminal: Windows Terminal 1.24.11911.0 (Store, stable)
  • Shell, if relevant: bash on the remote host
  • Relevant config, if any: ~/.config/herdr/config.toml has no [keys] section. Keyboard layout Spanish ISO (0000040A), not US-International.

Activity

  1. added
    bugSomething isn't working
    p2valid narrow or ordinary defect with limited impact or a practical workaround
    windowsaffects Windows-specific behavior
    remoteaffects SSH, headless, or remote attachment behavior
    inputkeyboard, mouse, clipboard, selection, or IME behavior
    on Sep 11, 2026
  2. akbash-bot commented on Sep 11, 2026

    @akbash-bot
    Collaborator

    Could you capture the Windows input records for one occurrence? That would let me replay the actual dead-key events against the Linux input path.

    In a PowerShell tab in Windows Terminal, outside Herdr, run this, replacing YOUR_HOST with your usual SSH target:

    $env:HERDR_WINDOWS_INPUT_TRACE = "1"
    $env:HERDR_LOG = "herdr::client::input::windows_vti=info"
    herdr --remote YOUR_HOST

    At a plain bash prompt, press AltGr+4, release both keys, then Space once. Do not press Enter. Detach with Ctrl+B, then Q. Back in PowerShell, run:

    Remove-Item Env:HERDR_WINDOWS_INPUT_TRACE, Env:HERDR_LOG
    $root = Join-Path $env:APPDATA "herdr"
    if ($env:XDG_CONFIG_HOME) { $root = Join-Path $env:XDG_CONFIG_HOME "herdr" }
    Get-Content (Join-Path $root "herdr-client.log") | Select-String "windows input trace:" | Select-Object -Last 40

    Please paste only that output. The log is written to %APPDATA%\herdr\herdr-client.log (or $env:XDG_CONFIG_HOME\herdr\herdr-client.log if configured). Tracing records typed keys, potentially including private text: avoid other typing during this capture and review the excerpt before posting.

  3. albertotb commented on Sep 11, 2026

    @albertotb
    Author

    Thanks for the quick response. Attaching the output of the provided command after doing the test:

    2026-09-11T10:28:46.781736Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=56 control_key_state=0
    2026-09-11T10:28:46.781741Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=59 control_key_state=0
    2026-09-11T10:28:46.781746Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=49 control_key_state=0
    2026-09-11T10:28:46.781750Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=95 control_key_state=0
    2026-09-11T10:28:46.781756Z  INFO herdr::client::input::windows_vti: windows input trace: client input events events=[Key { code: Char('b'), modifiers: 2, kind: Release, repeat_count: 1, generated_text: None, source: WindowsConsole { record: WindowsKeyRecord {
    key_down: false, repeat_count: 1, virtual_key_code: 66, virtual_scan_code: 48, unicode: 2, control_key_state: 8 } } }]
    2026-09-11T10:28:46.816520Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=27 control_key_state=0
    2026-09-11T10:28:46.816533Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=91 control_key_state=0
    2026-09-11T10:28:46.816542Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=49 control_key_state=0
    2026-09-11T10:28:46.816549Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=55 control_key_state=0
    2026-09-11T10:28:46.816554Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=59 control_key_state=0
    2026-09-11T10:28:46.816559Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=50 control_key_state=0
    2026-09-11T10:28:46.816565Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=57 control_key_state=0
    2026-09-11T10:28:46.816570Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=59 control_key_state=0
    2026-09-11T10:28:46.816575Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=48 control_key_state=0
    2026-09-11T10:28:46.816580Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=59 control_key_state=0
    2026-09-11T10:28:46.816585Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=48 control_key_state=0
    2026-09-11T10:28:46.816590Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=59 control_key_state=0
    2026-09-11T10:28:46.816595Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=48 control_key_state=0
    2026-09-11T10:28:46.816600Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=59 control_key_state=0
    2026-09-11T10:28:46.816605Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=49 control_key_state=0
    2026-09-11T10:28:46.816610Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=95 control_key_state=0
    2026-09-11T10:28:47.910977Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=27 control_key_state=0
    2026-09-11T10:28:47.911010Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=91 control_key_state=0
    2026-09-11T10:28:47.911017Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=56 control_key_state=0
    2026-09-11T10:28:47.911023Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=49 control_key_state=0
    2026-09-11T10:28:47.911028Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=59 control_key_state=0
    2026-09-11T10:28:47.911033Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=49 control_key_state=0
    2026-09-11T10:28:47.911041Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=54 control_key_state=0
    2026-09-11T10:28:47.911048Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=59 control_key_state=0
    2026-09-11T10:28:47.911053Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=49 control_key_state=0
    2026-09-11T10:28:47.911058Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=49 control_key_state=0
    2026-09-11T10:28:47.911063Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=51 control_key_state=0
    2026-09-11T10:28:47.911068Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=59 control_key_state=0
    2026-09-11T10:28:47.911073Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=49 control_key_state=0
    2026-09-11T10:28:47.911077Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=59 control_key_state=0
    2026-09-11T10:28:47.911082Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=48 control_key_state=0
    2026-09-11T10:28:47.911087Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=59 control_key_state=0
    2026-09-11T10:28:47.911092Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=49 control_key_state=0
    2026-09-11T10:28:47.911097Z  INFO herdr::client::input::windows_vti: windows input trace: console key record key_down=true repeat_count=1 virtual_key_code=0 virtual_scan_code=0 unicode=95 control_key_state=0
    2026-09-11T10:28:47.911108Z  INFO herdr::client::input::windows_vti: windows input trace: client input events events=[Key { code: Char('q'), modifiers: 0, kind: Press, repeat_count: 1, generated_text: None, source: WindowsConsole { record: WindowsKeyRecord { key_down:
    true, repeat_count: 1, virtual_key_code: 81, virtual_scan_code: 16, unicode: 113, control_key_state: 0 } } }]
    
  4. akbash-bot commented on Sep 11, 2026

    @akbash-bot
    Collaborator

    Thanks—the byte-by-byte logging pushed the AltGr sequence out of the excerpt; it shows only the final detach keys. My original filter was too broad.

    Could you extract just the decoded events from the existing log, without repeating the test? In the same PowerShell tab, run:

    $root = Join-Path $env:APPDATA "herdr"
    if ($env:XDG_CONFIG_HOME) { $root = Join-Path $env:XDG_CONFIG_HOME "herdr" }
    Get-Content (Join-Path $root "herdr-client.log") | Select-String "windows input trace: client input events" | Select-Object -Last 20 | ForEach-Object { $_.Line }

    Please paste that output, checking first for any private typed text. This reads the same herdr-client.log as before and does not enable tracing again.

  5. albertotb commented on Sep 11, 2026

    @albertotb
    Author
    2026-09-11T10:28:37.890051Z  INFO herdr::client::input::windows_vti: windows input trace: client input events events=[Mouse { kind: Moved, column: 88, row: 38, modifiers: 0 }]
    2026-09-11T10:28:37.898038Z  INFO herdr::client::input::windows_vti: windows input trace: client input events events=[Mouse { kind: Moved, column: 87, row: 38, modifiers: 0 }]
    2026-09-11T10:28:37.906094Z  INFO herdr::client::input::windows_vti: windows input trace: client input events events=[Mouse { kind: Moved, column: 86, row: 38, modifiers: 0 }]
    2026-09-11T10:28:37.914045Z  INFO herdr::client::input::windows_vti: windows input trace: client input events events=[Mouse { kind: Moved, column: 85, row: 38, modifiers: 0 }]
    2026-09-11T10:28:37.921997Z  INFO herdr::client::input::windows_vti: windows input trace: client input events events=[Mouse { kind: Moved, column: 85, row: 37, modifiers: 0 }]
    2026-09-11T10:28:37.930224Z  INFO herdr::client::input::windows_vti: windows input trace: client input events events=[Mouse { kind: Moved, column: 84, row: 37, modifiers: 0 }]
    2026-09-11T10:28:37.938225Z  INFO herdr::client::input::windows_vti: windows input trace: client input events events=[Mouse { kind: Moved, column: 83, row: 37, modifiers: 0 }]
    2026-09-11T10:28:37.954094Z  INFO herdr::client::input::windows_vti: windows input trace: client input events events=[Mouse { kind: Moved, column: 82, row: 36, modifiers: 0 }]
    2026-09-11T10:28:37.970084Z  INFO herdr::client::input::windows_vti: windows input trace: client input events events=[Mouse { kind: Moved, column: 81, row: 36, modifiers: 0 }]
    2026-09-11T10:28:37.978027Z  INFO herdr::client::input::windows_vti: windows input trace: client input events events=[Mouse { kind: Moved, column: 81, row: 35, modifiers: 0 }]
    2026-09-11T10:28:38.036295Z  INFO herdr::client::input::windows_vti: windows input trace: client input events events=[Mouse { kind: Down(Left), column: 81, row: 35, modifiers: 0 }]
    2026-09-11T10:28:38.084009Z  INFO herdr::client::input::windows_vti: windows input trace: client input events events=[Mouse { kind: Drag(Left), column: 81, row: 35, modifiers: 0 }]
    2026-09-11T10:28:38.132394Z  INFO herdr::client::input::windows_vti: windows input trace: client input events events=[Mouse { kind: Up(Left), column: 81, row: 35, modifiers: 0 }]
    2026-09-11T10:28:40.557886Z  INFO herdr::client::input::windows_vti: windows input trace: client input events events=[Key { code: Char('4'), modifiers: 0, kind: Press, repeat_count: 1, generated_text: None, source: WindowsConsole { record: WindowsKeyRecord { key_down: true, repeat_count: 1, virtual_key_code: 52, virtual_scan_code: 5, unicode: 0, control_key_state: 9 } } }]
    2026-09-11T10:28:40.657565Z  INFO herdr::client::input::windows_vti: windows input trace: client input events events=[Key { code: Char('4'), modifiers: 0, kind: Release, repeat_count: 1, generated_text: None, source: WindowsConsole { record: WindowsKeyRecord { key_down: false, repeat_count: 1, virtual_key_code: 52, virtual_scan_code: 5, unicode: 0, control_key_state: 9 } } }]
    2026-09-11T10:28:41.373877Z  INFO herdr::client::input::windows_vti: windows input trace: client input events events=[Key { code: Char('~'), modifiers: 0, kind: Press, repeat_count: 1, generated_text: None, source: WindowsConsole { record: WindowsKeyRecord { key_down: true, repeat_count: 1, virtual_key_code: 32, virtual_scan_code: 57, unicode: 126, control_key_state: 0 } } }]
    2026-09-11T10:28:41.449567Z  INFO herdr::client::input::windows_vti: windows input trace: client input events events=[Key { code: Char(' '), modifiers: 0, kind: Release, repeat_count: 1, generated_text: None, source: WindowsConsole { record: WindowsKeyRecord { key_down: false, repeat_count: 1, virtual_key_code: 32, virtual_scan_code: 57, unicode: 32, control_key_state: 0 } } }]
    2026-09-11T10:28:46.668099Z  INFO herdr::client::input::windows_vti: windows input trace: client input events events=[Key { code: Char('b'), modifiers: 2, kind: Press, repeat_count: 1, generated_text: None, source: WindowsConsole { record: WindowsKeyRecord { key_down: true, repeat_count: 1, virtual_key_code: 66, virtual_scan_code: 48, unicode: 2, control_key_state: 8 } } }]
    2026-09-11T10:28:46.781756Z  INFO herdr::client::input::windows_vti: windows input trace: client input events events=[Key { code: Char('b'), modifiers: 2, kind: Release, repeat_count: 1, generated_text: None, source: WindowsConsole { record: WindowsKeyRecord { key_down: false, repeat_count: 1, virtual_key_code: 66, virtual_scan_code: 48, unicode: 2, control_key_state: 8 } } }]
    2026-09-11T10:28:47.911108Z  INFO herdr::client::input::windows_vti: windows input trace: client input events events=[Key { code: Char('q'), modifiers: 0, kind: Press, repeat_count: 1, generated_text: None, source: WindowsConsole { record: WindowsKeyRecord { key_down: true, repeat_count: 1, virtual_key_code: 81, virtual_scan_code: 16, unicode: 113, control_key_state: 0 } } }]
    
  6. self-assigned this
    on Sep 11, 2026
  7. added
    maintainer-neededrequires maintainer judgment or maintainer-only reproduction
    and removed
    maintainer-neededrequires maintainer judgment or maintainer-only reproduction
    on Sep 11, 2026
  8. akbash-bot commented on Sep 11, 2026

    @akbash-bot
    Collaborator

    @albertotb Would you be willing to try the candidate from #3972 with your Spanish keyboard? German dead keys have been checked, but we would like to confirm your exact AltGr+4 case. This is optional, and you only need to build on Linux—not Windows.

    These steps use a separate test session and do not replace your installed Herdr or stop your existing sessions.

    1. Build on the Linux host

    Open a normal SSH connection from a fresh Windows Terminal tab (ssh YOUR_HOST), outside Herdr. The Linux host needs Git, a C compiler/build tools, Rust via rustup, and Zig 0.16.0. If those are unavailable, please stop here rather than change your machine just for this test.

    Paste this into the Linux SSH terminal. The build downloads dependencies and can take several minutes:

    TEST_DIR="$(mktemp -d "$HOME/herdr-3948.XXXXXX")" &&
    git init "$TEST_DIR" &&
    cd "$TEST_DIR" &&
    git fetch --depth 1 https://github.com/herdrdev/herdr.git refs/pull/3972/head &&
    git checkout --detach a92ae12de6144ea4017de5ced3f5546f9e580992 &&
    cargo build --release --locked &&
    TEST_SESSION="spanish-3948-$(date +%s)" &&
    printf '
    Your test session name is: %s
    ' "$TEST_SESSION" &&
    env -u HERDR_ENV -u HERDR_SESSION -u HERDR_SOCKET_PATH -u HERDR_CLIENT_SOCKET_PATH   ./target/release/herdr --session "$TEST_SESSION"

    If a command fails, stop there; do not continue with an installed binary instead. Once the test Herdr opens, press Ctrl+B, then Q to detach. Keep this SSH tab open. The test server keeps running.

    2. Test from Windows

    In a second, fresh PowerShell tab, replace YOUR_HOST with your usual SSH target and TEST_SESSION_NAME with the name printed above:

    herdr --remote YOUR_HOST --session TEST_SESSION_NAME

    If asked to stop or replace a server, answer No and stop the test.

    At a bash prompt in this test session, press AltGr+4, release both keys, then Space. Please tell us whether you see ~ or 4~. Do not press Enter; detach with Ctrl+B, then Q.

    3. Clean up

    Back in the first Linux SSH tab, paste:

    ./target/release/herdr session stop "$TEST_SESSION" &&
    ./target/release/herdr session delete "$TEST_SESSION"

    This removes only the temporary session. The build folder remains at $TEST_DIR; you can delete it afterward. No logs or private terminal content are needed.

  9. albertotb commented on Sep 11, 2026

    @albertotb
    Author

    Yes, I can try tomorrow. In fact Im vaguely familiar with building the project from source because I wanted to test the fix in Windows from #3701 (just to be clear this problem was tested in 0.9.0 stable). What I did in that case was fork the project and use your CI build action to build the exe. Is this a possibility here or I'm missing something? I do have access to a Linux machine, but using your build process took me about 10 mins.

  10. kangal-bot commented on Sep 11, 2026

    @kangal-bot
    Collaborator

    Implemented on master and queued for the next release. This is not available in a published Herdr release yet.

  11. kangal-bot commented on Sep 16, 2026

    @kangal-bot
    Collaborator

    Released on the preview channel in 2026-09-16-2c29fb29e302. This is available to preview users, but is not in a stable Herdr release yet.

  12. kangal-bot commented on Sep 16, 2026

    @kangal-bot
    Collaborator

    Released in v0.9.1.

  13. kangal-bot commented on Oct 12, 2026

    @kangal-bot
    Collaborator

    Released on the preview channel in 2026-10-12-6d697e1e75ff. This is available to preview users, but is not in a stable Herdr release yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workinginputkeyboard, mouse, clipboard, selection, or IME behaviormaintainer-neededrequires maintainer judgment or maintainer-only reproductionp2valid narrow or ordinary defect with limited impact or a practical workaroundpreview-releasedAvailable on the preview channel, pending a stable release.remoteaffects SSH, headless, or remote attachment behaviorwindowsaffects Windows-specific behavior

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions