mirror of
https://github.com/lihop/godot-xterm.git
synced 2024-11-21 17:20:25 +01:00
Move input handling into the Terminal node
Former-commit-id: d64800229f
This commit is contained in:
parent
9d06d7c313
commit
5e33e560f1
6 changed files with 223 additions and 74 deletions
|
@ -11,3 +11,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
### Changed
|
||||
- Implementation of Terminal node from GDScript to GDNative using [Aetf's patched version of libtsm](https://github.com/Aetf/libtsm).
|
||||
- Move input handling to the Terminal node itself, rather than handling it in a seperate Control node.
|
||||
|
|
|
@ -99,7 +99,7 @@ else:
|
|||
cpp_library += '.' + str(bits)
|
||||
|
||||
# make sure our binding library is properly includes
|
||||
env.Append(CPPPATH=['.', godot_headers_path, cpp_bindings_path + 'include/', cpp_bindings_path + 'include/core/', cpp_bindings_path + 'include/gen/', libtsm_path + 'src/tsm'])
|
||||
env.Append(CPPPATH=['.', godot_headers_path, cpp_bindings_path + 'include/', cpp_bindings_path + 'include/core/', cpp_bindings_path + 'include/gen/', libtsm_path + 'src/tsm', libtsm_path + 'external'])
|
||||
env.Append(LIBPATH=[cpp_bindings_path + 'bin/', libtsm_path + 'build/src/tsm'])
|
||||
env.Append(LIBS=[cpp_library, 'tsm', 'util']) # Note util used by pseudoterminal, tsm used by terminal.
|
||||
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
#include "terminal.h"
|
||||
#include <algorithm>
|
||||
#include <GlobalConstants.hpp>
|
||||
#include <InputEventKey.hpp>
|
||||
#include <OS.hpp>
|
||||
#include <Theme.hpp>
|
||||
#include <xkbcommon/xkbcommon-keysyms.h>
|
||||
|
||||
using namespace godot;
|
||||
|
||||
|
@ -27,6 +31,170 @@ const uint8_t Terminal::default_color_palette[TSM_COLOR_NUM][3] = {
|
|||
[TSM_COLOR_BACKGROUND] = {0x00, 0x00, 0x00},
|
||||
};
|
||||
|
||||
const std::map<std::pair<int64_t, int64_t>, uint32_t> Terminal::keymap = {
|
||||
|
||||
// Godot does not have seperate scancodes for keypad keys when NumLock is off.
|
||||
// We can check the unicode value to determine whether it is off and set the
|
||||
// appropriate scancode.
|
||||
// Based on the patch which adds support for this to TextEdit/LineEdit:
|
||||
// https://github.com/godotengine/godot/pull/3269/files
|
||||
{{'0', GlobalConstants::KEY_KP_0}, XKB_KEY_KP_0},
|
||||
{{0b0, GlobalConstants::KEY_KP_0}, XKB_KEY_KP_Insert},
|
||||
{{'1', GlobalConstants::KEY_KP_1}, XKB_KEY_KP_1},
|
||||
{{0b0, GlobalConstants::KEY_KP_1}, XKB_KEY_KP_End},
|
||||
{{'2', GlobalConstants::KEY_KP_2}, XKB_KEY_KP_2},
|
||||
{{0b0, GlobalConstants::KEY_KP_2}, XKB_KEY_KP_Down},
|
||||
{{'3', GlobalConstants::KEY_KP_3}, XKB_KEY_KP_3},
|
||||
{{0b0, GlobalConstants::KEY_KP_3}, XKB_KEY_KP_Page_Down},
|
||||
{{'4', GlobalConstants::KEY_KP_4}, XKB_KEY_KP_4},
|
||||
{{0b0, GlobalConstants::KEY_KP_4}, XKB_KEY_KP_Left},
|
||||
{{'5', GlobalConstants::KEY_KP_5}, XKB_KEY_KP_5},
|
||||
{{0b0, GlobalConstants::KEY_KP_5}, XKB_KEY_KP_Begin},
|
||||
{{'6', GlobalConstants::KEY_KP_6}, XKB_KEY_KP_6},
|
||||
{{0b0, GlobalConstants::KEY_KP_6}, XKB_KEY_KP_Right},
|
||||
{{'7', GlobalConstants::KEY_KP_7}, XKB_KEY_KP_7},
|
||||
{{0b0, GlobalConstants::KEY_KP_7}, XKB_KEY_KP_Home},
|
||||
{{'8', GlobalConstants::KEY_KP_8}, XKB_KEY_KP_8},
|
||||
{{0b0, GlobalConstants::KEY_KP_8}, XKB_KEY_KP_Up},
|
||||
{{'9', GlobalConstants::KEY_KP_9}, XKB_KEY_KP_9},
|
||||
{{0b0, GlobalConstants::KEY_KP_9}, XKB_KEY_KP_Page_Up},
|
||||
{{'.', GlobalConstants::KEY_KP_PERIOD}, XKB_KEY_KP_Decimal},
|
||||
{{0b0, GlobalConstants::KEY_KP_PERIOD}, XKB_KEY_KP_Delete},
|
||||
{{'/', GlobalConstants::KEY_KP_DIVIDE}, XKB_KEY_KP_Divide},
|
||||
{{'*', GlobalConstants::KEY_KP_MULTIPLY}, XKB_KEY_KP_Multiply},
|
||||
{{'-', GlobalConstants::KEY_KP_SUBTRACT}, XKB_KEY_KP_Subtract},
|
||||
{{'+', GlobalConstants::KEY_KP_ADD}, XKB_KEY_KP_Add},
|
||||
{{0b0, GlobalConstants::KEY_KP_ENTER}, XKB_KEY_KP_Enter},
|
||||
//{{ , }, XKB_KEY_KP_Equal},
|
||||
//{{ , }, XKB_KEY_KP_Separator},
|
||||
//{{ , }, XKB_KEY_KP_Tab},
|
||||
//{{ , }, XKB_KEY_KP_F1},
|
||||
//{{ , }, XKB_KEY_KP_F2},
|
||||
//{{ , }, XKB_KEY_KP_F3},
|
||||
//{{ , }, XKB_KEY_KP_F4},
|
||||
|
||||
// Godot scancodes do not distinguish between uppercase and lowercase
|
||||
// letters, so we can check the unicode value to determine this.
|
||||
{{'a', GlobalConstants::KEY_A}, XKB_KEY_a},
|
||||
{{'A', GlobalConstants::KEY_A}, XKB_KEY_A},
|
||||
{{'b', GlobalConstants::KEY_B}, XKB_KEY_b},
|
||||
{{'B', GlobalConstants::KEY_B}, XKB_KEY_B},
|
||||
{{'c', GlobalConstants::KEY_C}, XKB_KEY_c},
|
||||
{{'C', GlobalConstants::KEY_C}, XKB_KEY_C},
|
||||
{{'d', GlobalConstants::KEY_D}, XKB_KEY_d},
|
||||
{{'D', GlobalConstants::KEY_D}, XKB_KEY_D},
|
||||
{{'e', GlobalConstants::KEY_E}, XKB_KEY_e},
|
||||
{{'E', GlobalConstants::KEY_E}, XKB_KEY_E},
|
||||
{{'f', GlobalConstants::KEY_F}, XKB_KEY_f},
|
||||
{{'F', GlobalConstants::KEY_F}, XKB_KEY_F},
|
||||
{{'g', GlobalConstants::KEY_G}, XKB_KEY_g},
|
||||
{{'G', GlobalConstants::KEY_G}, XKB_KEY_G},
|
||||
{{'h', GlobalConstants::KEY_H}, XKB_KEY_h},
|
||||
{{'H', GlobalConstants::KEY_H}, XKB_KEY_H},
|
||||
{{'i', GlobalConstants::KEY_I}, XKB_KEY_i},
|
||||
{{'I', GlobalConstants::KEY_I}, XKB_KEY_I},
|
||||
{{'j', GlobalConstants::KEY_J}, XKB_KEY_j},
|
||||
{{'J', GlobalConstants::KEY_J}, XKB_KEY_J},
|
||||
{{'k', GlobalConstants::KEY_K}, XKB_KEY_k},
|
||||
{{'K', GlobalConstants::KEY_K}, XKB_KEY_K},
|
||||
{{'l', GlobalConstants::KEY_L}, XKB_KEY_l},
|
||||
{{'L', GlobalConstants::KEY_L}, XKB_KEY_L},
|
||||
{{'m', GlobalConstants::KEY_M}, XKB_KEY_m},
|
||||
{{'M', GlobalConstants::KEY_M}, XKB_KEY_M},
|
||||
{{'n', GlobalConstants::KEY_N}, XKB_KEY_n},
|
||||
{{'N', GlobalConstants::KEY_N}, XKB_KEY_N},
|
||||
{{'o', GlobalConstants::KEY_O}, XKB_KEY_o},
|
||||
{{'O', GlobalConstants::KEY_O}, XKB_KEY_O},
|
||||
{{'p', GlobalConstants::KEY_P}, XKB_KEY_p},
|
||||
{{'P', GlobalConstants::KEY_P}, XKB_KEY_P},
|
||||
{{'q', GlobalConstants::KEY_Q}, XKB_KEY_q},
|
||||
{{'Q', GlobalConstants::KEY_Q}, XKB_KEY_Q},
|
||||
{{'r', GlobalConstants::KEY_R}, XKB_KEY_r},
|
||||
{{'R', GlobalConstants::KEY_R}, XKB_KEY_R},
|
||||
{{'s', GlobalConstants::KEY_S}, XKB_KEY_s},
|
||||
{{'S', GlobalConstants::KEY_S}, XKB_KEY_S},
|
||||
{{'t', GlobalConstants::KEY_T}, XKB_KEY_t},
|
||||
{{'T', GlobalConstants::KEY_T}, XKB_KEY_T},
|
||||
{{'u', GlobalConstants::KEY_U}, XKB_KEY_u},
|
||||
{{'U', GlobalConstants::KEY_U}, XKB_KEY_U},
|
||||
{{'v', GlobalConstants::KEY_V}, XKB_KEY_v},
|
||||
{{'V', GlobalConstants::KEY_V}, XKB_KEY_V},
|
||||
{{'w', GlobalConstants::KEY_W}, XKB_KEY_w},
|
||||
{{'W', GlobalConstants::KEY_W}, XKB_KEY_W},
|
||||
{{'x', GlobalConstants::KEY_X}, XKB_KEY_x},
|
||||
{{'X', GlobalConstants::KEY_X}, XKB_KEY_X},
|
||||
{{'y', GlobalConstants::KEY_Y}, XKB_KEY_y},
|
||||
{{'Y', GlobalConstants::KEY_Y}, XKB_KEY_Y},
|
||||
{{'z', GlobalConstants::KEY_Z}, XKB_KEY_z},
|
||||
{{'Z', GlobalConstants::KEY_Z}, XKB_KEY_Z},
|
||||
|
||||
{{'0', GlobalConstants::KEY_0}, XKB_KEY_0},
|
||||
{{'1', GlobalConstants::KEY_1}, XKB_KEY_1},
|
||||
{{'2', GlobalConstants::KEY_2}, XKB_KEY_2},
|
||||
{{'3', GlobalConstants::KEY_3}, XKB_KEY_3},
|
||||
{{'4', GlobalConstants::KEY_4}, XKB_KEY_4},
|
||||
{{'5', GlobalConstants::KEY_5}, XKB_KEY_5},
|
||||
{{'6', GlobalConstants::KEY_6}, XKB_KEY_6},
|
||||
{{'7', GlobalConstants::KEY_7}, XKB_KEY_7},
|
||||
{{'8', GlobalConstants::KEY_8}, XKB_KEY_8},
|
||||
{{'9', GlobalConstants::KEY_9}, XKB_KEY_9},
|
||||
|
||||
{{'[', GlobalConstants::KEY_BRACKETLEFT}, XKB_KEY_bracketleft},
|
||||
{{'[', GlobalConstants::KEY_BRACKETLEFT}, XKB_KEY_bracketright},
|
||||
{{'{', GlobalConstants::KEY_BRACELEFT}, XKB_KEY_braceleft},
|
||||
{{'}', GlobalConstants::KEY_BRACERIGHT}, XKB_KEY_braceright},
|
||||
|
||||
{{'\\', GlobalConstants::KEY_BACKSLASH}, XKB_KEY_backslash},
|
||||
{{'|', GlobalConstants::KEY_BAR}, XKB_KEY_bar},
|
||||
{{'`', GlobalConstants::KEY_QUOTELEFT}, XKB_KEY_grave},
|
||||
{{'~', GlobalConstants::KEY_ASCIITILDE}, XKB_KEY_asciitilde},
|
||||
{{'/', GlobalConstants::KEY_SLASH}, XKB_KEY_slash},
|
||||
{{'?', GlobalConstants::KEY_QUESTION}, XKB_KEY_question},
|
||||
|
||||
{{0, GlobalConstants::KEY_HOME}, XKB_KEY_Home},
|
||||
{{0, GlobalConstants::KEY_BACKSPACE}, XKB_KEY_BackSpace},
|
||||
{{0, GlobalConstants::KEY_BACKTAB}, XKB_KEY_ISO_Left_Tab},
|
||||
{{0, GlobalConstants::KEY_CLEAR}, XKB_KEY_Clear},
|
||||
{{0, GlobalConstants::KEY_PAUSE}, XKB_KEY_Pause},
|
||||
{{0, GlobalConstants::KEY_SCROLLLOCK}, XKB_KEY_Scroll_Lock},
|
||||
{{0, GlobalConstants::KEY_SYSREQ}, XKB_KEY_Sys_Req},
|
||||
{{0, GlobalConstants::KEY_ESCAPE}, XKB_KEY_Escape},
|
||||
{{0, GlobalConstants::KEY_ENTER}, XKB_KEY_Return},
|
||||
{{0, GlobalConstants::KEY_INSERT}, XKB_KEY_Insert},
|
||||
{{0, GlobalConstants::KEY_DELETE}, XKB_KEY_Delete},
|
||||
{{0, GlobalConstants::KEY_PAGEUP}, XKB_KEY_Page_Up},
|
||||
{{0, GlobalConstants::KEY_PAGEDOWN}, XKB_KEY_Page_Down},
|
||||
{{0, GlobalConstants::KEY_UP}, XKB_KEY_Up},
|
||||
{{0, GlobalConstants::KEY_DOWN}, XKB_KEY_Down},
|
||||
{{0, GlobalConstants::KEY_RIGHT}, XKB_KEY_Right},
|
||||
{{0, GlobalConstants::KEY_LEFT}, XKB_KEY_Left},
|
||||
{{0, GlobalConstants::KEY_TAB}, XKB_KEY_Tab},
|
||||
//{{ , }, XKB_KEY_Linefeed},
|
||||
//{{ , }, XKB_KEY_Find},
|
||||
//{{ , }, XKB_KEY_Select},
|
||||
|
||||
{{0, GlobalConstants::KEY_F1}, XKB_KEY_F1},
|
||||
{{0, GlobalConstants::KEY_F2}, XKB_KEY_F2},
|
||||
{{0, GlobalConstants::KEY_F3}, XKB_KEY_F3},
|
||||
{{0, GlobalConstants::KEY_F4}, XKB_KEY_F4},
|
||||
{{0, GlobalConstants::KEY_F5}, XKB_KEY_F5},
|
||||
{{0, GlobalConstants::KEY_F6}, XKB_KEY_F6},
|
||||
{{0, GlobalConstants::KEY_F7}, XKB_KEY_F7},
|
||||
{{0, GlobalConstants::KEY_F8}, XKB_KEY_F8},
|
||||
{{0, GlobalConstants::KEY_F9}, XKB_KEY_F9},
|
||||
{{0, GlobalConstants::KEY_F10}, XKB_KEY_F10},
|
||||
{{0, GlobalConstants::KEY_F11}, XKB_KEY_F11},
|
||||
{{0, GlobalConstants::KEY_F12}, XKB_KEY_F12},
|
||||
{{0, GlobalConstants::KEY_F13}, XKB_KEY_F13},
|
||||
{{0, GlobalConstants::KEY_F14}, XKB_KEY_F14},
|
||||
{{0, GlobalConstants::KEY_F15}, XKB_KEY_F15},
|
||||
{{0, GlobalConstants::KEY_F16}, XKB_KEY_F16},
|
||||
//{{0, GlobalConstants::KEY_F17}, XKB_KEY_F17},
|
||||
//{{0, GlobalConstants::KEY_F18}, XKB_KEY_F18},
|
||||
//{{0, GlobalConstants::KEY_F19}, XKB_KEY_F19},
|
||||
//{{0, GlobalConstants::KEY_F20}, XKB_KEY_F20},
|
||||
};
|
||||
|
||||
static struct
|
||||
{
|
||||
Color col;
|
||||
|
@ -41,6 +209,13 @@ static void write_cb(struct tsm_vte *vte, const char *u8, size_t len, void *data
|
|||
{
|
||||
|
||||
Terminal *term = static_cast<Terminal *>(data);
|
||||
|
||||
PoolByteArray bytes = PoolByteArray();
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
bytes.append(u8[i]);
|
||||
|
||||
term->emit_signal("data_read", bytes);
|
||||
}
|
||||
|
||||
static int text_draw_cb(struct tsm_screen *con,
|
||||
|
@ -86,7 +261,7 @@ void Terminal::_register_methods()
|
|||
|
||||
register_method("_init", &Terminal::_init);
|
||||
register_method("_ready", &Terminal::_ready);
|
||||
register_method("_input", &Terminal::_input);
|
||||
register_method("_gui_input", &Terminal::_gui_input);
|
||||
register_method("_draw", &Terminal::_draw);
|
||||
|
||||
register_method("write", &Terminal::write);
|
||||
|
@ -94,6 +269,8 @@ void Terminal::_register_methods()
|
|||
|
||||
//register_property<Terminal, int>("rows", &Terminal::rows, 24);
|
||||
//register_property<Terminal, int>("cols", &Terminal::cols, 80);
|
||||
|
||||
register_signal<Terminal>("data_read", "data", GODOT_VARIANT_TYPE_POOL_BYTE_ARRAY);
|
||||
}
|
||||
|
||||
Terminal::Terminal()
|
||||
|
@ -148,8 +325,34 @@ void Terminal::_notification(int what)
|
|||
}
|
||||
}
|
||||
|
||||
void Terminal::_input(Variant event)
|
||||
void Terminal::_gui_input(Variant event)
|
||||
{
|
||||
Ref<InputEventKey> k = event;
|
||||
|
||||
if (k.is_valid())
|
||||
{
|
||||
if (!k->is_pressed())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t scancode = k->get_scancode();
|
||||
int64_t unicode = k->get_unicode();
|
||||
uint32_t ascii = unicode <= 127 ? unicode : 0;
|
||||
|
||||
unsigned int mods = 0;
|
||||
if (k->get_alt())
|
||||
mods |= TSM_ALT_MASK;
|
||||
if (k->get_control())
|
||||
mods |= TSM_CONTROL_MASK;
|
||||
if (k->get_shift())
|
||||
mods |= TSM_SHIFT_MASK;
|
||||
|
||||
auto iter = keymap.find({unicode, scancode});
|
||||
uint32_t keysym = (iter != keymap.end() ? iter->second : XKB_KEY_NoSymbol);
|
||||
|
||||
tsm_vte_handle_keyboard(vte, keysym, ascii, mods, unicode ? unicode : TSM_VTE_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
void Terminal::_draw()
|
||||
|
|
|
@ -34,6 +34,7 @@ namespace godot
|
|||
|
||||
private:
|
||||
static const uint8_t default_color_palette[TSM_COLOR_NUM][3];
|
||||
static const std::map<std::pair<int64_t, int64_t>, uint32_t> keymap;
|
||||
|
||||
Vector2 cell_size;
|
||||
std::map<int, Color> palette = {};
|
||||
|
@ -54,7 +55,7 @@ namespace godot
|
|||
void _init();
|
||||
void _ready();
|
||||
void _notification(int what);
|
||||
void _input(Variant event);
|
||||
void _gui_input(Variant event);
|
||||
void _draw();
|
||||
|
||||
void write(PoolByteArray bytes);
|
||||
|
|
|
@ -1,23 +1,22 @@
|
|||
[gd_scene load_steps=5 format=2]
|
||||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_xterm/nodes/terminal/terminal.gdns" type="Script" id=1]
|
||||
[ext_resource path="res://addons/godot_xterm/themes/default.theme" type="Theme" id=2]
|
||||
[ext_resource path="res://addons/godot_xterm/nodes/pseudoterminal/pseudoterminal.gdns" type="Script" id=3]
|
||||
[ext_resource path="res://examples/terminal/container.gd" type="Script" id=4]
|
||||
[ext_resource path="res://addons/godot_xterm/nodes/pseudoterminal/pseudoterminal.gdns" type="Script" id=2]
|
||||
[ext_resource path="res://addons/godot_xterm/themes/default.theme" type="Theme" id=4]
|
||||
|
||||
[node name="Container" type="Container"]
|
||||
margin_right = 40.0
|
||||
margin_bottom = 40.0
|
||||
script = ExtResource( 4 )
|
||||
[node name="Terminal" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
focus_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
theme = ExtResource( 4 )
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Terminal" type="Control" parent="."]
|
||||
margin_right = 40.0
|
||||
margin_bottom = 40.0
|
||||
theme = ExtResource( 2 )
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="Pseudoterminal" type="Node" parent="."]
|
||||
script = ExtResource( 3 )
|
||||
script = ExtResource( 2 )
|
||||
[connection signal="data_read" from="." to="Pseudoterminal" method="put_data"]
|
||||
[connection signal="data_received" from="Pseudoterminal" to="." method="write"]
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
extends Container
|
||||
# This Container ensures that the terminal always fills
|
||||
# the window and/or screen. It also connects the terminal
|
||||
# to the input/output of the Psuedoterminal.
|
||||
|
||||
const ESCAPE = 27
|
||||
const BACKSPACE = 8
|
||||
const BEEP = 7
|
||||
const SPACE = 32
|
||||
const LEFT_BRACKET = 91
|
||||
const ENTER = 10
|
||||
const BACKSPACE_ALT = 127
|
||||
|
||||
onready var viewport = get_viewport()
|
||||
|
||||
func _ready():
|
||||
$Pseudoterminal.connect("data_received", $Terminal, "write")
|
||||
|
||||
viewport.connect("size_changed", self, "_resize")
|
||||
_resize()
|
||||
|
||||
|
||||
func _input(event):
|
||||
#return
|
||||
if event is InputEventKey and event.pressed:
|
||||
var data = PoolByteArray([])
|
||||
accept_event()
|
||||
|
||||
# TODO: Handle more of these.
|
||||
if (event.control and event.scancode == KEY_C):
|
||||
data.append(3)
|
||||
elif event.unicode:
|
||||
data.append(event.unicode)
|
||||
elif event.scancode == KEY_ENTER:
|
||||
data.append(ENTER)
|
||||
elif event.scancode == KEY_BACKSPACE:
|
||||
data.append(BACKSPACE_ALT)
|
||||
elif event.scancode == KEY_ESCAPE:
|
||||
data.append(27)
|
||||
elif event.scancode == KEY_TAB:
|
||||
data.append(9)
|
||||
elif OS.get_scancode_string(event.scancode) == "Shift":
|
||||
pass
|
||||
elif OS.get_scancode_string(event.scancode) == "Control":
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
#push_warning('Unhandled input. scancode: ' + str(OS.get_scancode_string(event.scancode)))
|
||||
#emit_signal("output", data)
|
||||
$Pseudoterminal.put_data(data)
|
||||
|
||||
|
||||
func _resize():
|
||||
rect_size = viewport.size
|
||||
$Terminal.rect_size = rect_size
|
Loading…
Reference in a new issue