summaryrefslogtreecommitdiff
path: root/Libraries
diff options
context:
space:
mode:
authorNico Weber <thakis@chromium.org>2020-09-13 21:08:19 -0400
committerAndreas Kling <kling@serenityos.org>2020-09-15 09:45:13 +0200
commit83c07be794276b82833f22c0b9e8cd3a6b72a291 (patch)
tree1dc97552c016bb812b30841236cbc7dab458094f /Libraries
parent2fe127d96ff9991d13d73e4c26c85cb44efeac99 (diff)
downloadserenity-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.cpp40
-rw-r--r--Libraries/LibVT/Terminal.cpp20
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~");