aboutsummaryrefslogtreecommitdiff
path: root/src/input
diff options
context:
space:
mode:
authorakbash <akbash@herdr.dev>2026-09-03 00:19:49 +0300
committerGitHub <noreply@github.com>2026-09-02 23:19:49 +0200
commit2ae8b91ca5919c26df7ce779b0e9a5dd98b769ae (patch)
treead5374d3cf754346be29e525f7abb6ca3a04367b /src/input
parent45484aab84430ac2b18c7bbf44aba15f2b039677 (diff)
fix(windows): preserve dead-key composition in kitty panes (#3548)
refs #3546 Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com> Co-authored-by: JJ Liebig <jonathan.liebig@gmail.com>
Diffstat (limited to 'src/input')
-rw-r--r--src/input/encode.rs7
-rw-r--r--src/input/model.rs17
2 files changed, 24 insertions, 0 deletions
diff --git a/src/input/encode.rs b/src/input/encode.rs
index 774ab1a6..6dfff4ce 100644
--- a/src/input/encode.rs
+++ b/src/input/encode.rs
@@ -16,6 +16,13 @@ pub fn encode_key(key: KeyEvent, protocol: KeyboardProtocol) -> Vec<u8> {
}
pub fn encode_terminal_key(key: TerminalKey, protocol: KeyboardProtocol) -> Vec<u8> {
+ // A zero Unicode value on this Windows character event means the host layout is
+ // still composing a dead key. Kitty panes must not receive its physical fallback.
+ // Legacy Windows panes take the native ConPTY fallback before reaching this encoder.
+ if matches!(protocol, KeyboardProtocol::Kitty { .. }) && key.is_windows_shift_dead_key() {
+ return Vec::new();
+ }
+
// REPORT_ALL_KEYS must retain physical press/repeat/release semantics instead of
// reducing a native key to its layout-generated text.
let preserve_physical_key = key.has_physical_identity() && protocol.reports_all_keys();
diff --git a/src/input/model.rs b/src/input/model.rs
index 304c4f20..50cd7e42 100644
--- a/src/input/model.rs
+++ b/src/input/model.rs
@@ -78,6 +78,7 @@ pub struct TerminalKey {
pub shifted_codepoint: Option<u32>,
pub generated_text: Option<String>,
physical_identity_hint: bool,
+ windows_shift_dead_key: bool,
source: KeySource,
}
@@ -91,6 +92,7 @@ impl TerminalKey {
shifted_codepoint: None,
generated_text: None,
physical_identity_hint: false,
+ windows_shift_dead_key: false,
source: KeySource::Synthesized,
}
}
@@ -139,6 +141,7 @@ impl TerminalKey {
#[cfg(any(windows, test))]
pub fn with_windows_record(mut self, record: WindowsKeyRecord) -> Self {
+ self = self.with_windows_composition_hint(Some(record));
self.repeat_count = if self.kind == crossterm::event::KeyEventKind::Release {
1
} else {
@@ -153,6 +156,16 @@ impl TerminalKey {
self
}
+ pub(crate) fn with_windows_composition_hint(
+ mut self,
+ record: Option<WindowsKeyRecord>,
+ ) -> Self {
+ self.windows_shift_dead_key = matches!(self.code, KeyCode::Char(_))
+ && self.modifiers == KeyModifiers::SHIFT
+ && record.is_some_and(|record| record.unicode == 0);
+ self
+ }
+
pub(crate) fn with_physical_identity_hint(mut self, physical: bool) -> Self {
self.physical_identity_hint = physical;
self
@@ -176,6 +189,10 @@ impl TerminalKey {
None
}
+ pub(crate) fn is_windows_shift_dead_key(&self) -> bool {
+ self.windows_shift_dead_key
+ }
+
pub(crate) fn identity(&self) -> KeyIdentity {
match self.source {
#[cfg(any(windows, test))]