Add an additional input stage after physics picking

Allow handling events, that were not used during physics picking.

(cherry picked from commit godotengine/godot@fbd5d2ba8b)
This commit is contained in:
Markus Sauermann
2023-07-23 15:47:37 +02:00
committed by Spartan322
parent fe04f5ff9b
commit d14035edcc
8 changed files with 96 additions and 0 deletions

View File

@@ -130,6 +130,17 @@
[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>
</method>
<method name="_unhandled_picking_input" qualifiers="virtual">
<return type="void" />
<param index="0" name="event" type="InputEvent" />
<description>
Called when an [InputEventKey] hasn't been consumed by physics picking. The input event propagates up through the node tree in the current [Viewport] until a node consumes it.
It is only called if unhandled picking input processing is enabled, which is done automatically if this method is overridden, and can be toggled with [method set_process_unhandled_picking_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 mouse and touch events that were not set to handled during physics picking.
[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>
</method>
<method name="add_child">
<return type="void" />
<param index="0" name="node" type="Node" />
@@ -688,6 +699,12 @@
Returns [code]true[/code] if the node is processing unhandled key input (see [method set_process_unhandled_key_input]).
</description>
</method>
<method name="is_processing_unhandled_picking_input" qualifiers="const">
<return type="bool" />
<description>
Returns [code]true[/code] if the node is processing unhandled physics input (see [method set_process_unhandled_picking_input]).
</description>
</method>
<method name="move_child">
<return type="void" />
<param index="0" name="child_node" type="Node" />
@@ -952,6 +969,13 @@
[b]Note:[/b] If [method _unhandled_key_input] is overridden, this will be automatically enabled before [method _ready] is called.
</description>
</method>
<method name="set_process_unhandled_picking_input">
<return type="void" />
<param index="0" name="enable" type="bool" />
<description>
Enables unhandled picking input processing. Enabled automatically if [method _unhandled_picking_input] is overridden. Any calls to this before [method _ready] will be ignored.
</description>
</method>
<method name="set_scene_instance_load_placeholder">
<return type="void" />
<param index="0" name="load_placeholder" type="bool" />

View File

@@ -209,6 +209,10 @@ void Node::_notification(int p_notification) {
set_process_unhandled_key_input(true);
}
if (GDVIRTUAL_IS_OVERRIDDEN(_unhandled_picking_input)) {
set_process_unhandled_picking_input(true);
}
if (GDVIRTUAL_IS_OVERRIDDEN(_process)) {
set_process(true);
}
@@ -1255,6 +1259,27 @@ bool Node::is_processing_unhandled_key_input() const {
return data.unhandled_key_input;
}
void Node::set_process_unhandled_picking_input(bool p_enable) {
ERR_THREAD_GUARD
if (p_enable == data.unhandled_picking_input) {
return;
}
data.unhandled_picking_input = p_enable;
if (!is_inside_tree()) {
return;
}
if (p_enable) {
add_to_group("_vp_unhandled_picking_input" + itos(get_viewport()->get_instance_id()));
} else {
remove_from_group("_vp_unhandled_picking_input" + itos(get_viewport()->get_instance_id()));
}
}
bool Node::is_processing_unhandled_picking_input() const {
return data.unhandled_picking_input;
}
void Node::set_auto_translate_mode(AutoTranslateMode p_mode) {
ERR_THREAD_GUARD
if (data.auto_translate_mode == p_mode) {
@@ -3387,6 +3412,16 @@ void Node::_call_unhandled_key_input(const Ref<InputEvent> &p_event) {
unhandled_key_input(p_event);
}
void Node::_call_unhandled_picking_input(const Ref<InputEvent> &p_event) {
if (p_event->get_device() != InputEvent::DEVICE_ID_INTERNAL) {
GDVIRTUAL_CALL(_unhandled_picking_input, p_event);
}
if (!is_inside_tree() || !get_viewport() || get_viewport()->is_input_handled()) {
return;
}
unhandled_key_input(p_event);
}
void Node::_validate_property(PropertyInfo &p_property) const {
if ((p_property.name == "process_thread_group_order" || p_property.name == "process_thread_messages") && data.process_thread_group == PROCESS_THREAD_GROUP_INHERIT) {
p_property.usage = 0;
@@ -3405,6 +3440,9 @@ void Node::unhandled_input(const Ref<InputEvent> &p_event) {
void Node::unhandled_key_input(const Ref<InputEvent> &p_key_event) {
}
void Node::unhandled_picking_input(const Ref<InputEvent> &p_picking_event) {
}
Variant Node::_call_deferred_thread_group_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
if (p_argcount < 1) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
@@ -3558,6 +3596,8 @@ void Node::_bind_methods() {
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);
ClassDB::bind_method(D_METHOD("is_processing_unhandled_key_input"), &Node::is_processing_unhandled_key_input);
ClassDB::bind_method(D_METHOD("set_process_unhandled_picking_input", "enable"), &Node::set_process_unhandled_picking_input);
ClassDB::bind_method(D_METHOD("is_processing_unhandled_picking_input"), &Node::is_processing_unhandled_picking_input);
ClassDB::bind_method(D_METHOD("set_process_mode", "mode"), &Node::set_process_mode);
ClassDB::bind_method(D_METHOD("get_process_mode"), &Node::get_process_mode);
ClassDB::bind_method(D_METHOD("can_process"), &Node::can_process);
@@ -3795,6 +3835,7 @@ void Node::_bind_methods() {
GDVIRTUAL_BIND(_shortcut_input, "event");
GDVIRTUAL_BIND(_unhandled_input, "event");
GDVIRTUAL_BIND(_unhandled_key_input, "event");
GDVIRTUAL_BIND(_unhandled_picking_input, "event");
}
String Node::_get_name_num_separator() {
@@ -3829,6 +3870,7 @@ Node::Node() {
data.shortcut_input = false;
data.unhandled_input = false;
data.unhandled_key_input = false;
data.unhandled_picking_input = false;
data.physics_interpolated = true;

View File

@@ -221,6 +221,7 @@ private:
bool shortcut_input : 1;
bool unhandled_input : 1;
bool unhandled_key_input : 1;
bool unhandled_picking_input : 1;
// Physics interpolation can be turned on and off on a per node basis.
// This only takes effect when the SceneTree (or project setting) physics interpolation
@@ -341,6 +342,7 @@ protected:
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);
void _call_unhandled_picking_input(const Ref<InputEvent> &p_event);
void _validate_property(PropertyInfo &p_property) const;
@@ -349,6 +351,7 @@ protected:
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);
virtual void unhandled_picking_input(const Ref<InputEvent> &p_picking_event);
GDVIRTUAL1(_process, double)
GDVIRTUAL1(_physics_process, double)
@@ -361,6 +364,7 @@ protected:
GDVIRTUAL1(_shortcut_input, Ref<InputEvent>)
GDVIRTUAL1(_unhandled_input, Ref<InputEvent>)
GDVIRTUAL1(_unhandled_key_input, Ref<InputEvent>)
GDVIRTUAL1(_unhandled_picking_input, Ref<InputEvent>)
public:
enum {
@@ -578,6 +582,9 @@ public:
void set_process_unhandled_key_input(bool p_enable);
bool is_processing_unhandled_key_input() const;
void set_process_unhandled_picking_input(bool p_enable);
bool is_processing_unhandled_picking_input() const;
_FORCE_INLINE_ bool _is_any_processing() const {
return data.process || data.process_internal || data.physics_process || data.physics_process_internal;
}

View File

@@ -1232,6 +1232,9 @@ void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_cal
case CALL_INPUT_TYPE_UNHANDLED_KEY_INPUT:
n->_call_unhandled_key_input(p_input);
break;
case CALL_INPUT_TYPE_UNHANDLED_PICKING_INPUT:
n->_call_unhandled_picking_input(p_input);
break;
}
}

View File

@@ -257,6 +257,7 @@ private:
CALL_INPUT_TYPE_SHORTCUT_INPUT,
CALL_INPUT_TYPE_UNHANDLED_INPUT,
CALL_INPUT_TYPE_UNHANDLED_KEY_INPUT,
CALL_INPUT_TYPE_UNHANDLED_PICKING_INPUT,
};
//used by viewport

View File

@@ -961,6 +961,11 @@ void Viewport::_process_picking() {
}
}
#endif // _3D_DISABLED
if (!local_input_handled) {
ERR_FAIL_COND(!is_inside_tree());
get_tree()->_call_input_pause(unhandled_picking_input_group, SceneTree::CALL_INPUT_TYPE_UNHANDLED_PICKING_INPUT, ev, this);
}
}
}
@@ -5015,6 +5020,7 @@ Viewport::Viewport() {
unhandled_input_group = "_vp_unhandled_input" + id;
shortcut_input_group = "_vp_shortcut_input" + id;
unhandled_key_input_group = "_vp_unhandled_key_input" + id;
unhandled_picking_input_group = "_vp_unhandled_picking_input" + id;
// Window tooltip.
gui.tooltip_delay = GLOBAL_GET("gui/timers/tooltip_delay_sec");

View File

@@ -278,6 +278,7 @@ private:
StringName shortcut_input_group;
StringName unhandled_input_group;
StringName unhandled_key_input_group;
StringName unhandled_picking_input_group;
void _update_audio_listener_2d();

View File

@@ -673,6 +673,18 @@ TEST_CASE("[Node] Processing checks") {
CHECK_FALSE(node->is_processing_unhandled_key_input());
}
SUBCASE("Unhandled picking input processing") {
CHECK_FALSE(node->is_processing_unhandled_picking_input());
node->set_process_unhandled_picking_input(true);
CHECK(node->is_processing_unhandled_picking_input());
node->set_process_unhandled_picking_input(false);
CHECK_FALSE(node->is_processing_unhandled_picking_input());
}
SUBCASE("Shortcut input processing") {
CHECK_FALSE(node->is_processing_shortcut_input());