[Input] Add extra shortcut_input input processing step to process Unicode character input with Alt / Ctrl modifiers, after processing of shortcuts.

This commit is contained in:
bruvzg 2022-01-11 15:59:52 +02:00
parent 479143ab2a
commit d1207a0504
No known key found for this signature in database
GPG Key ID: 7960FCF39844EC38
41 changed files with 183 additions and 52 deletions

View File

@ -84,6 +84,17 @@
[b]Note:[/b] [method _ready] may be called only once for each node. After removing a node from the scene tree and adding it again, [code]_ready[/code] will not be called a second time. This can be bypassed by requesting another call with [method request_ready], which may be called anywhere before adding the node again.
</description>
</method>
<method name="_shortcut_input" qualifiers="virtual">
<return type="void" />
<argument index="0" name="event" type="InputEvent" />
<description>
Called when an [InputEventKey] or [InputEventShortcut] hasn't been consumed by [method _input] or any GUI [Control] item. The input event propagates up through the node tree until a node consumes it.
It is only called if shortcut processing is enabled, which is done automatically if this method is overridden, and can be toggled with [method set_process_shortcut_input].
To consume the input event and stop it propagating further to other nodes, [method Viewport.set_input_as_handled] can be called.
This method can be used to handle shortcuts.
[b]Note:[/b] This method is only called if the node is present in the scene tree (i.e. if it's not orphan).
</description>
</method>
<method name="_unhandled_input" qualifiers="virtual">
<return type="void" />
<argument index="0" name="event" type="InputEvent" />
@ -102,6 +113,7 @@
Called when an [InputEventKey] or [InputEventShortcut] hasn't been consumed by [method _input] or any GUI [Control] item. The input event propagates up through the node tree until a node consumes it.
It is only called if unhandled key input processing is enabled, which is done automatically if this method is overridden, and can be toggled with [method set_process_unhandled_key_input].
To consume the input event and stop it propagating further to other nodes, [method Viewport.set_input_as_handled] can be called.
This method can be used to handle Unicode character input with [kbd]Alt[/kbd], [kbd]Alt + Ctrl[/kbd], and [kbd]Alt + Shift[/kbd] modifiers, after shortcuts were handled.
For gameplay input, this and [method _unhandled_input] are usually a better fit than [method _input] as they allow the GUI to intercept the events first.
[b]Note:[/b] This method is only called if the node is present in the scene tree (i.e. if it's not an orphan).
</description>
@ -462,6 +474,12 @@
Returns [code]true[/code] if internal processing is enabled (see [method set_process_internal]).
</description>
</method>
<method name="is_processing_shortcut_input" qualifiers="const">
<return type="bool" />
<description>
Returns [code]true[/code] if the node is processing shortcuts (see [method set_process_shortcut_input]).
</description>
</method>
<method name="is_processing_unhandled_input" qualifiers="const">
<return type="bool" />
<description>
@ -673,6 +691,13 @@
[b]Warning:[/b] Built-in Nodes rely on the internal processing for their own logic, so changing this value from your code may lead to unexpected behavior. Script access to this internal logic is provided for specific advanced uses, but is unsafe and not supported.
</description>
</method>
<method name="set_process_shortcut_input">
<return type="void" />
<argument index="0" name="enable" type="bool" />
<description>
Enables shortcut processing. Enabled automatically if [method _shortcut_input] is overridden. Any calls to this before [method _ready] will be ignored.
</description>
</method>
<method name="set_process_unhandled_input">
<return type="void" />
<argument index="0" name="enable" type="bool" />

View File

@ -106,7 +106,7 @@ void EditorFileDialog::_notification(int p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
if (!is_visible()) {
set_process_unhandled_input(false);
set_process_shortcut_input(false);
}
} break;
@ -126,7 +126,7 @@ void EditorFileDialog::_notification(int p_what) {
}
}
void EditorFileDialog::unhandled_input(const Ref<InputEvent> &p_event) {
void EditorFileDialog::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
Ref<InputEventKey> k = p_event;
@ -327,7 +327,7 @@ void EditorFileDialog::_post_popup() {
_update_favorites();
}
set_process_unhandled_input(true);
set_process_shortcut_input(true);
}
void EditorFileDialog::_thumbnail_result(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, const Variant &p_udata) {

View File

@ -201,7 +201,7 @@ private:
void _thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, const Variant &p_udata);
void _request_single_thumbnail(const String &p_path);
virtual void unhandled_input(const Ref<InputEvent> &p_event) override;
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
bool _is_open_should_be_disabled();

View File

@ -685,7 +685,7 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) {
}
}
void EditorProperty::unhandled_key_input(const Ref<InputEvent> &p_event) {
void EditorProperty::shortcut_input(const Ref<InputEvent> &p_event) {
if (!selected || !p_event->is_pressed()) {
return;
}
@ -971,7 +971,7 @@ EditorProperty::EditorProperty() {
label_reference = nullptr;
bottom_editor = nullptr;
menu = nullptr;
set_process_unhandled_key_input(true);
set_process_shortcut_input(true);
}
void EditorProperty::_update_popup() {

View File

@ -128,7 +128,7 @@ protected:
virtual void _set_read_only(bool p_read_only);
virtual void gui_input(const Ref<InputEvent> &p_event) override;
virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
const Color *_get_property_colors();
public:

View File

@ -430,7 +430,7 @@ void EditorNode::_update_title() {
DisplayServer::get_singleton()->window_set_title(title);
}
void EditorNode::unhandled_input(const Ref<InputEvent> &p_event) {
void EditorNode::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
Ref<InputEventKey> k = p_event;
@ -7168,7 +7168,7 @@ EditorNode::EditorNode() {
_update_recent_scenes();
editor_data.restore_editor_global_states();
set_process_unhandled_input(true);
set_process_shortcut_input(true);
load_errors = memnew(RichTextLabel);
load_error_dialog = memnew(AcceptDialog);

View File

@ -585,7 +585,7 @@ private:
void _exit_editor(int p_exit_code);
virtual void unhandled_input(const Ref<InputEvent> &p_event) override;
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
bool has_main_screen() const { return true; }

View File

@ -92,7 +92,7 @@ void EditorSettingsDialog::popup_edit_settings() {
search_box->grab_focus();
_update_shortcuts();
set_process_unhandled_input(true);
set_process_shortcut_input(true);
// Restore valid window bounds or pop up at default size.
Rect2 saved_size = EditorSettings::get_singleton()->get_project_metadata("dialog_bounds", "editor_settings", Rect2());
@ -119,7 +119,7 @@ void EditorSettingsDialog::_notification(int p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
if (!is_visible()) {
EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "editor_settings", Rect2(get_position(), get_size()));
set_process_unhandled_input(false);
set_process_shortcut_input(false);
}
} break;
@ -148,7 +148,7 @@ void EditorSettingsDialog::_notification(int p_what) {
}
}
void EditorSettingsDialog::unhandled_input(const Ref<InputEvent> &p_event) {
void EditorSettingsDialog::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
const Ref<InputEventKey> k = p_event;

View File

@ -82,7 +82,7 @@ class EditorSettingsDialog : public AcceptDialog {
void _settings_property_edited(const String &p_name);
void _settings_save();
virtual void unhandled_input(const Ref<InputEvent> &p_event) override;
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
void _notification(int p_what);
void _update_icons();

View File

@ -1267,7 +1267,7 @@ void AnimationPlayerEditor::_onion_skinning_menu(int p_option) {
}
}
void AnimationPlayerEditor::unhandled_key_input(const Ref<InputEvent> &p_ev) {
void AnimationPlayerEditor::shortcut_input(const Ref<InputEvent> &p_ev) {
ERR_FAIL_COND(p_ev.is_null());
Ref<InputEventKey> k = p_ev;
@ -1750,7 +1750,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
last_active = false;
timeline_position = 0;
set_process_unhandled_key_input(true);
set_process_shortcut_input(true);
add_child(track_editor);
track_editor->set_v_size_flags(SIZE_EXPAND_FILL);

View File

@ -204,7 +204,7 @@ class AnimationPlayerEditor : public VBoxContainer {
void _animation_key_editor_seek(float p_pos, bool p_drag, bool p_timeline_only = false);
void _animation_key_editor_anim_len_changed(float p_len);
virtual void unhandled_key_input(const Ref<InputEvent> &p_ev) override;
virtual void shortcut_input(const Ref<InputEvent> &p_ev) override;
void _animation_tool_menu(int p_option);
void _onion_skinning_menu(int p_option);

View File

@ -640,7 +640,7 @@ void EditorAssetLibrary::_update_repository_options() {
}
}
void EditorAssetLibrary::unhandled_key_input(const Ref<InputEvent> &p_event) {
void EditorAssetLibrary::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
const Ref<InputEventKey> key = p_event;
@ -1541,7 +1541,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
description = nullptr;
set_process(true);
set_process_unhandled_key_input(true); // Global shortcuts since there is no main element to be focused.
set_process_shortcut_input(true); // Global shortcuts since there is no main element to be focused.
downloads_scroll = memnew(ScrollContainer);
downloads_scroll->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);

View File

@ -304,7 +304,7 @@ class EditorAssetLibrary : public PanelContainer {
protected:
static void _bind_methods();
void _notification(int p_what);
virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
public:
void disable_community_support();

View File

@ -475,7 +475,7 @@ real_t CanvasItemEditor::snap_angle(real_t p_target, real_t p_start) const {
}
}
void CanvasItemEditor::unhandled_key_input(const Ref<InputEvent> &p_ev) {
void CanvasItemEditor::shortcut_input(const Ref<InputEvent> &p_ev) {
ERR_FAIL_COND(p_ev.is_null());
Ref<InputEventKey> k = p_ev;
@ -5322,7 +5322,7 @@ CanvasItemEditor::CanvasItemEditor() {
ED_SHORTCUT("canvas_item_editor/zoom_800_percent", TTR("Zoom to 800%"), Key::KEY_4);
ED_SHORTCUT("canvas_item_editor/zoom_1600_percent", TTR("Zoom to 1600%"), Key::KEY_5);
set_process_unhandled_key_input(true);
set_process_shortcut_input(true);
// Update the menus' checkboxes
call_deferred(SNAME("set_state"), get_state());

View File

@ -413,7 +413,7 @@ private:
void _keying_changed();
virtual void unhandled_key_input(const Ref<InputEvent> &p_ev) override;
virtual void shortcut_input(const Ref<InputEvent> &p_ev) override;
void _draw_text_at_position(Point2 p_position, String p_string, Side p_side);
void _draw_margin_at_position(int p_value, Point2 p_position, Side p_side);

View File

@ -6848,7 +6848,7 @@ void Node3DEditor::snap_selected_nodes_to_floor() {
}
}
void Node3DEditor::unhandled_key_input(const Ref<InputEvent> &p_event) {
void Node3DEditor::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (!is_visible_in_tree()) {
@ -7893,7 +7893,7 @@ Node3DEditor::Node3DEditor() {
selected = nullptr;
set_process_unhandled_key_input(true);
set_process_shortcut_input(true);
add_to_group("_spatial_editor_group");
EDITOR_DEF("editors/3d/manipulator_gizmo_size", 80);

View File

@ -770,7 +770,7 @@ private:
protected:
void _notification(int p_what);
//void _gui_input(InputEvent p_event);
virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
static void _bind_methods();

View File

@ -3019,7 +3019,7 @@ void ScriptEditor::input(const Ref<InputEvent> &p_event) {
}
}
void ScriptEditor::unhandled_key_input(const Ref<InputEvent> &p_event) {
void ScriptEditor::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (!is_visible_in_tree() || !p_event->is_pressed() || p_event->is_echo()) {
@ -3740,7 +3740,7 @@ ScriptEditor::ScriptEditor() {
ED_SHORTCUT("script_editor/next_script", TTR("Next Script"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::PERIOD);
ED_SHORTCUT("script_editor/prev_script", TTR("Previous Script"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::COMMA);
set_process_input(true);
set_process_unhandled_key_input(true);
set_process_shortcut_input(true);
file_menu = memnew(MenuButton);
file_menu->set_text(TTR("File"));

View File

@ -426,7 +426,7 @@ class ScriptEditor : public PanelContainer {
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
virtual void input(const Ref<InputEvent> &p_event) override;
virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
void _script_list_gui_input(const Ref<InputEvent> &ev);
void _make_script_list_context_menu();

View File

@ -1903,7 +1903,7 @@ void ProjectManager::_notification(int p_what) {
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
set_process_unhandled_key_input(is_visible_in_tree());
set_process_shortcut_input(is_visible_in_tree());
} break;
case NOTIFICATION_WM_CLOSE_REQUEST: {
@ -1962,7 +1962,7 @@ void ProjectManager::_update_project_buttons() {
erase_missing_btn->set_disabled(!_project_list->is_any_project_missing());
}
void ProjectManager::unhandled_key_input(const Ref<InputEvent> &p_ev) {
void ProjectManager::shortcut_input(const Ref<InputEvent> &p_ev) {
ERR_FAIL_COND(p_ev.is_null());
Ref<InputEventKey> k = p_ev;

View File

@ -126,7 +126,7 @@ class ProjectManager : public Control {
void _install_project(const String &p_zip_path, const String &p_title);
void _dim_window();
virtual void unhandled_key_input(const Ref<InputEvent> &p_ev) override;
virtual void shortcut_input(const Ref<InputEvent> &p_ev) override;
void _files_dropped(PackedStringArray p_files, int p_screen);
void _version_button_pressed();

View File

@ -49,7 +49,7 @@ void ProjectSettingsEditor::popup_project_settings() {
_add_feature_overrides();
general_settings_inspector->update_category_list();
set_process_unhandled_input(true);
set_process_shortcut_input(true);
localization_editor->update_translations();
autoload_settings->update_autoload();
@ -202,7 +202,7 @@ void ProjectSettingsEditor::_select_type(Variant::Type p_type) {
type_box->select(type_box->get_item_index(p_type));
}
void ProjectSettingsEditor::unhandled_input(const Ref<InputEvent> &p_event) {
void ProjectSettingsEditor::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
const Ref<InputEventKey> k = p_event;

View File

@ -82,7 +82,7 @@ class ProjectSettingsEditor : public AcceptDialog {
void _feature_selected(int p_index);
void _select_type(Variant::Type p_type);
virtual void unhandled_input(const Ref<InputEvent> &p_event) override;
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
String _get_setting_name() const;
void _setting_edited(const String &p_name);

View File

@ -79,7 +79,7 @@ void SceneTreeDock::input(const Ref<InputEvent> &p_event) {
}
}
void SceneTreeDock::unhandled_key_input(const Ref<InputEvent> &p_event) {
void SceneTreeDock::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (get_viewport()->gui_get_focus_owner() && get_viewport()->gui_get_focus_owner()->is_text_field()) {
@ -3476,7 +3476,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
add_child(quick_open);
quick_open->connect("quick_open", callable_mp(this, &SceneTreeDock::_quick_open));
set_process_unhandled_key_input(true);
set_process_shortcut_input(true);
delete_dialog = memnew(ConfirmationDialog);
add_child(delete_dialog);

View File

@ -220,7 +220,7 @@ class SceneTreeDock : public VBoxContainer {
void _nodes_drag_begin();
virtual void input(const Ref<InputEvent> &p_event) override;
virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
void _import_subscene();

View File

@ -339,14 +339,14 @@ bool BaseButton::is_keep_pressed_outside() const {
void BaseButton::set_shortcut(const Ref<Shortcut> &p_shortcut) {
shortcut = p_shortcut;
set_process_unhandled_key_input(shortcut.is_valid());
set_process_shortcut_input(shortcut.is_valid());
}
Ref<Shortcut> BaseButton::get_shortcut() const {
return shortcut;
}
void BaseButton::unhandled_key_input(const Ref<InputEvent> &p_event) {
void BaseButton::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (!_is_focus_owner_in_shortcut_context()) {

View File

@ -77,7 +77,7 @@ protected:
virtual void toggled(bool p_pressed);
static void _bind_methods();
virtual void gui_input(const Ref<InputEvent> &p_event) override;
virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
void _notification(int p_what);
bool _is_focus_owner_in_shortcut_context() const;

View File

@ -95,7 +95,7 @@ void FileDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
if (!is_visible()) {
set_process_unhandled_input(false);
set_process_shortcut_input(false);
}
} break;
@ -119,7 +119,7 @@ void FileDialog::_notification(int p_what) {
}
}
void FileDialog::unhandled_input(const Ref<InputEvent> &p_event) {
void FileDialog::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
Ref<InputEventKey> k = p_event;
@ -217,7 +217,7 @@ void FileDialog::_post_popup() {
tree->grab_focus();
}
set_process_unhandled_input(true);
set_process_shortcut_input(true);
// For open dir mode, deselect all items on file dialog open.
if (mode == FILE_MODE_OPEN_DIR) {

View File

@ -133,7 +133,7 @@ private:
void _update_drives(bool p_select = true);
virtual void unhandled_input(const Ref<InputEvent> &p_event) override;
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
bool _is_open_should_be_disabled();

View File

@ -215,6 +215,27 @@ void LineEdit::_delete(bool p_word, bool p_all_to_right) {
}
}
void LineEdit::unhandled_key_input(const Ref<InputEvent> &p_event) {
Ref<InputEventKey> k = p_event;
if (k.is_valid()) {
if (!k->is_pressed()) {
return;
}
// Handle Unicode (with modifiers active, process after shortcuts).
if (has_focus() && editable && (k->get_unicode() >= 32)) {
selection_delete();
char32_t ucodestr[2] = { (char32_t)k->get_unicode(), 0 };
int prev_len = text.length();
insert_text_at_caret(ucodestr);
if (text.length() != prev_len) {
_text_changed();
}
accept_event();
}
}
}
void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
@ -2445,6 +2466,7 @@ LineEdit::LineEdit(const String &p_placeholder) {
set_focus_mode(FOCUS_ALL);
set_default_cursor_shape(CURSOR_IBEAM);
set_mouse_filter(MOUSE_FILTER_STOP);
set_process_unhandled_key_input(true);
caret_blink_timer = memnew(Timer);
add_child(caret_blink_timer, false, INTERNAL_MODE_FRONT);

View File

@ -202,6 +202,7 @@ private:
protected:
void _notification(int p_what);
static void _bind_methods();
virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;
virtual void gui_input(const Ref<InputEvent> &p_event) override;
bool _set(const StringName &p_name, const Variant &p_value);

View File

@ -33,7 +33,7 @@
#include "core/os/keyboard.h"
#include "scene/main/window.h"
void MenuButton::unhandled_key_input(const Ref<InputEvent> &p_event) {
void MenuButton::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (!_is_focus_owner_in_shortcut_context()) {
@ -232,7 +232,7 @@ MenuButton::MenuButton(const String &p_text) :
set_flat(true);
set_toggle_mode(true);
set_disable_shortcuts(false);
set_process_unhandled_key_input(true);
set_process_shortcut_input(true);
set_focus_mode(FOCUS_NONE);
set_action_mode(ACTION_MODE_BUTTON_PRESS);

View File

@ -54,7 +54,7 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
static void _bind_methods();
virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
public:
virtual void pressed() override;

View File

@ -1542,6 +1542,21 @@ void TextEdit::_notification(int p_what) {
}
}
void TextEdit::unhandled_key_input(const Ref<InputEvent> &p_event) {
Ref<InputEventKey> k = p_event;
if (k.is_valid()) {
if (!k->is_pressed()) {
return;
}
// Handle Unicode (with modifiers active, process after shortcuts).
if (has_focus() && editable && (k->get_unicode() >= 32)) {
handle_unicode_input(k->get_unicode());
accept_event();
}
}
}
void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
ERR_FAIL_COND(p_gui_input.is_null());
@ -6620,6 +6635,7 @@ TextEdit::TextEdit(const String &p_placeholder) {
set_focus_mode(FOCUS_ALL);
_update_caches();
set_default_cursor_shape(CURSOR_IBEAM);
set_process_unhandled_key_input(true);
text.set_tab_size(text.get_tab_size());

View File

@ -623,6 +623,7 @@ protected:
public:
/* General overrides. */
virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;
virtual void gui_input(const Ref<InputEvent> &p_gui_input) override;
virtual Size2 get_minimum_size() const override;
virtual bool is_text_field() const override;

View File

@ -79,6 +79,9 @@ void Node::_notification(int p_notification) {
if (data.input) {
add_to_group("_vp_input" + itos(get_viewport()->get_instance_id()));
}
if (data.shortcut_input) {
add_to_group("_vp_shortcut_input" + itos(get_viewport()->get_instance_id()));
}
if (data.unhandled_input) {
add_to_group("_vp_unhandled_input" + itos(get_viewport()->get_instance_id()));
}
@ -100,6 +103,9 @@ void Node::_notification(int p_notification) {
if (data.input) {
remove_from_group("_vp_input" + itos(get_viewport()->get_instance_id()));
}
if (data.shortcut_input) {
remove_from_group("_vp_shortcut_input" + itos(get_viewport()->get_instance_id()));
}
if (data.unhandled_input) {
remove_from_group("_vp_unhandled_input" + itos(get_viewport()->get_instance_id()));
}
@ -126,6 +132,10 @@ void Node::_notification(int p_notification) {
set_process_input(true);
}
if (GDVIRTUAL_IS_OVERRIDDEN(_shortcut_input)) {
set_process_shortcut_input(true);
}
if (GDVIRTUAL_IS_OVERRIDDEN(_unhandled_input)) {
set_process_unhandled_input(true);
}
@ -835,6 +845,26 @@ bool Node::is_processing_input() const {
return data.input;
}
void Node::set_process_shortcut_input(bool p_enable) {
if (p_enable == data.shortcut_input) {
return;
}
data.shortcut_input = p_enable;
if (!is_inside_tree()) {
return;
}
if (p_enable) {
add_to_group("_vp_shortcut_input" + itos(get_viewport()->get_instance_id()));
} else {
remove_from_group("_vp_shortcut_input" + itos(get_viewport()->get_instance_id()));
}
}
bool Node::is_processing_shortcut_input() const {
return data.shortcut_input;
}
void Node::set_process_unhandled_input(bool p_enable) {
if (p_enable == data.unhandled_input) {
return;
@ -2615,6 +2645,15 @@ void Node::_call_input(const Ref<InputEvent> &p_event) {
}
input(p_event);
}
void Node::_call_shortcut_input(const Ref<InputEvent> &p_event) {
GDVIRTUAL_CALL(_shortcut_input, p_event);
if (!is_inside_tree() || !get_viewport() || get_viewport()->is_input_handled()) {
return;
}
shortcut_input(p_event);
}
void Node::_call_unhandled_input(const Ref<InputEvent> &p_event) {
GDVIRTUAL_CALL(_unhandled_input, p_event);
if (!is_inside_tree() || !get_viewport() || get_viewport()->is_input_handled()) {
@ -2622,6 +2661,7 @@ void Node::_call_unhandled_input(const Ref<InputEvent> &p_event) {
}
unhandled_input(p_event);
}
void Node::_call_unhandled_key_input(const Ref<InputEvent> &p_event) {
GDVIRTUAL_CALL(_unhandled_key_input, p_event);
if (!is_inside_tree() || !get_viewport() || get_viewport()->is_input_handled()) {
@ -2633,6 +2673,9 @@ void Node::_call_unhandled_key_input(const Ref<InputEvent> &p_event) {
void Node::input(const Ref<InputEvent> &p_event) {
}
void Node::shortcut_input(const Ref<InputEvent> &p_key_event) {
}
void Node::unhandled_input(const Ref<InputEvent> &p_event) {
}
@ -2694,6 +2737,8 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_processing"), &Node::is_processing);
ClassDB::bind_method(D_METHOD("set_process_input", "enable"), &Node::set_process_input);
ClassDB::bind_method(D_METHOD("is_processing_input"), &Node::is_processing_input);
ClassDB::bind_method(D_METHOD("set_process_shortcut_input", "enable"), &Node::set_process_shortcut_input);
ClassDB::bind_method(D_METHOD("is_processing_shortcut_input"), &Node::is_processing_shortcut_input);
ClassDB::bind_method(D_METHOD("set_process_unhandled_input", "enable"), &Node::set_process_unhandled_input);
ClassDB::bind_method(D_METHOD("is_processing_unhandled_input"), &Node::is_processing_unhandled_input);
ClassDB::bind_method(D_METHOD("set_process_unhandled_key_input", "enable"), &Node::set_process_unhandled_key_input);
@ -2854,6 +2899,7 @@ void Node::_bind_methods() {
GDVIRTUAL_BIND(_ready);
GDVIRTUAL_BIND(_get_configuration_warnings);
GDVIRTUAL_BIND(_input, "event");
GDVIRTUAL_BIND(_shortcut_input, "event");
GDVIRTUAL_BIND(_unhandled_input, "event");
GDVIRTUAL_BIND(_unhandled_key_input, "event");
}

View File

@ -136,6 +136,7 @@ private:
bool process_internal = false;
bool input = false;
bool shortcut_input = false;
bool unhandled_input = false;
bool unhandled_key_input = false;
@ -215,11 +216,13 @@ protected:
//call from SceneTree
void _call_input(const Ref<InputEvent> &p_event);
void _call_shortcut_input(const Ref<InputEvent> &p_event);
void _call_unhandled_input(const Ref<InputEvent> &p_event);
void _call_unhandled_key_input(const Ref<InputEvent> &p_event);
protected:
virtual void input(const Ref<InputEvent> &p_event);
virtual void shortcut_input(const Ref<InputEvent> &p_key_event);
virtual void unhandled_input(const Ref<InputEvent> &p_event);
virtual void unhandled_key_input(const Ref<InputEvent> &p_key_event);
@ -231,6 +234,7 @@ protected:
GDVIRTUAL0RC(Vector<String>, _get_configuration_warnings)
GDVIRTUAL1(_input, Ref<InputEvent>)
GDVIRTUAL1(_shortcut_input, Ref<InputEvent>)
GDVIRTUAL1(_unhandled_input, Ref<InputEvent>)
GDVIRTUAL1(_unhandled_key_input, Ref<InputEvent>)
@ -395,6 +399,9 @@ public:
void set_process_input(bool p_enable);
bool is_processing_input() const;
void set_process_shortcut_input(bool p_enable);
bool is_processing_shortcut_input() const;
void set_process_unhandled_input(bool p_enable);
bool is_processing_unhandled_input() const;

View File

@ -897,6 +897,9 @@ void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_cal
case CALL_INPUT_TYPE_INPUT:
n->_call_input(p_input);
break;
case CALL_INPUT_TYPE_SHORTCUT_INPUT:
n->_call_shortcut_input(p_input);
break;
case CALL_INPUT_TYPE_UNHANDLED_INPUT:
n->_call_unhandled_input(p_input);
break;

View File

@ -204,6 +204,7 @@ private:
enum CallInputType {
CALL_INPUT_TYPE_INPUT,
CALL_INPUT_TYPE_SHORTCUT_INPUT,
CALL_INPUT_TYPE_UNHANDLED_INPUT,
CALL_INPUT_TYPE_UNHANDLED_KEY_INPUT,
};

View File

@ -2744,11 +2744,18 @@ void Viewport::push_unhandled_input(const Ref<InputEvent> &p_event, bool p_local
ev = p_event;
}
// Unhandled Input.
get_tree()->_call_input_pause(unhandled_input_group, SceneTree::CALL_INPUT_TYPE_UNHANDLED_INPUT, ev, this);
// Shortcut Input.
if (Object::cast_to<InputEventKey>(*ev) != nullptr || Object::cast_to<InputEventShortcut>(*ev) != nullptr) {
get_tree()->_call_input_pause(shortcut_input_group, SceneTree::CALL_INPUT_TYPE_SHORTCUT_INPUT, ev, this);
}
// Unhandled key Input - used for performance reasons - This is called a lot less than _unhandled_input since it ignores MouseMotion, etc.
if (!is_input_handled() && (Object::cast_to<InputEventKey>(*ev) != nullptr || Object::cast_to<InputEventShortcut>(*ev) != nullptr)) {
// Unhandled Input.
if (!is_input_handled()) {
get_tree()->_call_input_pause(unhandled_input_group, SceneTree::CALL_INPUT_TYPE_UNHANDLED_INPUT, ev, this);
}
// Unhandled key Input - Used for performance reasons - This is called a lot less than _unhandled_input since it ignores MouseMotion, and to handle Unicode input with Alt / Ctrl modifiers after handling shortcuts.
if (!is_input_handled() && (Object::cast_to<InputEventKey>(*ev) != nullptr)) {
get_tree()->_call_input_pause(unhandled_key_input_group, SceneTree::CALL_INPUT_TYPE_UNHANDLED_KEY_INPUT, ev, this);
}
@ -3879,6 +3886,7 @@ Viewport::Viewport() {
input_group = "_vp_input" + id;
gui_input_group = "_vp_gui_input" + id;
unhandled_input_group = "_vp_unhandled_input" + id;
shortcut_input_group = "_vp_shortcut_input" + id;
unhandled_key_input_group = "_vp_unhandled_key_input" + id;
// Window tooltip.

View File

@ -270,6 +270,7 @@ private:
Rect2i to_screen_rect;
StringName input_group;
StringName gui_input_group;
StringName shortcut_input_group;
StringName unhandled_input_group;
StringName unhandled_key_input_group;