Add Control+Shift+U (rebindabe) action for Unicode input, show hex as it is entered.
This commit is contained in:
parent
b214aa8faf
commit
b776f55bcb
|
@ -400,6 +400,7 @@ static const _BuiltinActionDisplayName _builtin_action_display_names[] = {
|
||||||
{ "ui_filedialog_refresh", TTRC("Refresh") },
|
{ "ui_filedialog_refresh", TTRC("Refresh") },
|
||||||
{ "ui_filedialog_show_hidden", TTRC("Show Hidden") },
|
{ "ui_filedialog_show_hidden", TTRC("Show Hidden") },
|
||||||
{ "ui_swap_input_direction ", TTRC("Swap Input Direction") },
|
{ "ui_swap_input_direction ", TTRC("Swap Input Direction") },
|
||||||
|
{ "ui_unicode_start", TTRC("Start Unicode Character Input") },
|
||||||
{ "", ""}
|
{ "", ""}
|
||||||
/* clang-format on */
|
/* 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));
|
inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER));
|
||||||
default_builtin_cache.insert("ui_text_submit", inputs);
|
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 /////
|
// ///// UI Graph Shortcuts /////
|
||||||
|
|
||||||
inputs = List<Ref<InputEvent>>();
|
inputs = List<Ref<InputEvent>>();
|
||||||
|
|
|
@ -37,6 +37,18 @@
|
||||||
<tutorials>
|
<tutorials>
|
||||||
</tutorials>
|
</tutorials>
|
||||||
<methods>
|
<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">
|
<method name="clear">
|
||||||
<return type="void" />
|
<return type="void" />
|
||||||
<description>
|
<description>
|
||||||
|
@ -133,6 +145,12 @@
|
||||||
Returns the selection end column.
|
Returns the selection end column.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</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">
|
<method name="has_selection" qualifiers="const">
|
||||||
<return type="bool" />
|
<return type="bool" />
|
||||||
<description>
|
<description>
|
||||||
|
|
|
@ -1386,6 +1386,10 @@
|
||||||
Default [InputEventAction] to undo the most recent action.
|
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.
|
[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>
|
||||||
|
<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="">
|
<member name="input/ui_up" type="Dictionary" setter="" getter="">
|
||||||
Default [InputEventAction] to move up in the UI.
|
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.
|
[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.
|
||||||
|
|
|
@ -61,16 +61,6 @@ void LineEdit::_edit() {
|
||||||
editing = true;
|
editing = true;
|
||||||
_validate_caret_can_draw();
|
_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();
|
show_virtual_keyboard();
|
||||||
queue_redraw();
|
queue_redraw();
|
||||||
emit_signal(SNAME("editing_toggled"), true);
|
emit_signal(SNAME("editing_toggled"), true);
|
||||||
|
@ -84,14 +74,7 @@ void LineEdit::_unedit() {
|
||||||
editing = false;
|
editing = false;
|
||||||
_validate_caret_can_draw();
|
_validate_caret_can_draw();
|
||||||
|
|
||||||
DisplayServer::WindowID wid = get_window() ? get_window()->get_window_id() : DisplayServer::INVALID_WINDOW_ID;
|
apply_ime();
|
||||||
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();
|
|
||||||
set_caret_column(caret_column); // Update scroll_offset.
|
set_caret_column(caret_column); // Update scroll_offset.
|
||||||
|
|
||||||
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
|
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
|
||||||
|
@ -109,6 +92,64 @@ bool LineEdit::is_editing() const {
|
||||||
return editing;
|
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() {
|
void LineEdit::_swap_current_input_direction() {
|
||||||
if (input_direction == TEXT_DIRECTION_LTR) {
|
if (input_direction == TEXT_DIRECTION_LTR) {
|
||||||
input_direction = TEXT_DIRECTION_RTL;
|
input_direction = TEXT_DIRECTION_RTL;
|
||||||
|
@ -333,9 +374,10 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
|
||||||
|
|
||||||
Ref<InputEventMouseButton> b = p_event;
|
Ref<InputEventMouseButton> b = p_event;
|
||||||
|
|
||||||
// Ignore mouse clicks in IME input mode.
|
if (b.is_valid()) {
|
||||||
if (b.is_valid() && ime_text.is_empty()) {
|
|
||||||
if (b->is_pressed() && b->get_button_index() == MouseButton::RIGHT) {
|
if (b->is_pressed() && b->get_button_index() == MouseButton::RIGHT) {
|
||||||
|
apply_ime();
|
||||||
|
|
||||||
if (editable && !selection.enabled) {
|
if (editable && !selection.enabled) {
|
||||||
set_caret_at_pixel_pos(b->get_position().x);
|
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)) {
|
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();
|
String paste_buffer = DisplayServer::get_singleton()->clipboard_get_primary().strip_escapes();
|
||||||
|
|
||||||
deselect();
|
deselect();
|
||||||
|
@ -388,6 +432,8 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (b->is_pressed()) {
|
if (b->is_pressed()) {
|
||||||
|
apply_ime();
|
||||||
|
|
||||||
accept_event(); // Don't pass event further when clicked on text field.
|
accept_event(); // Don't pass event further when clicked on text field.
|
||||||
if (editable && !text.is_empty() && _is_over_clear_button(b->get_position())) {
|
if (editable && !text.is_empty() && _is_over_clear_button(b->get_position())) {
|
||||||
clear_button_status.press_attempt = true;
|
clear_button_status.press_attempt = true;
|
||||||
|
@ -561,46 +607,111 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!k->is_pressed()) {
|
// Start Unicode input (hold).
|
||||||
if (alt_start && k->get_keycode() == Key::ALT) {
|
if (k->is_alt_pressed() && k->get_keycode() == Key::KP_ADD && !alt_start && !alt_start_no_hold) {
|
||||||
alt_start = false;
|
if (selection.enabled) {
|
||||||
if ((alt_code > 0x31 && alt_code < 0xd800) || (alt_code > 0xdfff && alt_code <= 0x10ffff)) {
|
selection_delete();
|
||||||
char32_t ucodestr[2] = { (char32_t)alt_code, 0 };
|
|
||||||
insert_text_at_caret(ucodestr);
|
|
||||||
}
|
}
|
||||||
|
alt_start = true;
|
||||||
|
alt_code = 0;
|
||||||
|
ime_text = "u";
|
||||||
|
ime_selection = Vector2i(0, -1);
|
||||||
|
_shape();
|
||||||
|
queue_redraw();
|
||||||
accept_event();
|
accept_event();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alt + Unicode input:
|
// Start Unicode input (press).
|
||||||
if (k->is_alt_pressed()) {
|
if (k->is_action("ui_unicode_start", true) && !alt_start && !alt_start_no_hold) {
|
||||||
if (!alt_start) {
|
if (selection.enabled) {
|
||||||
if (k->get_keycode() == Key::KP_ADD) {
|
selection_delete();
|
||||||
alt_start = true;
|
}
|
||||||
|
alt_start_no_hold = true;
|
||||||
alt_code = 0;
|
alt_code = 0;
|
||||||
|
ime_text = "u";
|
||||||
|
ime_selection = Vector2i(0, -1);
|
||||||
|
_shape();
|
||||||
|
queue_redraw();
|
||||||
accept_event();
|
accept_event();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
|
// 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) {
|
if (k->get_keycode() >= Key::KEY_0 && k->get_keycode() <= Key::KEY_9) {
|
||||||
alt_code = alt_code << 4;
|
alt_code = alt_code << 4;
|
||||||
alt_code += (uint32_t)(k->get_keycode() - Key::KEY_0);
|
alt_code += (uint32_t)(k->get_keycode() - Key::KEY_0);
|
||||||
}
|
} else if (k->get_keycode() >= Key::KP_0 && k->get_keycode() <= Key::KP_9) {
|
||||||
if (k->get_keycode() >= Key::KP_0 && k->get_keycode() <= Key::KP_9) {
|
|
||||||
alt_code = alt_code << 4;
|
alt_code = alt_code << 4;
|
||||||
alt_code += (uint32_t)(k->get_keycode() - Key::KP_0);
|
alt_code += (uint32_t)(k->get_keycode() - Key::KP_0);
|
||||||
}
|
} else if (k->get_keycode() >= Key::A && k->get_keycode() <= Key::F) {
|
||||||
if (k->get_keycode() >= Key::A && k->get_keycode() <= Key::F) {
|
|
||||||
alt_code = alt_code << 4;
|
alt_code = alt_code << 4;
|
||||||
alt_code += (uint32_t)(k->get_keycode() - Key::A) + 10;
|
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 {
|
||||||
|
ime_text = "u";
|
||||||
|
}
|
||||||
|
ime_selection = Vector2i(0, -1);
|
||||||
|
_shape();
|
||||||
|
queue_redraw();
|
||||||
accept_event();
|
accept_event();
|
||||||
return;
|
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 (context_menu_enabled) {
|
||||||
if (k->is_action("ui_menu", true)) {
|
if (k->is_action("ui_menu", true)) {
|
||||||
_update_context_menu();
|
_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);
|
Control::drop_data(p_point, p_data);
|
||||||
|
|
||||||
if (p_data.is_string() && is_editable()) {
|
if (p_data.is_string() && is_editable()) {
|
||||||
|
apply_ime();
|
||||||
|
|
||||||
set_caret_at_pixel_pos(p_point.x);
|
set_caret_at_pixel_pos(p_point.x);
|
||||||
int caret_column_tmp = caret_column;
|
int caret_column_tmp = caret_column;
|
||||||
bool is_inside_sel = selection.enabled && caret_column >= selection.begin && caret_column <= selection.end;
|
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) {
|
if (editing) {
|
||||||
DisplayServer::WindowID wid = get_window() ? get_window()->get_window_id() : DisplayServer::INVALID_WINDOW_ID;
|
_update_ime_window_position();
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -1745,6 +1850,8 @@ void LineEdit::clear() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LineEdit::show_virtual_keyboard() {
|
void LineEdit::show_virtual_keyboard() {
|
||||||
|
_update_ime_window_position();
|
||||||
|
|
||||||
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
|
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
|
||||||
if (selection.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);
|
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() {
|
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("set_horizontal_alignment", "alignment"), &LineEdit::set_horizontal_alignment);
|
||||||
ClassDB::bind_method(D_METHOD("get_horizontal_alignment"), &LineEdit::get_horizontal_alignment);
|
ClassDB::bind_method(D_METHOD("get_horizontal_alignment"), &LineEdit::get_horizontal_alignment);
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,7 @@ private:
|
||||||
bool text_changed_dirty = false;
|
bool text_changed_dirty = false;
|
||||||
|
|
||||||
bool alt_start = false;
|
bool alt_start = false;
|
||||||
|
bool alt_start_no_hold = false;
|
||||||
uint32_t alt_code = 0;
|
uint32_t alt_code = 0;
|
||||||
|
|
||||||
String undo_text;
|
String undo_text;
|
||||||
|
@ -209,6 +210,9 @@ private:
|
||||||
void _edit();
|
void _edit();
|
||||||
void _unedit();
|
void _unedit();
|
||||||
|
|
||||||
|
void _close_ime_window();
|
||||||
|
void _update_ime_window_position();
|
||||||
|
|
||||||
void _clear_undo_stack();
|
void _clear_undo_stack();
|
||||||
void _clear_redo();
|
void _clear_redo();
|
||||||
void _create_undo_state();
|
void _create_undo_state();
|
||||||
|
@ -263,6 +267,10 @@ protected:
|
||||||
public:
|
public:
|
||||||
bool is_editing() const;
|
bool is_editing() const;
|
||||||
|
|
||||||
|
bool has_ime_text() const;
|
||||||
|
void cancel_ime();
|
||||||
|
void apply_ime();
|
||||||
|
|
||||||
void set_horizontal_alignment(HorizontalAlignment p_alignment);
|
void set_horizontal_alignment(HorizontalAlignment p_alignment);
|
||||||
HorizontalAlignment get_horizontal_alignment() const;
|
HorizontalAlignment get_horizontal_alignment() const;
|
||||||
|
|
||||||
|
|
|
@ -1557,7 +1557,7 @@ void TextEdit::_notification(int p_what) {
|
||||||
carets.write[c].draw_pos.x = rect.position.x;
|
carets.write[c].draw_pos.x = rect.position.x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
if (ime_selection.y > 0) {
|
||||||
// IME caret.
|
// 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);
|
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++) {
|
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) {
|
bool TextEdit::alt_input(const Ref<InputEvent> &p_gui_input) {
|
||||||
Ref<InputEventKey> k = p_gui_input;
|
Ref<InputEventKey> k = p_gui_input;
|
||||||
if (k.is_valid()) {
|
if (k.is_valid()) {
|
||||||
if (!k->is_pressed()) {
|
// Start Unicode input (hold).
|
||||||
if (alt_start && k->get_keycode() == Key::ALT) {
|
if (k->is_alt_pressed() && k->get_keycode() == Key::KP_ADD && !alt_start && !alt_start_no_hold) {
|
||||||
alt_start = false;
|
if (has_selection()) {
|
||||||
if ((alt_code > 0x31 && alt_code < 0xd800) || (alt_code > 0xdfff && alt_code <= 0x10ffff)) {
|
delete_selection();
|
||||||
handle_unicode_input(alt_code);
|
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (k->is_alt_pressed()) {
|
|
||||||
if (!alt_start) {
|
|
||||||
if (k->get_keycode() == Key::KP_ADD) {
|
|
||||||
alt_start = true;
|
alt_start = true;
|
||||||
alt_code = 0;
|
alt_code = 0;
|
||||||
|
ime_text = "u";
|
||||||
|
ime_selection = Vector2i(0, -1);
|
||||||
|
_update_ime_text();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
|
// 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) {
|
if (k->get_keycode() >= Key::KEY_0 && k->get_keycode() <= Key::KEY_9) {
|
||||||
alt_code = alt_code << 4;
|
alt_code = alt_code << 4;
|
||||||
alt_code += (uint32_t)(k->get_keycode() - Key::KEY_0);
|
alt_code += (uint32_t)(k->get_keycode() - Key::KEY_0);
|
||||||
}
|
} else if (k->get_keycode() >= Key::KP_0 && k->get_keycode() <= Key::KP_9) {
|
||||||
if (k->get_keycode() >= Key::KP_0 && k->get_keycode() <= Key::KP_9) {
|
|
||||||
alt_code = alt_code << 4;
|
alt_code = alt_code << 4;
|
||||||
alt_code += (uint32_t)(k->get_keycode() - Key::KP_0);
|
alt_code += (uint32_t)(k->get_keycode() - Key::KP_0);
|
||||||
}
|
} else if (k->get_keycode() >= Key::A && k->get_keycode() <= Key::F) {
|
||||||
if (k->get_keycode() >= Key::A && k->get_keycode() <= Key::F) {
|
|
||||||
alt_code = alt_code << 4;
|
alt_code = alt_code << 4;
|
||||||
alt_code += (uint32_t)(k->get_keycode() - Key::A) + 10;
|
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 {
|
||||||
|
ime_text = "u";
|
||||||
|
}
|
||||||
|
ime_selection = Vector2i(0, -1);
|
||||||
|
_update_ime_text();
|
||||||
return true;
|
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;
|
return false;
|
||||||
|
@ -3117,7 +3171,9 @@ void TextEdit::cancel_ime() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ime_text = String();
|
ime_text = String();
|
||||||
ime_selection = Point2();
|
ime_selection = Vector2i();
|
||||||
|
alt_start = false;
|
||||||
|
alt_start_no_hold = false;
|
||||||
_close_ime_window();
|
_close_ime_window();
|
||||||
_update_ime_text();
|
_update_ime_text();
|
||||||
}
|
}
|
||||||
|
@ -3126,11 +3182,19 @@ void TextEdit::apply_ime() {
|
||||||
if (!has_ime_text()) {
|
if (!has_ime_text()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force apply the current IME text.
|
// 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)) {
|
||||||
|
handle_unicode_input(alt_code);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
String insert_ime_text = ime_text;
|
String insert_ime_text = ime_text;
|
||||||
cancel_ime();
|
cancel_ime();
|
||||||
insert_text_at_caret(insert_ime_text);
|
insert_text_at_caret(insert_ime_text);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TextEdit::set_editable(bool p_editable) {
|
void TextEdit::set_editable(bool p_editable) {
|
||||||
if (editable == p_editable) {
|
if (editable == p_editable) {
|
||||||
|
@ -5966,7 +6030,7 @@ void TextEdit::adjust_viewport_to_caret(int p_caret) {
|
||||||
|
|
||||||
// Get position of the end of caret.
|
// Get position of the end of caret.
|
||||||
if (has_ime_text()) {
|
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));
|
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 {
|
} 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));
|
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.
|
// Get position of the end of caret.
|
||||||
if (has_ime_text()) {
|
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));
|
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 {
|
} 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));
|
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));
|
||||||
|
|
|
@ -276,6 +276,7 @@ private:
|
||||||
bool setting_text = false;
|
bool setting_text = false;
|
||||||
|
|
||||||
bool alt_start = false;
|
bool alt_start = false;
|
||||||
|
bool alt_start_no_hold = false;
|
||||||
uint32_t alt_code = 0;
|
uint32_t alt_code = 0;
|
||||||
|
|
||||||
// Text properties.
|
// Text properties.
|
||||||
|
|
Loading…
Reference in New Issue