diff options
Diffstat (limited to 'src/client')
| -rw-r--r-- | src/client/input.rs | 48 | ||||
| -rw-r--r-- | src/client/input/windows_vti.rs | 31 | ||||
| -rw-r--r-- | src/client/mod.rs | 13 |
3 files changed, 81 insertions, 11 deletions
diff --git a/src/client/input.rs b/src/client/input.rs index 1d557543..c37a15c7 100644 --- a/src/client/input.rs +++ b/src/client/input.rs @@ -210,7 +210,7 @@ fn windows_crossterm_reader_loop( tracing::debug!(event = ?event, "windows control key forwarded as semantic input"); } - let Some(event) = crate::protocol::ClientInputEvent::from_crossterm(event) else { + let Some(event) = windows_crossterm_input_event(event) else { continue; }; if event_tx @@ -226,6 +226,21 @@ fn windows_crossterm_reader_loop( } } +#[cfg(any(windows, test))] +fn windows_crossterm_input_event( + event: crossterm::event::Event, +) -> Option<crate::protocol::ClientInputEvent> { + let event = crate::protocol::ClientInputEvent::from_crossterm(event)?; + match event { + crate::protocol::ClientInputEvent::Key { + code: crate::protocol::ClientKeyCode::Char(codepoint), + modifiers: 0, + kind: crate::protocol::ClientKeyKind::Press, + } => Some(crate::protocol::ClientInputEvent::Text { codepoint }), + event => Some(event), + } +} + #[cfg(windows)] fn windows_event_is_control_key(event: &crossterm::event::Event) -> bool { use crossterm::event::{Event, KeyModifiers}; @@ -308,11 +323,22 @@ fn windows_client_input_event_from_raw( event: crate::raw_input::RawInputEvent, ) -> Option<crate::protocol::ClientInputEvent> { match event { - crate::raw_input::RawInputEvent::Key(key) => Some(crate::protocol::ClientInputEvent::Key { - code: crate::protocol::ClientKeyCode::from_crossterm(key.code)?, - modifiers: key.modifiers.bits(), - kind: crate::protocol::ClientKeyKind::from_crossterm(key.kind), - }), + crate::raw_input::RawInputEvent::Key(key) if key.is_text_commit => { + let crossterm::event::KeyCode::Char(codepoint) = key.code else { + return None; + }; + Some(crate::protocol::ClientInputEvent::Text { codepoint }) + } + crate::raw_input::RawInputEvent::Key(key) => { + let code = crate::protocol::ClientKeyCode::from_crossterm(key.code)?; + let modifiers = key.modifiers.bits(); + let kind = crate::protocol::ClientKeyKind::from_crossterm(key.kind); + Some(crate::protocol::ClientInputEvent::Key { + code, + modifiers, + kind, + }) + } crate::raw_input::RawInputEvent::Mouse(mouse) => { Some(crate::protocol::ClientInputEvent::Mouse { kind: crate::protocol::ClientMouseKind::from_crossterm(mouse.kind)?, @@ -474,6 +500,16 @@ mod windows_tests { } #[test] + fn windows_crossterm_printable_press_is_text() { + let event = Event::Key(KeyEvent::new(KeyCode::Char('你'), KeyModifiers::empty())); + + assert_eq!( + windows_crossterm_input_event(event), + Some(crate::protocol::ClientInputEvent::Text { codepoint: '你' }) + ); + } + + #[test] fn windows_ctrl_bracket_starts_raw_escape_sequence() { let ctrl_bracket = Event::Key(KeyEvent::new(KeyCode::Char('['), KeyModifiers::CONTROL)); assert_eq!( diff --git a/src/client/input/windows_vti.rs b/src/client/input/windows_vti.rs index 5742b825..8966112e 100644 --- a/src/client/input/windows_vti.rs +++ b/src/client/input/windows_vti.rs @@ -622,6 +622,12 @@ impl WindowsInputMapper { kind: crate::protocol::ClientKeyKind, ) -> Option<crate::protocol::ClientInputEvent> { let modifiers = windows_key_modifiers(key.control_key_state); + if key.virtual_key_code == 0 { + let codepoint = self.utf16_unit_to_char(key.unicode)?; + if !codepoint.is_control() { + return Some(crate::protocol::ClientInputEvent::Text { codepoint }); + } + } if modifiers.contains(crossterm::event::KeyModifiers::CONTROL) && key.unicode == 0x000a && (key.virtual_key_code == 0x4a || key.virtual_scan_code == 0x24) @@ -1220,6 +1226,25 @@ mod tests { } #[test] + fn vti_win32_input_mode_marks_ime_commit_as_text() { + for control_key_state in [0, 0x0010, 0x0008] { + let records = win32_input_mode_encoded_record(WindowsKeyRecord { + key_down: true, + repeat_count: 1, + virtual_key_code: 0, + virtual_scan_code: 0, + unicode: '你' as u16, + control_key_state, + }); + + assert_eq!( + translate(records), + vec![crate::protocol::ClientInputEvent::Text { codepoint: '你' }] + ); + } + } + + #[test] fn vti_win32_input_mode_decoded_paste_flag_clears_after_raw_completion() { let mut records = win32_input_mode_encoded_key_bytes(b"\x1b[200~"); records.extend("one\x1b[201~".chars().map(key_char)); @@ -1694,11 +1719,7 @@ mod tests { assert_eq!( translate(records), vec