aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/input/windows_vti.rs67
1 files changed, 62 insertions, 5 deletions
diff --git a/src/client/input/windows_vti.rs b/src/client/input/windows_vti.rs
index 3b29e790..5742b825 100644
--- a/src/client/input/windows_vti.rs
+++ b/src/client/input/windows_vti.rs
@@ -389,6 +389,7 @@ impl WindowsInputMapper {
key_down = key.key_down,
repeat_count = key.repeat_count,
virtual_key_code = key.virtual_key_code,
+ virtual_scan_code = key.virtual_scan_code,
unicode = key.unicode,
control_key_state = key.control_key_state,
"windows input trace: console key record"
@@ -452,8 +453,11 @@ impl WindowsInputMapper {
return false;
}
+ // Physical Escape carries a scan code. Scan-code-zero Escape can
+ // introduce raw VT reports and must stay in the framer.
let bare_escape = modifiers.is_empty()
- && (key.virtual_key_code == 0x1b || (key.virtual_key_code == 0 && key.unicode == 0x1b));
+ && ((key.virtual_key_code == 0x1b && key.virtual_scan_code == 0)
+ || (key.virtual_key_code == 0 && key.unicode == 0x1b));
let ctrl_bracket = key.virtual_key_code == 0xdb
&& key.unicode == 0x1b
&& modifiers == crossterm::event::KeyModifiers::CONTROL;
@@ -1338,9 +1342,11 @@ mod tests {
}
#[test]
- fn vti_escape_key_record_flushes_to_escape_after_idle() {
+ fn vti_scan_code_zero_escape_key_record_flushes_after_idle() {
let mut translator = WindowsInputTranslator::default();
- assert!(translator.translate(key_vk(0x1b, 0)).is_empty());
+ assert!(translator
+ .translate(key_vk_with_scan_unicode(0x1b, 0, '\0', 0))
+ .is_empty());
assert_eq!(
translator.idle(),
vec![crate::protocol::ClientInputEvent::Key {
@@ -1352,6 +1358,19 @@ mod tests {
}
#[test]
+ fn vti_physical_escape_key_record_is_immediately_semantic() {
+ let mut translator = WindowsInputTranslator::default();
+ assert_eq!(
+ translator.translate(key_vk_with_scan_unicode(0x1b, 0x01, '\x1b', 0)),
+ vec![crate::protocol::ClientInputEvent::Key {
+ code: crate::protocol::ClientKeyCode::Esc,
+ modifiers: 0,
+ kind: crate::protocol::ClientKeyKind::Press,
+ }]
+ );
+ }
+
+ #[test]
fn vti_repeated_escape_record_stays_semantic() {
assert_eq!(
translate([key_vk_with_repeat(0x1b, 3)]),
@@ -1752,8 +1771,8 @@ mod tests {
}
#[test]
- fn vti_escape_key_record_without_unicode_starts_mouse_sequence() {
- let records = [key_vk(0x1b, 0)]
+ fn vti_scan_code_zero_escape_starts_mouse_sequence() {
+ let records = [key_vk_with_scan_unicode(0x1b, 0, '\0', 0)]
.into_iter()
.chain("[<35;48;26M".chars().map(key_char));
@@ -1769,6 +1788,44 @@ mod tests {
}
#[test]
+ fn vti_nonzero_scan_escape_is_immediately_semantic() {
+ let mut translator = WindowsInputTranslator::default();
+ assert_eq!(
+ translator.translate(key_vk_with_scan_unicode(0x1b, 0x02, '\0', 0)),
+ vec![crate::protocol::ClientInputEvent::Key {
+ code: crate::protocol::ClientKeyCode::Esc,
+ modifiers: 0,
+ kind: crate::protocol::ClientKeyKind::Press,
+ }]
+ );
+ }
+
+ #[test]
+ fn vti_win32_input_mode_physical_escape_is_immediately_semantic() {
+ let records = win32_input_mode_encoded_record(WindowsKeyRecord {
+ key_down: true,
+ repeat_count: 1,
+ virtual_key_code: 0x1b,
+ virtual_scan_code: 0x01,
+ unicode: 0x1b,
+ control_key_state: 0,
+ });
+ let mut translator = WindowsInputTranslator::default();
+
+ assert_eq!(
+ records
+ .into_iter()
+ .flat_map(|record| translator.translate(record))
+ .collect::<Vec<_>>(),
+ vec![crate::protocol::ClientInputEvent::Key {
+ code: crate::protocol::ClientKeyCode::Esc,
+ modifiers: 0,
+ kind: crate::protocol::ClientKeyKind::Press,
+ }]
+ );
+ }
+
+ #[test]
fn vti_win32_input_mode_encoded_mouse_sequence() {
assert_eq!(
translate(win32_input_mode_encoded_raw_bytes(b"\x1b[<35;48;26M")),