mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 16:37:35 +00:00
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.
This commit is contained in:
parent
2fe127d96f
commit
83c07be794
2 changed files with 32 additions and 28 deletions
|
@ -616,7 +616,6 @@ void Editor::handle_read_event()
|
||||||
}
|
}
|
||||||
|
|
||||||
auto reverse_tab = false;
|
auto reverse_tab = false;
|
||||||
auto ctrl_held = false;
|
|
||||||
|
|
||||||
// Discard starting bytes until they make sense as utf-8.
|
// Discard starting bytes until they make sense as utf-8.
|
||||||
size_t valid_bytes = 0;
|
size_t valid_bytes = 0;
|
||||||
|
@ -635,6 +634,11 @@ void Editor::handle_read_event()
|
||||||
Vector<unsigned, 4> csi_parameters;
|
Vector<unsigned, 4> csi_parameters;
|
||||||
Vector<u8> csi_intermediate_bytes;
|
Vector<u8> csi_intermediate_bytes;
|
||||||
u8 csi_final;
|
u8 csi_final;
|
||||||
|
enum CSIMod {
|
||||||
|
Shift = 1,
|
||||||
|
Alt = 2,
|
||||||
|
Ctrl = 4,
|
||||||
|
};
|
||||||
|
|
||||||
for (auto code_point : input_view) {
|
for (auto code_point : input_view) {
|
||||||
if (m_finish)
|
if (m_finish)
|
||||||
|
@ -677,11 +681,10 @@ void Editor::handle_read_event()
|
||||||
}
|
}
|
||||||
m_state = InputState::CSIExpectFinal;
|
m_state = InputState::CSIExpectFinal;
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case InputState::CSIExpectFinal:
|
case InputState::CSIExpectFinal: {
|
||||||
m_state = InputState::Free;
|
m_state = InputState::Free;
|
||||||
if (!(code_point >= 0x40 && code_point <= 0x7f)) {
|
if (!(code_point >= 0x40 && code_point <= 0x7f)) {
|
||||||
dbgprintf("LibLine: Invalid CSI: %02x (%c)\r\n", code_point, code_point);
|
dbgprintf("LibLine: Invalid CSI: %02x (%c)\r\n", code_point, code_point);
|
||||||
ctrl_held = false;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
csi_final = code_point;
|
csi_final = code_point;
|
||||||
|
@ -692,68 +695,61 @@ void Editor::handle_read_event()
|
||||||
else
|
else
|
||||||
csi_parameters.append(0);
|
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') {
|
if (csi_final == 'Z') {
|
||||||
// 'reverse tab'
|
// 'reverse tab'
|
||||||
reverse_tab = true;
|
reverse_tab = true;
|
||||||
ctrl_held = false;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cleanup_suggestions();
|
cleanup_suggestions();
|
||||||
|
|
||||||
switch (csi_final) {
|
switch (csi_final) {
|
||||||
case 'A': // ^[[A: arrow up
|
case 'A': // ^[[A: arrow up
|
||||||
search_backwards();
|
search_backwards();
|
||||||
ctrl_held = false;
|
|
||||||
continue;
|
continue;
|
||||||
case 'B': // ^[[B: arrow down
|
case 'B': // ^[[B: arrow down
|
||||||
search_forwards();
|
search_forwards();
|
||||||
ctrl_held = false;
|
|
||||||
continue;
|
continue;
|
||||||
case 'D': // ^[[D: arrow left
|
case 'D': // ^[[D: arrow left
|
||||||
if (ctrl_held)
|
if (modifiers == CSIMod::Ctrl)
|
||||||
cursor_left_word();
|
cursor_left_word();
|
||||||
else
|
else
|
||||||
cursor_left_character();
|
cursor_left_character();
|
||||||
ctrl_held = false;
|
|
||||||
continue;
|
continue;
|
||||||
case 'C': // ^[[C: arrow right
|
case 'C': // ^[[C: arrow right
|
||||||
if (ctrl_held)
|
if (modifiers == CSIMod::Ctrl)
|
||||||
cursor_right_word();
|
cursor_right_word();
|
||||||
else
|
else
|
||||||
cursor_right_character();
|
cursor_right_character();
|
||||||
ctrl_held = false;
|
|
||||||
continue;
|
continue;
|
||||||
case 'H': // ^[[H: home
|
case 'H': // ^[[H: home
|
||||||
go_home();
|
go_home();
|
||||||
ctrl_held = false;
|
|
||||||
continue;
|
continue;
|
||||||
case 'F': // ^[[F: end
|
case 'F': // ^[[F: end
|
||||||
go_end();
|
go_end();
|
||||||
ctrl_held = false;
|
|
||||||
continue;
|
continue;
|
||||||
case '~':
|
case '~':
|
||||||
if (csi_parameters.size() == 1 && csi_parameters[0] == 3) { // ^[[3~: delete
|
if (param1 == 3) { // ^[[3~: delete
|
||||||
erase_character_forwards();
|
erase_character_forwards();
|
||||||
m_search_offset = 0;
|
m_search_offset = 0;
|
||||||
ctrl_held = false;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// ^[[5~: page up
|
// ^[[5~: page up
|
||||||
// ^[[6~: page down
|
// ^[[6~: page down
|
||||||
dbgprintf("LibLine: Unhandled '~'\r\n");
|
dbgprintf("LibLine: Unhandled '~': %d\r\n", param1);
|
||||||
ctrl_held = false;
|
|
||||||
continue;
|
continue;
|
||||||
default:
|
default:
|
||||||
dbgprintf("LibLine: Unhandled final: %02x (%c)\r\n", code_point, code_point);
|
dbgprintf("LibLine: Unhandled final: %02x (%c)\r\n", code_point, code_point);
|
||||||
ctrl_held = false;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case InputState::Free:
|
case InputState::Free:
|
||||||
if (code_point == 27) {
|
if (code_point == 27) {
|
||||||
m_state = InputState::GotEscape;
|
m_state = InputState::GotEscape;
|
||||||
|
|
|
@ -1026,19 +1026,27 @@ void Terminal::handle_key_press(KeyCode key, u32 code_point, u8 flags)
|
||||||
bool ctrl = flags & Mod_Ctrl;
|
bool ctrl = flags & Mod_Ctrl;
|
||||||
bool alt = flags & Mod_Alt;
|
bool alt = flags & Mod_Alt;
|
||||||
bool shift = flags & Mod_Shift;
|
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) {
|
switch (key) {
|
||||||
case KeyCode::Key_Up:
|
case KeyCode::Key_Up:
|
||||||
emit_string(ctrl ? "\033[OA" : "\033[A");
|
emit_final_with_modifier('A');
|
||||||
return;
|
return;
|
||||||
case KeyCode::Key_Down:
|
case KeyCode::Key_Down:
|
||||||
emit_string(ctrl ? "\033[OB" : "\033[B");
|
emit_final_with_modifier('B');
|
||||||
return;
|
return;
|
||||||
case KeyCode::Key_Right:
|
case KeyCode::Key_Right:
|
||||||
emit_string(ctrl ? "\033[OC" : "\033[C");
|
emit_final_with_modifier('C');
|
||||||
return;
|
return;
|
||||||
case KeyCode::Key_Left:
|
case KeyCode::Key_Left:
|
||||||
emit_string(ctrl ? "\033[OD" : "\033[D");
|
emit_final_with_modifier('D');
|
||||||
return;
|
return;
|
||||||
case KeyCode::Key_Insert:
|
case KeyCode::Key_Insert:
|
||||||
emit_string("\033[2~");
|
emit_string("\033[2~");
|
||||||
|
@ -1047,10 +1055,10 @@ void Terminal::handle_key_press(KeyCode key, u32 code_point, u8 flags)
|
||||||
emit_string("\033[3~");
|
emit_string("\033[3~");
|
||||||
return;
|
return;
|
||||||
case KeyCode::Key_Home:
|
case KeyCode::Key_Home:
|
||||||
emit_string("\033[H");
|
emit_final_with_modifier('H');
|
||||||
return;
|
return;
|
||||||
case KeyCode::Key_End:
|
case KeyCode::Key_End:
|
||||||
emit_string("\033[F");
|
emit_final_with_modifier('F');
|
||||||
return;
|
return;
|
||||||
case KeyCode::Key_PageUp:
|
case KeyCode::Key_PageUp:
|
||||||
emit_string("\033[5~");
|
emit_string("\033[5~");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue