summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbruvzg <7645683+bruvzg@users.noreply.github.com>2024-09-05 10:52:29 +0300
committerbruvzg <7645683+bruvzg@users.noreply.github.com>2024-09-12 11:47:24 +0300
commitb776f55bcb8c360e8c5a969a8c21f4ae4753954d (patch)
treeb44704207bd8a325142c2afd4175b98299701d4b
parentb214aa8faff745ad08c2b2109cc553782ac81d05 (diff)
downloadredot-engine-b776f55bcb8c360e8c5a969a8c21f4ae4753954d.tar.gz
Add Control+Shift+U (rebindabe) action for Unicode input, show hex as it is entered.
-rw-r--r--core/input/input_map.cpp5
-rw-r--r--doc/classes/LineEdit.xml18
-rw-r--r--doc/classes/ProjectSettings.xml4
-rw-r--r--scene/gui/line_edit.cpp233
-rw-r--r--scene/gui/line_edit.h8
-rw-r--r--scene/gui/text_edit.cpp134
-rw-r--r--scene/gui/text_edit.h1
7 files changed, 307 insertions, 96 deletions
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index ddeee9d765..9a772c87c9 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -400,6 +400,7 @@ static const _BuiltinActionDisplayName _builtin_action_display_names[] = {
{ "ui_filedialog_refresh", TTRC("Refresh") },
{ "ui_filedialog_show_hidden", TTRC("Show Hidden") },
{ "ui_swap_input_direction ", TTRC("Swap Input Direction") },
+ { "ui_unicode_start", TTRC("Start Unicode Character Input") },
{ "", ""}
/* clang-format on */
};
@@ -754,6 +755,10 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER));
default_builtin_cache.insert("ui_text_submit", inputs);
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(Key::U | KeyModifierMask::CTRL | KeyModifierMask::SHIFT));
+ default_builtin_cache.insert("ui_unicode_start", inputs);
+
// ///// UI Graph Shortcuts /////
inputs = List<Ref<InputEvent>>();
diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml
index a37dd47914..d218f720a3 100644
--- a/doc/classes/LineEdit.xml
+++ b/doc/classes/LineEdit.xml
@@ -37,6 +37,18 @@
<tutorials>
</tutorials>
<methods>
+ <method name="apply_ime">
+ <return type="void" />
+ <description>
+ Applies text from the [url=https://en.wikipedia.org/wiki/Input_method]Input Method Editor[/url] (IME) and closes the IME if it is open.
+ </description>
+ </method>
+ <method name="cancel_ime">
+ <return type="void" />
+ <description>
+ Closes the [url=https://en.wikipedia.org/wiki/Input_method]Input Method Editor[/url] (IME) if it is open. Any text in the IME will be lost.
+ </description>
+ </method>
<method name="clear">
<return type="void" />
<description>
@@ -133,6 +145,12 @@
Returns the selection end column.
</description>
</method>
+ <method name="has_ime_text" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if the user has text in the [url=https://en.wikipedia.org/wiki/Input_method]Input Method Editor[/url] (IME).
+ </description>
+ </method>
<method name="has_selection" qualifiers="const">
<return type="bool" />
<description>
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 80a4ca9a8a..b205b862a3 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -1386,6 +1386,10 @@
Default [InputEventAction] to undo the most recent action.
[b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
+ <member name="input/ui_unicode_start" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to start Unicode character hexadecimal code input in a text field.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
+ </member>
<member name="input/ui_up" type="Dictionary" setter="" getter="">
Default [InputEventAction] to move up in the UI.
[b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 3b5d4fc33e..1a066b0728 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -61,16 +61,6 @@ void LineEdit::_edit() {
editing = true;
_validate_caret_can_draw();
- DisplayServer::WindowID wid = get_window() ? get_window()->get_window_id() : DisplayServer::INVALID_WINDOW_ID;
- if (wid != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
- DisplayServer::get_singleton()->window_set_ime_active(true, wid);
- Point2 pos = Point2(get_caret_pixel_pos().x, (get_size().y + theme_cache.font->get_height(theme_cache.font_size)) / 2) + get_global_position();
- if (get_window()->get_embedder()) {
- pos += get_viewport()->get_popup_base_transform().get_origin();
- }
- DisplayServer::get_singleton()->window_set_ime_position(pos, wid);
- }
-
show_virtual_keyboard();
queue_redraw();
emit_signal(SNAME("editing_toggled"), true);
@@ -84,14 +74,7 @@ void LineEdit::_unedit() {
editing = false;
_validate_caret_can_draw();
- DisplayServer::WindowID wid = get_window() ? get_window()->get_window_id() : DisplayServer::INVALID_WINDOW_ID;
- if (wid != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
- DisplayServer::get_singleton()->window_set_ime_position(Point2(), wid);
- DisplayServer::get_singleton()->window_set_ime_active(false, wid);
- }
- ime_text = "";
- ime_selection = Point2();
- _shape();
+ apply_ime();
set_caret_column(caret_column); // Update scroll_offset.
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
@@ -109,6 +92,64 @@ bool LineEdit::is_editing() const {
return editing;
}
+void LineEdit::_close_ime_window() {
+ DisplayServer::WindowID wid = get_window() ? get_window()->get_window_id() : DisplayServer::INVALID_WINDOW_ID;
+ if (wid == DisplayServer::INVALID_WINDOW_ID || !DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
+ return;
+ }
+ DisplayServer::get_singleton()->window_set_ime_position(Point2(), wid);
+ DisplayServer::get_singleton()->window_set_ime_active(false, wid);
+}
+
+void LineEdit::_update_ime_window_position() {
+ DisplayServer::WindowID wid = get_window() ? get_window()->get_window_id() : DisplayServer::INVALID_WINDOW_ID;
+ if (wid == DisplayServer::INVALID_WINDOW_ID || !DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
+ return;
+ }
+ DisplayServer::get_singleton()->window_set_ime_active(true, wid);
+ Point2 pos = Point2(get_caret_pixel_pos().x, (get_size().y + theme_cache.font->get_height(theme_cache.font_size)) / 2) + get_global_position();
+ if (get_window()->get_embedder()) {
+ pos += get_viewport()->get_popup_base_transform().get_origin();
+ }
+ // The window will move to the updated position the next time the IME is updated, not immediately.
+ DisplayServer::get_singleton()->window_set_ime_position(pos, wid);
+}
+
+bool LineEdit::has_ime_text() const {
+ return !ime_text.is_empty();
+}
+
+void LineEdit::cancel_ime() {
+ if (!has_ime_text()) {
+ return;
+ }
+ ime_text = String();
+ ime_selection = Vector2i();
+ alt_start = false;
+ alt_start_no_hold = false;
+ _close_ime_window();
+ _shape();
+}
+
+void LineEdit::apply_ime() {
+ if (!has_ime_text()) {
+ return;
+ }
+
+ // Force apply the current IME text.
+ if (alt_start || alt_start_no_hold) {
+ cancel_ime();
+ if ((alt_code > 0x31 && alt_code < 0xd800) || (alt_code > 0xdfff && alt_code <= 0x10ffff)) {
+ char32_t ucodestr[2] = { (char32_t)alt_code, 0 };
+ insert_text_at_caret(ucodestr);
+ }
+ } else {
+ String insert_ime_text = ime_text;
+ cancel_ime();
+ insert_text_at_caret(insert_ime_text);
+ }
+}
+
void LineEdit::_swap_current_input_direction() {
if (input_direction == TEXT_DIRECTION_LTR) {
input_direction = TEXT_DIRECTION_RTL;
@@ -333,9 +374,10 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> b = p_event;
- // Ignore mouse clicks in IME input mode.
- if (b.is_valid() && ime_text.is_empty()) {
+ if (b.is_valid()) {
if (b->is_pressed() && b->get_button_index() == MouseButton::RIGHT) {
+ apply_ime();
+
if (editable && !selection.enabled) {
set_caret_at_pixel_pos(b->get_position().x);
}
@@ -356,6 +398,8 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
}
if (editable && is_middle_mouse_paste_enabled() && b->is_pressed() && b->get_button_index() == MouseButton::MIDDLE && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CLIPBOARD_PRIMARY)) {
+ apply_ime();
+
String paste_buffer = DisplayServer::get_singleton()->clipboard_get_primary().strip_escapes();
deselect();
@@ -388,6 +432,8 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
}
if (b->is_pressed()) {
+ apply_ime();
+
accept_event(); // Don't pass event further when clicked on text field.
if (editable && !text.is_empty() && _is_over_clear_button(b->get_position())) {
clear_button_status.press_attempt = true;
@@ -561,46 +607,111 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
return;
}
- if (!k->is_pressed()) {
- if (alt_start && k->get_keycode() == Key::ALT) {
- alt_start = false;
- if ((alt_code > 0x31 && alt_code < 0xd800) || (alt_code > 0xdfff && alt_code <= 0x10ffff)) {
- char32_t ucodestr[2] = { (char32_t)alt_code, 0 };
- insert_text_at_caret(ucodestr);
- }
- accept_event();
- return;
+ // Start Unicode input (hold).
+ if (k->is_alt_pressed() && k->get_keycode() == Key::KP_ADD && !alt_start && !alt_start_no_hold) {
+ if (selection.enabled) {
+ selection_delete();
}
+ alt_start = true;
+ alt_code = 0;
+ ime_text = "u";
+ ime_selection = Vector2i(0, -1);
+ _shape();
+ queue_redraw();
+ accept_event();
return;
}
- // Alt + Unicode input:
- if (k->is_alt_pressed()) {
- if (!alt_start) {
- if (k->get_keycode() == Key::KP_ADD) {
- alt_start = true;
- alt_code = 0;
- accept_event();
- return;
- }
+ // Start Unicode input (press).
+ if (k->is_action("ui_unicode_start", true) && !alt_start && !alt_start_no_hold) {
+ if (selection.enabled) {
+ selection_delete();
+ }
+ alt_start_no_hold = true;
+ alt_code = 0;
+ ime_text = "u";
+ ime_selection = Vector2i(0, -1);
+ _shape();
+ queue_redraw();
+ accept_event();
+ return;
+ }
+
+ // Update Unicode input.
+ if (k->is_pressed() && ((k->is_alt_pressed() && alt_start) || alt_start_no_hold)) {
+ if (k->get_keycode() >= Key::KEY_0 && k->get_keycode() <= Key::KEY_9) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)(k->get_keycode() - Key::KEY_0);
+ } else if (k->get_keycode() >= Key::KP_0 && k->get_keycode() <= Key::KP_9) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)(k->get_keycode() - Key::KP_0);
+ } else if (k->get_keycode() >= Key::A && k->get_keycode() <= Key::F) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)(k->get_keycode() - Key::A) + 10;
+ } else if ((Key)k->get_unicode() >= Key::KEY_0 && (Key)k->get_unicode() <= Key::KEY_9) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)((Key)k->get_unicode() - Key::KEY_0);
+ } else if ((Key)k->get_unicode() >= Key::A && (Key)k->get_unicode() <= Key::F) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)((Key)k->get_unicode() - Key::A) + 10;
+ } else if (k->get_physical_keycode() >= Key::KEY_0 && k->get_physical_keycode() <= Key::KEY_9) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)(k->get_physical_keycode() - Key::KEY_0);
+ }
+ if (k->get_keycode() == Key::BACKSPACE) {
+ alt_code = alt_code >> 4;
+ }
+ if (alt_code > 0x10ffff) {
+ alt_code = 0x10ffff;
+ }
+ if (alt_code > 0) {
+ ime_text = vformat("u%s", String::num_int64(alt_code, 16, true));
} else {
- if (k->get_keycode() >= Key::KEY_0 && k->get_keycode() <= Key::KEY_9) {
- alt_code = alt_code << 4;
- alt_code += (uint32_t)(k->get_keycode() - Key::KEY_0);
- }
- if (k->get_keycode() >= Key::KP_0 && k->get_keycode() <= Key::KP_9) {
- alt_code = alt_code << 4;
- alt_code += (uint32_t)(k->get_keycode() - Key::KP_0);
- }
- if (k->get_keycode() >= Key::A && k->get_keycode() <= Key::F) {
- alt_code = alt_code << 4;
- alt_code += (uint32_t)(k->get_keycode() - Key::A) + 10;
- }
- accept_event();
- return;
+ ime_text = "u";
+ }
+ ime_selection = Vector2i(0, -1);
+ _shape();
+ queue_redraw();
+ accept_event();
+ return;
+ }
+
+ // Submit Unicode input.
+ if ((!k->is_pressed() && alt_start && k->get_keycode() == Key::ALT) || (alt_start_no_hold && (k->is_action("ui_text_submit", true) || k->is_action("ui_accept", true)))) {
+ alt_start = false;
+ alt_start_no_hold = false;
+ if ((alt_code > 0x31 && alt_code < 0xd800) || (alt_code > 0xdfff && alt_code <= 0x10ffff)) {
+ ime_text = String();
+ ime_selection = Vector2i();
+ char32_t ucodestr[2] = { (char32_t)alt_code, 0 };
+ insert_text_at_caret(ucodestr);
+ } else {
+ ime_text = String();
+ ime_selection = Vector2i();
+ _shape();
}
+ queue_redraw();
+ accept_event();
+ return;
}
+ // Cancel Unicode input.
+ if (alt_start_no_hold && k->is_action("ui_cancel", true)) {
+ alt_start = false;
+ alt_start_no_hold = false;
+ ime_text = String();
+ ime_selection = Vector2i();
+ _shape();
+ queue_redraw();
+ accept_event();
+ return;
+ }
+
+ if (!k->is_pressed()) {
+ return;
+ }
+
+ // Open context menu.
if (context_menu_enabled) {
if (k->is_action("ui_menu", true)) {
_update_context_menu();
@@ -830,6 +941,8 @@ void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) {
Control::drop_data(p_point, p_data);
if (p_data.is_string() && is_editable()) {
+ apply_ime();
+
set_caret_at_pixel_pos(p_point.x);
int caret_column_tmp = caret_column;
bool is_inside_sel = selection.enabled && caret_column >= selection.begin && caret_column <= selection.end;
@@ -1213,15 +1326,7 @@ void LineEdit::_notification(int p_what) {
}
if (editing) {
- DisplayServer::WindowID wid = get_window() ? get_window()->get_window_id() : DisplayServer::INVALID_WINDOW_ID;
- if (wid != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
- DisplayServer::get_singleton()->window_set_ime_active(true, wid);
- Point2 pos = Point2(get_caret_pixel_pos().x, (get_size().y + theme_cache.font->get_height(theme_cache.font_size)) / 2) + get_global_position();
- if (get_window()->get_embedder()) {
- pos += get_viewport()->get_popup_base_transform().get_origin();
- }
- DisplayServer::get_singleton()->window_set_ime_position(pos, wid);
- }
+ _update_ime_window_position();
}
} break;
@@ -1745,6 +1850,8 @@ void LineEdit::clear() {
}
void LineEdit::show_virtual_keyboard() {
+ _update_ime_window_position();
+
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
if (selection.enabled) {
DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), DisplayServer::VirtualKeyboardType(virtual_keyboard_type), max_length, selection.begin, selection.end);
@@ -2644,6 +2751,10 @@ void LineEdit::_validate_property(PropertyInfo &p_property) const {
}
void LineEdit::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("has_ime_text"), &LineEdit::has_ime_text);
+ ClassDB::bind_method(D_METHOD("cancel_ime"), &LineEdit::cancel_ime);
+ ClassDB::bind_method(D_METHOD("apply_ime"), &LineEdit::apply_ime);
+
ClassDB::bind_method(D_METHOD("set_horizontal_alignment", "alignment"), &LineEdit::set_horizontal_alignment);
ClassDB::bind_method(D_METHOD("get_horizontal_alignment"), &LineEdit::get_horizontal_alignment);
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index 984512745a..ac7436646b 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -92,6 +92,7 @@ private:
bool text_changed_dirty = false;
bool alt_start = false;
+ bool alt_start_no_hold = false;
uint32_t alt_code = 0;
String undo_text;
@@ -209,6 +210,9 @@ private:
void _edit();
void _unedit();
+ void _close_ime_window();
+ void _update_ime_window_position();
+
void _clear_undo_stack();
void _clear_redo();
void _create_undo_state();
@@ -263,6 +267,10 @@ protected:
public:
bool is_editing() const;
+ bool has_ime_text() const;
+ void cancel_ime();
+ void apply_ime();
+
void set_horizontal_alignment(HorizontalAlignment p_alignment);
HorizontalAlignment get_horizontal_alignment() const;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index ab0ad2f4b7..d7799588ea 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1557,7 +1557,7 @@ void TextEdit::_notification(int p_what) {
carets.write[c].draw_pos.x = rect.position.x;
}
}
- {
+ if (ime_selection.y > 0) {
// IME caret.
const Vector<Vector2> sel = TS->shaped_text_get_selection(rid, get_caret_column(c) + ime_selection.x, get_caret_column(c) + ime_selection.x + ime_selection.y);
for (int j = 0; j < sel.size(); j++) {
@@ -1688,39 +1688,93 @@ void TextEdit::unhandled_key_input(const Ref<InputEvent> &p_event) {
bool TextEdit::alt_input(const Ref<InputEvent> &p_gui_input) {
Ref<InputEventKey> k = p_gui_input;
if (k.is_valid()) {
- if (!k->is_pressed()) {
- if (alt_start && k->get_keycode() == Key::ALT) {
- alt_start = false;
- if ((alt_code > 0x31 && alt_code < 0xd800) || (alt_code > 0xdfff && alt_code <= 0x10ffff)) {
- handle_unicode_input(alt_code);
- }
- return true;
+ // Start Unicode input (hold).
+ if (k->is_alt_pressed() && k->get_keycode() == Key::KP_ADD && !alt_start && !alt_start_no_hold) {
+ if (has_selection()) {
+ delete_selection();
}
- return false;
+ alt_start = true;
+ alt_code = 0;
+ ime_text = "u";
+ ime_selection = Vector2i(0, -1);
+ _update_ime_text();
+ return true;
}
- if (k->is_alt_pressed()) {
- if (!alt_start) {
- if (k->get_keycode() == Key::KP_ADD) {
- alt_start = true;
- alt_code = 0;
- return true;
- }
+ // Start Unicode input (press).
+ if (k->is_action("ui_unicode_start", true) && !alt_start && !alt_start_no_hold) {
+ if (has_selection()) {
+ delete_selection();
+ }
+ alt_start_no_hold = true;
+ alt_code = 0;
+ ime_text = "u";
+ ime_selection = Vector2i(0, -1);
+ _update_ime_text();
+ return true;
+ }
+
+ // Update Unicode input.
+ if (k->is_pressed() && ((k->is_alt_pressed() && alt_start) || alt_start_no_hold)) {
+ if (k->get_keycode() >= Key::KEY_0 && k->get_keycode() <= Key::KEY_9) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)(k->get_keycode() - Key::KEY_0);
+ } else if (k->get_keycode() >= Key::KP_0 && k->get_keycode() <= Key::KP_9) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)(k->get_keycode() - Key::KP_0);
+ } else if (k->get_keycode() >= Key::A && k->get_keycode() <= Key::F) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)(k->get_keycode() - Key::A) + 10;
+ } else if ((Key)k->get_unicode() >= Key::KEY_0 && (Key)k->get_unicode() <= Key::KEY_9) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)((Key)k->get_unicode() - Key::KEY_0);
+ } else if ((Key)k->get_unicode() >= Key::A && (Key)k->get_unicode() <= Key::F) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)((Key)k->get_unicode() - Key::A) + 10;
+ } else if (k->get_physical_keycode() >= Key::KEY_0 && k->get_physical_keycode() <= Key::KEY_9) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)(k->get_physical_keycode() - Key::KEY_0);
+ }
+ if (k->get_keycode() == Key::BACKSPACE) {
+ alt_code = alt_code >> 4;
+ }
+ if (alt_code > 0x10ffff) {
+ alt_code = 0x10ffff;
+ }
+ if (alt_code > 0) {
+ ime_text = vformat("u%s", String::num_int64(alt_code, 16, true));
} else {
- if (k->get_keycode() >= Key::KEY_0 && k->get_keycode() <= Key::KEY_9) {
- alt_code = alt_code << 4;
- alt_code += (uint32_t)(k->get_keycode() - Key::KEY_0);
- }
- if (k->get_keycode() >= Key::KP_0 && k->get_keycode() <= Key::KP_9) {
- alt_code = alt_code << 4;
- alt_code += (uint32_t)(k->get_keycode() - Key::KP_0);
- }
- if (k->get_keycode() >= Key::A && k->get_keycode() <= Key::F) {
- alt_code = alt_code << 4;
- alt_code += (uint32_t)(k->get_keycode() - Key::A) + 10;
- }
- return true;
+ ime_text = "u";
}
+ ime_selection = Vector2i(0, -1);
+ _update_ime_text();
+ return true;
+ }
+
+ // Submit Unicode input.
+ if ((!k->is_pressed() && alt_start && k->get_keycode() == Key::ALT) || (alt_start_no_hold && (k->is_action("ui_text_submit", true) || k->is_action("ui_accept", true)))) {
+ alt_start = false;
+ alt_start_no_hold = false;
+ if ((alt_code > 0x31 && alt_code < 0xd800) || (alt_code > 0xdfff && alt_code <= 0x10ffff)) {
+ ime_text = String();
+ ime_selection = Vector2i();
+ handle_unicode_input(alt_code);
+ } else {
+ ime_text = String();
+ ime_selection = Vector2i();
+ }
+ _update_ime_text();
+ return true;
+ }
+
+ // Cancel Unicode input.
+ if (alt_start_no_hold && k->is_action("ui_cancel", true)) {
+ alt_start = false;
+ alt_start_no_hold = false;
+ ime_text = String();
+ ime_selection = Vector2i();
+ _update_ime_text();
+ return true;
}
}
return false;
@@ -3117,7 +3171,9 @@ void TextEdit::cancel_ime() {
return;
}
ime_text = String();
- ime_selection = Point2();
+ ime_selection = Vector2i();
+ alt_start = false;
+ alt_start_no_hold = false;
_close_ime_window();
_update_ime_text();
}
@@ -3126,10 +3182,18 @@ void TextEdit::apply_ime() {
if (!has_ime_text()) {
return;
}
+
// Force apply the current IME text.
- String insert_ime_text = ime_text;
- cancel_ime();
- insert_text_at_caret(insert_ime_text);
+ if (alt_start || alt_start_no_hold) {
+ cancel_ime();
+ if ((alt_code > 0x31 && alt_code < 0xd800) || (alt_code > 0xdfff && alt_code <= 0x10ffff)) {
+ handle_unicode_input(alt_code);
+ }
+ } else {
+ String insert_ime_text = ime_text;
+ cancel_ime();
+ insert_text_at_caret(insert_ime_text);
+ }
}
void TextEdit::set_editable(bool p_editable) {
@@ -5966,7 +6030,7 @@ void TextEdit::adjust_viewport_to_caret(int p_caret) {
// Get position of the end of caret.
if (has_ime_text()) {
- if (ime_selection.y != 0) {
+ if (ime_selection.y > 0) {
caret_pos.y = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_selection.x + ime_selection.y, get_caret_line(p_caret), get_caret_column(p_caret));
} else {
caret_pos.y = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_text.size(), get_caret_line(p_caret), get_caret_column(p_caret));
@@ -6018,7 +6082,7 @@ void TextEdit::center_viewport_to_caret(int p_caret) {
// Get position of the end of caret.
if (has_ime_text()) {
- if (ime_selection.y != 0) {
+ if (ime_selection.y > 0) {
caret_pos.y = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_selection.x + ime_selection.y, get_caret_line(p_caret), get_caret_column(p_caret));
} else {
caret_pos.y = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_text.size(), get_caret_line(p_caret), get_caret_column(p_caret));
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index a448e185b1..c5f838020b 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -276,6 +276,7 @@ private:
bool setting_text = false;
bool alt_start = false;
+ bool alt_start_no_hold = false;
uint32_t alt_code = 0;
// Text properties.