Skip to content

Commit b252867

Browse files
committed
[macOS/Windows] Add Emoji & Symbols context menu item to LineEdit/TextEdit to show system character picker.
1 parent 24d7451 commit b252867

21 files changed

+167
-4
lines changed

doc/classes/DisplayServer.xml

+10
Original file line numberDiff line numberDiff line change
@@ -1215,6 +1215,13 @@
12151215
[b]Note:[/b] This method is implemented on Android, iOS, macOS, Windows, and Linux (X11/Wayland).
12161216
</description>
12171217
</method>
1218+
<method name="show_emoji_and_symbol_picker" qualifiers="const">
1219+
<return type="void" />
1220+
<description>
1221+
Opens system emoji and symbol picker.
1222+
[b]Note:[/b] This method is implemented on macOS and Windows.
1223+
</description>
1224+
</method>
12181225
<method name="status_indicator_get_rect" qualifiers="const">
12191226
<return type="Rect2" />
12201227
<param index="0" name="id" type="int" />
@@ -1941,6 +1948,9 @@
19411948
<constant name="FEATURE_NATIVE_DIALOG_FILE_MIME" value="30" enum="Feature">
19421949
Native file selection dialog supports MIME types as filters.
19431950
</constant>
1951+
<constant name="FEATURE_EMOJI_AND_SYMBOL_PICKER" value="31" enum="Feature">
1952+
Display server supports system emoji and symbol picker. [b]Windows, macOS[/b]
1953+
</constant>
19441954
<constant name="MOUSE_MODE_VISIBLE" value="0" enum="MouseMode">
19451955
Makes the mouse cursor visible if it is hidden.
19461956
</constant>

doc/classes/LineEdit.xml

+7-1
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,9 @@
276276
<member name="editable" type="bool" setter="set_editable" getter="is_editable" default="true" keywords="readonly, disabled, enabled">
277277
If [code]false[/code], existing text cannot be modified and new text cannot be added.
278278
</member>
279+
<member name="emoji_menu_enabled" type="bool" setter="set_emoji_menu_enabled" getter="is_emoji_menu_enabled" default="true">
280+
If [code]false[/code], "Emoji and Symbols" menu is enabled.
281+
</member>
279282
<member name="expand_to_text_length" type="bool" setter="set_expand_to_text_length_enabled" getter="is_expand_to_text_length_enabled" default="false">
280283
If [code]true[/code], the [LineEdit] width will increase to stay longer than the [member text]. It will [b]not[/b] compress if the [member text] is shortened.
281284
</member>
@@ -478,7 +481,10 @@
478481
<constant name="MENU_INSERT_SHY" value="29" enum="MenuItems">
479482
Inserts soft hyphen (SHY) character.
480483
</constant>
481-
<constant name="MENU_MAX" value="30" enum="MenuItems">
484+
<constant name="MENU_EMOJI_AND_SYMBOL" value="30" enum="MenuItems">
485+
Opens system emoji and symbol picker.
486+
</constant>
487+
<constant name="MENU_MAX" value="31" enum="MenuItems">
482488
Represents the size of the [enum MenuItems] enum.
483489
</constant>
484490
<constant name="KEYBOARD_TYPE_DEFAULT" value="0" enum="VirtualKeyboardType">

doc/classes/TextEdit.xml

+7-1
Original file line numberDiff line numberDiff line change
@@ -1299,6 +1299,9 @@
12991299
<member name="editable" type="bool" setter="set_editable" getter="is_editable" default="true" keywords="readonly, disabled, enabled">
13001300
If [code]false[/code], existing text cannot be modified and new text cannot be added.
13011301
</member>
1302+
<member name="emoji_menu_enabled" type="bool" setter="set_emoji_menu_enabled" getter="is_emoji_menu_enabled" default="true">
1303+
If [code]false[/code], "Emoji and Symbols" menu is enabled.
1304+
</member>
13021305
<member name="empty_selection_clipboard_enabled" type="bool" setter="set_empty_selection_clipboard_enabled" getter="is_empty_selection_clipboard_enabled" default="true">
13031306
If [code]true[/code], copying or cutting without a selection is performed on all lines with a caret. Otherwise, copy and cut require a selection.
13041307
</member>
@@ -1519,7 +1522,10 @@
15191522
<constant name="MENU_INSERT_SHY" value="29" enum="MenuItems">
15201523
Inserts soft hyphen (SHY) character.
15211524
</constant>
1522-
<constant name="MENU_MAX" value="30" enum="MenuItems">
1525+
<constant name="MENU_EMOJI_AND_SYMBOL" value="30" enum="MenuItems">
1526+
Opens system emoji and symbol picker.
1527+
</constant>
1528+
<constant name="MENU_MAX" value="31" enum="MenuItems">
15231529
Represents the size of the [enum MenuItems] enum.
15241530
</constant>
15251531
<constant name="ACTION_NONE" value="0" enum="EditAction">

