diff --git a/addons/godot_xterm/native/src/terminal.cpp b/addons/godot_xterm/native/src/terminal.cpp index b7b318a..42dd004 100644 --- a/addons/godot_xterm/native/src/terminal.cpp +++ b/addons/godot_xterm/native/src/terminal.cpp @@ -25,6 +25,8 @@ using namespace godot; void Terminal::_bind_methods() { + ADD_SIGNAL(MethodInfo("key_pressed", PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data"), PropertyInfo(Variant::OBJECT, "event"))); + ClassDB::bind_method(D_METHOD("get_cols"), &Terminal::get_cols); ClassDB::bind_method(D_METHOD("set_cols", "cols"), &Terminal::set_cols); ClassDB::add_property("Terminal", PropertyInfo(Variant::INT, "cols"), "set_cols", "get_cols"); @@ -218,10 +220,15 @@ void Terminal::_write_cb(tsm_vte *vte, const char *u8, size_t len, void *data) Terminal *term = static_cast(data); if (len > 0) { - size_t old_size = term->response.size(); - term->response.resize(old_size + len); - uint8_t *dest = term->response.ptrw() + old_size; - memcpy(dest, u8, len); + PackedByteArray data; + data.resize(len); + memcpy(data.ptrw(), u8, len); + term->response.append_array(data); + + if (term->last_input_event_key.is_valid()) { + term->emit_signal("key_pressed", data.get_string_from_utf8(), term->last_input_event_key); + term->last_input_event_key.unref(); + } } } diff --git a/test/test_rendering.gd b/test/test_rendering.gd index a80fa66..5503838 100644 --- a/test/test_rendering.gd +++ b/test/test_rendering.gd @@ -17,6 +17,7 @@ func before_each(): terminal = Terminal.new() terminal.add_theme_font_override("normal_font", preload("res://themes/fonts/regular.tres")) terminal.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) + watch_signals(terminal) call_deferred("add_child_autofree", terminal) await wait_for_signal(terminal.ready, 5) @@ -33,3 +34,57 @@ class TestRendering: await wait_frames(15) var cell_color = pick_cell_color(Vector2i(0, 0)) assert_eq(cell_color, Color.RED) + + +class TestKeyPressed: + extends RenderingTest + + var input_event: InputEventKey + + func before_each(): + await super.before_each() + + terminal.grab_focus() + + input_event = InputEventKey.new() + input_event.pressed = true + Input.call_deferred("parse_input_event", input_event) + + func test_key_pressed_emitted_on_key_input(): + input_event.keycode = KEY_A + input_event.unicode = "a".unicode_at(0) + + await wait_for_signal(terminal.key_pressed, 1) + assert_signal_emitted(terminal, "key_pressed") + + func test_key_pressed_emits_interpreted_key_input_as_first_param(): + input_event.keycode = KEY_UP + input_event.unicode = 0 + + await wait_for_signal(terminal.key_pressed, 1) + + var signal_parameters = get_signal_parameters(terminal, "key_pressed", 0) + assert_eq(signal_parameters[0], "\u001b[A") + + func test_key_pressed_emits_original_input_event_as_second_param(): + input_event.keycode = KEY_L + input_event.unicode = "l".unicode_at(0) + + await wait_for_signal(terminal.key_pressed, 1) + + var signal_parameters = get_signal_parameters(terminal, "key_pressed", 0) + assert_eq(signal_parameters[1], input_event) + + func test_key_pressed_not_emitted_when_writing_to_terminal(): + terminal.write("a") + await wait_frames(1) + assert_signal_emit_count(terminal, "key_pressed", 0) + + func test_key_pressed_not_emitted_by_other_input_type(): + var mouse_input = InputEventMouseButton.new() + mouse_input.button_index = MOUSE_BUTTON_LEFT + mouse_input.pressed = true + Input.call_deferred("parse_input_event", mouse_input) + + await wait_for_signal(terminal.gui_input, 1) + assert_signal_emit_count(terminal, "key_pressed", 0) diff --git a/test/test_terminal.gd b/test/test_terminal.gd index 8d50d30..03d8805 100644 --- a/test/test_terminal.gd +++ b/test/test_terminal.gd @@ -60,3 +60,19 @@ class TestCursorPos: func test_get_cursor_pos_y(): terminal.write("_".repeat(terminal.cols + 1)) assert_eq(terminal.get_cursor_pos().y, 1) + + +class TestWrite: + extends TerminalTest + + func test_returns_response_when_input_contains_query(): + var response = terminal.write("\u001b[6n") # Query cursor position. + assert_eq(response, "\u001b[1;1R") + + func test_returns_response_to_multiple_queries(): + var response = terminal.write("\u001b[6n\u001b[5n") # Query cursor position and status. + assert_eq(response, "\u001b[1;1R\u001b[0n") + + func test_returns_response_to_multiple_queries_among_other_data(): + var response = terminal.write("hello\r\nworld\u001b[6nother\r\ndata\u001b[5ntest") + assert_eq(response, "\u001b[2;6R\u001b[0n")