diff options
author | Nico Weber <thakis@chromium.org> | 2020-09-13 21:08:19 -0400 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-09-15 09:45:13 +0200 |
commit | 83c07be794276b82833f22c0b9e8cd3a6b72a291 (patch) | |
tree | 1dc97552c016bb812b30841236cbc7dab458094f /Libraries | |
parent | 2fe127d96ff9991d13d73e4c26c85cb44efeac99 (diff) | |
download | serenity-83c07be794276b82833f22c0b9e8cd3a6b72a291.zip |
LibVT+LibLine: Use `1;mods` CSI parameters for ctrl/alt/shift-arrow keys
xterms send a bitmask (+ 1) in the 2nd CSI parameter if "special"
keys (arrow keys, pgup/down, etc) are sent with modifiers held down.
Serenity's Terminal used to send ^[[O, which is a nonexistent
escape sequence and a misread of VT100's ^[O (ie the '[' is
replaced by 'O'). Since the xterm scheme also supports shift
and alt modifiers, switch to that.
More flexible, and makes ctrl-left/right and alt-left/right work
in SerenityOS's bash port.
Also do this for page up/down.
No behavior change for SerenityOS's Shell.
Diffstat (limited to 'Libraries')
-rw-r--r-- | Libraries/LibLine/Editor.cpp | 40 | ||||
-rw-r--r-- | Libraries/LibVT/Terminal.cpp | 20 |
2 files changed, 32 insertions, 28 deletions
diff --git a/Libraries/LibLine/Editor.cpp b/Libraries/LibLine/Editor.cpp index 9a2e271224..7401a93882 100644 --- a/Libraries/LibLine/Editor.cpp +++ b/Libraries/LibLine/Editor.cpp @@ -616,7 +616,6 @@ void Editor::handle_read_event() } auto reverse_tab = false; - auto ctrl_held = false; // Discard starting bytes until they make sense as utf-8. size_t valid_bytes = 0; @@ -635,6 +634,11 @@ void Editor::handle_read_event() Vector<unsigned, 4> csi_parameters; Vector<u8> csi_intermediate_bytes; u8 csi_final; + enum CSIMod { + Shift = 1, + Alt = 2, + Ctrl = 4, + }; for (auto code_point : input_view) { if (m_finish) @@ -677,11 +681,10 @@ void Editor::handle_read_event() } m_state = InputState::CSIExpectFinal; [[fallthrough]]; - case InputState::CSIExpectFinal: + case InputState::CSIExpectFinal: { m_state = InputState::Free; if (!(code_point >= 0x40 && code_point <= 0x7f)) { dbgprintf("LibLine: Invalid CSI: %02x (%c)\r\n", code_point, code_point); - ctrl_held = false; continue; } csi_final = code_point; @@ -692,68 +695,61 @@ void Editor::handle_read_event() else csi_parameters.append(0); } + unsigned param1 = 0, param2 = 0; + if (csi_parameters.size() >= 1) + param1 = csi_parameters[0]; + if (csi_parameters.size() >= 2) + param2 = csi_parameters[1]; + unsigned modifiers = param2 ? param2 - 1 : 0; - if (csi_final == 'O') { - // mod_ctrl - ctrl_held = true; - continue; - } if (csi_final == 'Z') { // 'reverse tab' reverse_tab = true; - ctrl_held = false; break; } cleanup_suggestions(); + switch (csi_final) { case 'A': // ^[[A: arrow up search_backwards(); - ctrl_held = false; continue; case 'B': // ^[[B: arrow down search_forwards(); - ctrl_held = false; continue; case 'D': // ^[[D: arrow left - if (ctrl_held) + if (modifiers == CSIMod::Ctrl) cursor_left_word(); else cursor_left_character(); - ctrl_held = false; continue; case 'C': // ^[[C: arrow right - if (ctrl_held) + if (modifiers == CSIMod::Ctrl) cursor_right_word(); else cursor_right_character(); - ctrl_held = false; continue; case 'H': // ^[[H: home go_home(); - ctrl_held = false; continue; case 'F': // ^[[F: end go_end(); - ctrl_held = false; continue; case '~': - if (csi_parameters.size() == 1 && csi_parameters[0] == 3) { // ^[[3~: delete + if (param1 == 3) { // ^[[3~: delete erase_character_forwards(); m_search_offset = 0; - ctrl_held = false; continue; } // ^[[5~: page up // ^[[6~: page down - dbgprintf("LibLine: Unhandled '~'\r\n"); - ctrl_held = false; + dbgprintf("LibLine: Unhandled '~': %d\r\n", param1); continue; default: dbgprintf("LibLine: Unhandled final: %02x (%c)\r\n", code_point, code_point); - ctrl_held = false; continue; } break; + } case InputState::Free: if (code_point == 27) { m_state = InputState::GotEscape; diff --git a/Libraries/LibVT/Terminal.cpp b/Libraries/LibVT/Terminal.cpp index e1636f4696..1b7aeee0f2 100644 --- a/Libraries/LibVT/Terminal.cpp +++ b/Libraries/LibVT/Terminal.cpp @@ -1026,19 +1026,27 @@ void Terminal::handle_key_press(KeyCode key, u32 code_point, u8 flags) bool ctrl = flags & Mod_Ctrl; bool alt = flags & Mod_Alt; bool shift = flags & Mod_Shift; + unsigned modifier_mask = int(shift) + (int(alt) << 1) + (int(ctrl) << 2); + + auto emit_final_with_modifier = [this, modifier_mask](char final) { + if (modifier_mask) + emit_string(String::format("\e[1;%d%c", modifier_mask + 1, final)); + else + emit_string(String::format("\e[%c", final)); + }; switch (key) { case KeyCode::Key_Up: - emit_string(ctrl ? "\033[OA" : "\033[A"); + emit_final_with_modifier('A'); return; case KeyCode::Key_Down: - emit_string(ctrl ? "\033[OB" : "\033[B"); + emit_final_with_modifier('B'); return; case KeyCode::Key_Right: - emit_string(ctrl ? "\033[OC" : "\033[C"); + emit_final_with_modifier('C'); return; case KeyCode::Key_Left: - emit_string(ctrl ? "\033[OD" : "\033[D"); + emit_final_with_modifier('D'); return; case KeyCode::Key_Insert: emit_string("\033[2~"); @@ -1047,10 +1055,10 @@ void Terminal::handle_key_press(KeyCode key, u32 code_point, u8 flags) emit_string("\033[3~"); return; case KeyCode::Key_Home: - emit_string("\033[H"); + emit_final_with_modifier('H'); return; case KeyCode::Key_End: - emit_string("\033[F"); + emit_final_with_modifier('F'); return; case KeyCode::Key_PageUp: emit_string("\033[5~"); |