editor/gui/editor_spin_slider.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,7 @@ void EditorSpinSlider::_ensure_input_popup() {
715715
add_child(value_input_popup);
716716

717717
value_input = memnew(LineEdit);
718+
value_input->set_emoji_menu_enabled(false);
718719
value_input->set_focus_mode(FOCUS_CLICK);
719720
value_input_popup->add_child(value_input);
720721
value_input->set_anchors_and_offsets_preset(PRESET_FULL_RECT);

editor/plugins/script_text_editor.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -1738,6 +1738,9 @@ void ScriptTextEditor::_edit_option(int p_op) {
17381738
_lookup_symbol(text, tx->get_caret_line(0), tx->get_caret_column(0));
17391739
}
17401740
} break;
1741+
case EDIT_EMOJI_AND_SYMBOL: {
1742+
code_editor->get_text_editor()->show_emoji_and_symbol_picker();
1743+
} break;
17411744
default: {
17421745
if (p_op >= EditorContextMenuPlugin::BASE_ID) {
17431746
EditorContextMenuPluginManager::get_singleton()->activate_custom_option(EditorContextMenuPlugin::CONTEXT_SLOT_SCRIPT_EDITOR_CODE, p_op, tx);
@@ -2294,6 +2297,10 @@ void ScriptTextEditor::_prepare_edit_menu() {
22942297

22952298
void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p_foldable, bool p_open_docs, bool p_goto_definition, Vector2 p_pos) {
22962299
context_menu->clear();
2300+
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_EMOJI_AND_SYMBOL_PICKER)) {
2301+
context_menu->add_item(TTR("Emoji & Symbols"), EDIT_EMOJI_AND_SYMBOL);
2302+
context_menu->add_separator();
2303+
}
22972304
context_menu->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO);
22982305
context_menu->add_shortcut(ED_GET_SHORTCUT("ui_redo"), EDIT_REDO);
22992306

editor/plugins/script_text_editor.h

+1
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ class ScriptTextEditor : public ScriptEditorBase {
157157
DEBUG_GOTO_PREV_BREAKPOINT,
158158
HELP_CONTEXTUAL,
159159
LOOKUP_SYMBOL,
160+
EDIT_EMOJI_AND_SYMBOL,
160161
};
161162

162163
void _enable_code_editor();

editor/plugins/text_editor.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,9 @@ void TextEditor::_edit_option(int p_op) {
481481
case BOOKMARK_REMOVE_ALL: {
482482
code_editor->remove_all_bookmarks();
483483
} break;
484+
case EDIT_EMOJI_AND_SYMBOL: {
485+
code_editor->get_text_editor()->show_emoji_and_symbol_picker();
486+
} break;
484487
}
485488
}
486489

