Skip to content

Commit

Permalink
Don't report associated text only for C0/C1
Browse files Browse the repository at this point in the history
This has a side effect that we'll have text reported for Alt+Shift+T
and similar, but only C0/C1 should be excluded and Alt+Shift+T is
emitting neither, thus regular `T` will be reported.

Fixes alacritty#7657.
  • Loading branch information
kchibisov committed Jan 27, 2024
1 parent ee4fcc8 commit 4eec597
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 23 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

- CLI env variables clearing configuration file variables
- Vi inline search/semantic selection expanding across newlines
- C0 and C1 codes being emitted in associated text when using kitty keyboard

### Changed

Expand Down
53 changes: 30 additions & 23 deletions alacritty/src/input/keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,11 +275,18 @@ fn build_sequence(key: KeyEvent, mods: ModifiersState, mode: TermMode) -> Vec<u8
let context =
SequenceBuilder { mode, modifiers, kitty_seq, kitty_encode_all, kitty_event_type };

let associated_text = key.text_with_all_modifiers().filter(|text| {
mode.contains(TermMode::REPORT_ASSOCIATED_TEXT)
&& key.state != ElementState::Released
&& !text.is_empty()
&& !is_control_character(text)
});

let sequence_base = context
.try_build_numpad(&key)
.or_else(|| context.try_build_named(&key))
.or_else(|| context.try_build_control_char_or_mod(&key, &mut modifiers))
.or_else(|| context.try_build_textual(&key));
.or_else(|| context.try_build_textual(&key, associated_text));

let (payload, terminator) = match sequence_base {
Some(SequenceBase { payload, terminator }) => (payload, terminator),
Expand All @@ -289,10 +296,7 @@ fn build_sequence(key: KeyEvent, mods: ModifiersState, mode: TermMode) -> Vec<u8
let mut payload = format!("\x1b[{}", payload);

// Add modifiers information.
if kitty_event_type
|| !modifiers.is_empty()
|| (mode.contains(TermMode::REPORT_ASSOCIATED_TEXT) && key.text.is_some())
{
if kitty_event_type || !modifiers.is_empty() || associated_text.is_some() {
payload.push_str(&format!(";{}", modifiers.encode_esc_sequence()));
}

Expand All @@ -307,19 +311,13 @@ fn build_sequence(key: KeyEvent, mods: ModifiersState, mode: TermMode) -> Vec<u8
payload.push(event_type);
}

// Associated text is not reported when the control/alt/logo is pressesed.
if mode.contains(TermMode::REPORT_ASSOCIATED_TEXT)
&& key.state != ElementState::Released
&& (modifiers.is_empty() || modifiers == SequenceModifiers::SHIFT)
{
if let Some(text) = key.text {
let mut codepoints = text.chars().map(u32::from);
if let Some(codepoint) = codepoints.next() {
payload.push_str(&format!(";{codepoint}"));
}
for codepoint in codepoints {
payload.push_str(&format!(":{codepoint}"));
}
if let Some(text) = associated_text {
let mut codepoints = text.chars().map(u32::from);
if let Some(codepoint) = codepoints.next() {
payload.push_str(&format!(";{codepoint}"));
}
for codepoint in codepoints {
payload.push_str(&format!(":{codepoint}"));
}
}

Expand All @@ -342,7 +340,11 @@ pub struct SequenceBuilder {

impl SequenceBuilder {
/// Try building sequence from the event's emitting text.
fn try_build_textual(&self, key: &KeyEvent) -> Option<SequenceBase> {
fn try_build_textual(
&self,
key: &KeyEvent,
associated_text: Option<&str>,
) -> Option<SequenceBase> {
let character = match key.logical_key.as_ref() {
Key::Character(character) => character,
_ => return None,
Expand Down Expand Up @@ -374,10 +376,7 @@ impl SequenceBuilder {
};

Some(SequenceBase::new(payload.into(), SequenceTerminator::Kitty))
} else if self.kitty_encode_all
&& self.mode.contains(TermMode::REPORT_ASSOCIATED_TEXT)
&& key.text.is_some()
{
} else if self.kitty_encode_all && associated_text.is_some() {
// Fallback when need to report text, but we don't have any key associated with this
// text.
Some(SequenceBase::new("0".into(), SequenceTerminator::Kitty))
Expand Down Expand Up @@ -644,3 +643,11 @@ impl From<ModifiersState> for SequenceModifiers {
modifiers
}
}

/// Check whether the `text` is `0x7f`, `C0` or `C1` control code.
fn is_control_character(text: &str) -> bool {
// 0x7f (DEL) is included here since it has a dedicated control code (`^?`) which generally
// does not match the reported text (`^H`), despite not technically being part of C0 or C1.
let codepoint = text.bytes().next().unwrap();
text.len() == 1 && (codepoint < 0x20 || (0x7f..=0x9f).contains(&codepoint))
}

0 comments on commit 4eec597

Please sign in to comment.