@@ -560,6 +563,10 @@ void TextEditor::_prepare_edit_menu() {
560563

561564
void TextEditor::_make_context_menu(bool p_selection, bool p_can_fold, bool p_is_folded, Vector2 p_position) {
562565
context_menu->clear();
566+
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_EMOJI_AND_SYMBOL_PICKER)) {
567+
context_menu->add_item(TTR("Emoji & Symbols"), EDIT_EMOJI_AND_SYMBOL);
568+
context_menu->add_separator();
569+
}
563570
if (p_selection) {
564571
context_menu->add_shortcut(ED_GET_SHORTCUT("ui_cut"), EDIT_CUT);
565572
context_menu->add_shortcut(ED_GET_SHORTCUT("ui_copy"), EDIT_COPY);

editor/plugins/text_editor.h

+1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ class TextEditor : public ScriptEditorBase {
9191
BOOKMARK_GOTO_NEXT,
9292
BOOKMARK_GOTO_PREV,
9393
BOOKMARK_REMOVE_ALL,
94+
EDIT_EMOJI_AND_SYMBOL,
9495
};
9596

9697
protected:

editor/plugins/text_shader_editor.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,9 @@ void TextShaderEditor::_menu_option(int p_option) {
729729
case HELP_DOCS: {
730730
OS::get_singleton()->shell_open(vformat("%s/tutorials/shaders/shader_reference/index.html", VERSION_DOCS_URL));
731731
} break;
732+
case EDIT_EMOJI_AND_SYMBOL: {
733+
code_editor->get_text_editor()->show_emoji_and_symbol_picker();
734+
} break;
732735
}
733736
if (p_option != SEARCH_FIND && p_option != SEARCH_REPLACE && p_option != SEARCH_GOTO_LINE) {
734737
callable_mp((Control *)code_editor->get_text_editor(), &Control::grab_focus).call_deferred();
@@ -1087,6 +1090,10 @@ void TextShaderEditor::_bookmark_item_pressed(int p_idx) {
10871090

10881091
void TextShaderEditor::_make_context_menu(bool p_selection, Vector2 p_position) {
10891092
context_menu->clear();
1093+
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_EMOJI_AND_SYMBOL_PICKER)) {
1094+
context_menu->add_item(TTR("Emoji & Symbols"), EDIT_EMOJI_AND_SYMBOL);
1095+
context_menu->add_separator();
1096+
}
10901097
if (p_selection) {
10911098
context_menu->add_shortcut(ED_GET_SHORTCUT("ui_cut"), EDIT_CUT);
10921099
context_menu->add_shortcut(ED_GET_SHORTCUT("ui_copy"), EDIT_COPY);

editor/plugins/text_shader_editor.h

+1
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ class TextShaderEditor : public ShaderEditor {
134134
BOOKMARK_GOTO_PREV,
135135
BOOKMARK_REMOVE_ALL,
136136
HELP_DOCS,
137+
EDIT_EMOJI_AND_SYMBOL,
137138
};
138139

139140
MenuButton *edit_menu = nullptr;

platform/macos/display_server_macos.h

+1
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,7 @@ class DisplayServerMacOS : public DisplayServer {
432432
virtual String keyboard_get_layout_name(int p_index) const override;
433433
virtual Key keyboard_get_keycode_from_physical(Key p_keycode) const override;
434434
virtual Key keyboard_get_label_from_physical(Key p_keycode) const override;
435+
virtual void show_emoji_and_symbol_picker() const override;
435436

436437
virtual void process_events() override;
437438
virtual void force_process_and_drop_events() override;

platform/macos/display_server_macos.mm

+5
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,7 @@
789789
case FEATURE_NATIVE_HELP:
790790
case FEATURE_WINDOW_DRAG:
791791
case FEATURE_SCREEN_EXCLUDE_FROM_CAPTURE:
792+
case FEATURE_EMOJI_AND_SYMBOL_PICKER:
792793
return true;
793794
default: {
794795
}
@@ -3134,6 +3135,10 @@
31343135
return (Key)(KeyMappingMacOS::remap_key(macos_keycode, 0, true) | modifiers);
31353136
}
31363137

3138+
void DisplayServerMacOS::show_emoji_and_symbol_picker() const {
3139+
[[NSApplication sharedApplication] orderFrontCharacterPalette:nil];
3140+
}
3141+
31373142
void DisplayServerMacOS::process_events() {
31383143
ERR_FAIL_COND(!Thread::is_main_thread());
31393144

platform/windows/display_server_windows.cpp

+23
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ bool DisplayServerWindows::has_feature(Feature p_feature) const {
140140
case FEATURE_WINDOW_EMBEDDING:
141141
case FEATURE_SCREEN_EXCLUDE_FROM_CAPTURE:
142142
return true;
143+
case FEATURE_EMOJI_AND_SYMBOL_PICKER:
144+
return (os_ver.dwBuildNumber >= 17134); // Windows 10 Redstone 4 (1803)+ only.
143145
default:
144146
return false;
145147
}
@@ -3433,6 +3435,27 @@ Key DisplayServerWindows::keyboard_get_label_from_physical(Key p_keycode) const
34333435
return p_keycode;
34343436
}
34353437

3438+
void DisplayServerWindows::show_emoji_and_symbol_picker() const {
3439+
// Send Win + Period shortcut, there's no non-WinRT public API.
3440+
3441+
INPUT input[4] = {};
3442+
input[0].type = INPUT_KEYBOARD; // Win down.
3443+
input[0].ki.wVk = VK_LWIN;
3444+
3445+
input[1].type = INPUT_KEYBOARD; // Period down.
3446+
input[1].ki.wVk = VK_OEM_PERIOD;
3447+
3448+
input[2].type = INPUT_KEYBOARD; // Win up.
3449+
input[2].ki.wVk = VK_LWIN;
3450+
input[2].ki.dwFlags = KEYEVENTF_KEYUP;
3451+
3452+
input[3].type = INPUT_KEYBOARD; // Period up.
3453+
input[3].ki.wVk = VK_OEM_PERIOD;
3454+
input[3].ki.dwFlags = KEYEVENTF_KEYUP;
3455+
3456+
SendInput(4, input, sizeof(INPUT));
3457+
}
3458+
34363459
String DisplayServerWindows::_get_keyboard_layout_display_name(const String &p_klid) const {
34373460
String ret;
34383461
HKEY key;

platform/windows/display_server_windows.h

+1
Original file line numberDiff line numberDiff line change
@@ -842,6 +842,7 @@ class DisplayServerWindows : public DisplayServer {
842842
virtual String keyboard_get_layout_name(int p_index) const override;
843843
virtual Key keyboard_get_keycode_from_physical(Key p_keycode) const override;
844844
virtual Key keyboard_get_label_from_physical(Key p_keycode) const override;
845+
virtual void show_emoji_and_symbol_picker() const override;
845846

846847
virtual int tablet_get_driver_count() const override;
847848
virtual String tablet_get_driver_name(int p_driver) const override;

scene/gui/line_edit.cpp

+32-1
Original file line numberDiff line numberDiff line change
@@ -2369,7 +2369,10 @@ void LineEdit::menu_option(int p_option) {
23692369
if (editable) {
23702370
insert_text_at_caret(String::chr(0x00AD));
23712371
}
2372-
}
2372+
} break;
2373+
case MENU_EMOJI_AND_SYMBOL: {
2374+
show_emoji_and_symbol_picker();
2375+
} break;
23732376
}
23742377
}
23752378

@@ -2381,6 +2384,22 @@ bool LineEdit::is_context_menu_enabled() {
23812384
return context_menu_enabled;
23822385
}
23832386

2387+
void LineEdit::show_emoji_and_symbol_picker() {
2388+
_update_ime_window_position();
2389+
DisplayServer::get_singleton()->show_emoji_and_symbol_picker();
2390+
}
2391+
2392+
void LineEdit::set_emoji_menu_enabled(bool p_enabled) {
2393+
if (emoji_menu_enabled != p_enabled) {
2394+
emoji_menu_enabled = p_enabled;
2395+
_update_context_menu();
2396+
}
2397+
}
2398+
2399+
bool LineEdit::is_emoji_menu_enabled() const {
2400+
return emoji_menu_enabled;
2401+
}
2402+
23842403
bool LineEdit::is_menu_visible() const {
23852404
return menu && menu->is_visible();
23862405
}
@@ -2709,6 +2728,11 @@ void LineEdit::_generate_context_menu() {
27092728
menu_ctl->add_item(ETR("Word Joiner (WJ)"), MENU_INSERT_WJ);
27102729
menu_ctl->add_item(ETR("Soft Hyphen (SHY)"), MENU_INSERT_SHY);
27112730

2731+
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_EMOJI_AND_SYMBOL_PICKER)) {
2732+
menu->add_item(ETR("Emoji & Symbols"), MENU_EMOJI_AND_SYMBOL);
2733+
menu->add_separator();
2734+
}
2735+
27122736
menu->add_item(ETR("Cut"), MENU_CUT);
27132737
menu->add_item(ETR("Copy"), MENU_COPY);
27142738
menu->add_item(ETR("Paste"), MENU_PASTE);
@@ -2764,6 +2788,9 @@ void LineEdit::_update_context_menu() {
27642788
m_menu->set_item_checked(idx, m_checked); \
27652789
}
27662790

2791+
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_EMOJI_AND_SYMBOL_PICKER)) {
2792+
MENU_ITEM_DISABLED(menu, MENU_EMOJI_AND_SYMBOL, !editable || !emoji_menu_enabled)
2793+
}
27672794
MENU_ITEM_ACTION_DISABLED(menu, MENU_CUT, "ui_cut", !editable)
27682795
MENU_ITEM_ACTION(menu, MENU_COPY, "ui_copy")
27692796
MENU_ITEM_ACTION_DISABLED(menu, MENU_PASTE, "ui_paste", !editable)
@@ -2859,6 +2886,8 @@ void LineEdit::_bind_methods() {
28592886
ClassDB::bind_method(D_METHOD("is_menu_visible"), &LineEdit::is_menu_visible);
28602887
ClassDB::bind_method(D_METHOD("set_context_menu_enabled", "enable"), &LineEdit::set_context_menu_enabled);
28612888
ClassDB::bind_method(D_METHOD("is_context_menu_enabled"), &LineEdit::is_context_menu_enabled);
2889+
ClassDB::bind_method(D_METHOD("set_emoji_menu_enabled", "enable"), &LineEdit::set_emoji_menu_enabled);
2890+
ClassDB::bind_method(D_METHOD("is_emoji_menu_enabled"), &LineEdit::is_emoji_menu_enabled);
28622891
ClassDB::bind_method(D_METHOD("set_virtual_keyboard_enabled", "enable"), &LineEdit::set_virtual_keyboard_enabled);
28632892
ClassDB::bind_method(D_METHOD("is_virtual_keyboard_enabled"), &LineEdit::is_virtual_keyboard_enabled);
28642893
ClassDB::bind_method(D_METHOD("set_virtual_keyboard_type", "type"), &LineEdit::set_virtual_keyboard_type);
@@ -2917,6 +2946,7 @@ void LineEdit::_bind_methods() {
29172946
BIND_ENUM_CONSTANT(MENU_INSERT_ZWNJ);
29182947
BIND_ENUM_CONSTANT(MENU_INSERT_WJ);
29192948
BIND_ENUM_CONSTANT(MENU_INSERT_SHY);
2949+
BIND_ENUM_CONSTANT(MENU_EMOJI_AND_SYMBOL);
29202950
BIND_ENUM_CONSTANT(MENU_MAX);
29212951

29222952
BIND_ENUM_CONSTANT(KEYBOARD_TYPE_DEFAULT);
@@ -2936,6 +2966,7 @@ void LineEdit::_bind_methods() {
29362966
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_editing_on_text_submit"), "set_keep_editing_on_text_submit", "is_editing_kept_on_text_submit");
29372967
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand_to_text_length"), "set_expand_to_text_length_enabled", "is_expand_to_text_length_enabled");
29382968
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled");
2969+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emoji_menu_enabled"), "set_emoji_menu_enabled", "is_emoji_menu_enabled");
29392970
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "virtual_keyboard_enabled"), "set_virtual_keyboard_enabled", "is_virtual_keyboard_enabled");
29402971
ADD_PROPERTY(PropertyInfo(Variant::INT, "virtual_keyboard_type", PROPERTY_HINT_ENUM, "Default,Multiline,Number,Decimal,Phone,Email,Password,URL"), "set_virtual_keyboard_type", "get_virtual_keyboard_type");
29412972
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clear_button_enabled"), "set_clear_button_enabled", "is_clear_button_enabled");

scene/gui/line_edit.h

+7
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ class LineEdit : public Control {
6969
MENU_INSERT_ZWNJ,
7070
MENU_INSERT_WJ,
7171
MENU_INSERT_SHY,
72+
MENU_EMOJI_AND_SYMBOL,
7273
MENU_MAX
7374
};
7475

@@ -112,6 +113,7 @@ class LineEdit : public Control {
112113
bool drag_and_drop_selection_enabled = true;
113114

114115
bool context_menu_enabled = true;
116+
bool emoji_menu_enabled = true;
115117
PopupMenu *menu = nullptr;
116118
PopupMenu *menu_dir = nullptr;
117119
PopupMenu *menu_ctl = nullptr;
@@ -289,6 +291,11 @@ class LineEdit : public Control {
289291
PopupMenu *get_menu() const;
290292
bool is_menu_visible() const;
291293

294+
void show_emoji_and_symbol_picker();
295+
296+
void set_emoji_menu_enabled(bool p_enabled);
297+
bool is_emoji_menu_enabled() const;
298+
292299
void select(int p_from = 0, int p_to = -1);
293300
void select_all();
294301
void selection_delete();

scene/gui/spin_box.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,7 @@ void SpinBox::_bind_methods() {
622622

623623
SpinBox::SpinBox() {
624624
line_edit = memnew(LineEdit);
625+
line_edit->set_emoji_menu_enabled(false);
625626
add_child(line_edit, false, INTERNAL_MODE_FRONT);
626627

627628
line_edit->set_theme_type_variation("SpinBoxInnerLineEdit");

0 commit comments

Comments
 (0)