Improve input event accumulation

- API has been simplified: all events now go through `parse_input_event()`. Whether they are accumulated or not depends on the `use_accumulated_input` flag.
- Event accumulation is now thread-safe (it was not needed so far, but it prepares the ground for the following changes).
- Touch drag events now support accumulation.
This commit is contained in:
Pedro J. Estébanez 2020-09-20 21:30:34 +02:00
parent 42e40a7d3c
commit 58a54f534e
8 changed files with 45 additions and 31 deletions

View file

@ -136,7 +136,6 @@ public:
virtual int get_joy_axis_index_from_string(String p_axis) = 0; virtual int get_joy_axis_index_from_string(String p_axis) = 0;
virtual void parse_input_event(const Ref<InputEvent> &p_event) = 0; virtual void parse_input_event(const Ref<InputEvent> &p_event) = 0;
virtual void accumulate_input_event(const Ref<InputEvent> &p_event) = 0;
virtual void flush_accumulated_events() = 0; virtual void flush_accumulated_events() = 0;
virtual void set_use_accumulated_input(bool p_enable) = 0; virtual void set_use_accumulated_input(bool p_enable) = 0;

View file

@ -966,6 +966,22 @@ String InputEventScreenDrag::as_text() const {
return "InputEventScreenDrag : index=" + itos(index) + ", position=(" + String(get_position()) + "), relative=(" + String(get_relative()) + "), speed=(" + String(get_speed()) + ")"; return "InputEventScreenDrag : index=" + itos(index) + ", position=(" + String(get_position()) + "), relative=(" + String(get_relative()) + "), speed=(" + String(get_speed()) + ")";
} }
bool InputEventScreenDrag::accumulate(const Ref<InputEvent> &p_event) {
Ref<InputEventScreenDrag> drag = p_event;
if (drag.is_null())
return false;
if (get_index() != drag->get_index()) {
return false;
}
set_position(drag->get_position());
set_speed(drag->get_speed());
relative += drag->get_relative();
return true;
}
void InputEventScreenDrag::_bind_methods() { void InputEventScreenDrag::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_index", "index"), &InputEventScreenDrag::set_index); ClassDB::bind_method(D_METHOD("set_index", "index"), &InputEventScreenDrag::set_index);
ClassDB::bind_method(D_METHOD("get_index"), &InputEventScreenDrag::get_index); ClassDB::bind_method(D_METHOD("get_index"), &InputEventScreenDrag::get_index);

View file

@ -502,6 +502,8 @@ public:
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const; virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
virtual String as_text() const; virtual String as_text() const;
virtual bool accumulate(const Ref<InputEvent> &p_event);
InputEventScreenDrag(); InputEventScreenDrag();
}; };

View file

@ -315,10 +315,6 @@ Vector3 InputDefault::get_gyroscope() const {
return gyroscope; return gyroscope;
} }
void InputDefault::parse_input_event(const Ref<InputEvent> &p_event) {
_parse_input_event_impl(p_event, false);
}
void InputDefault::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated) { void InputDefault::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated) {
// Notes on mouse-touch emulation: // Notes on mouse-touch emulation:
// - Emulated mouse events are parsed, that is, re-routed to this method, so they make the same effects // - Emulated mouse events are parsed, that is, re-routed to this method, so they make the same effects
@ -327,8 +323,6 @@ void InputDefault::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool
// - Emulated touch events are handed right to the main loop (i.e., the SceneTree) because they don't // - Emulated touch events are handed right to the main loop (i.e., the SceneTree) because they don't
// require additional handling by this class. // require additional handling by this class.
_THREAD_SAFE_METHOD_
Ref<InputEventKey> k = p_event; Ref<InputEventKey> k = p_event;
if (k.is_valid() && !k->is_echo() && k->get_scancode() != 0) { if (k.is_valid() && !k->is_echo() && k->get_scancode() != 0) {
if (k->is_pressed()) { if (k->is_pressed()) {
@ -697,11 +691,13 @@ void InputDefault::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_sh
OS::get_singleton()->set_custom_mouse_cursor(p_cursor, (OS::CursorShape)p_shape, p_hotspot); OS::get_singleton()->set_custom_mouse_cursor(p_cursor, (OS::CursorShape)p_shape, p_hotspot);
} }
void InputDefault::accumulate_input_event(const Ref<InputEvent> &p_event) { void InputDefault::parse_input_event(const Ref<InputEvent> &p_event) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND(p_event.is_null()); ERR_FAIL_COND(p_event.is_null());
if (!use_accumulated_input) { if (!use_accumulated_input) {
parse_input_event(p_event); _parse_input_event_impl(p_event, false);
return; return;
} }
if (!accumulated_events.empty() && accumulated_events.back()->get()->accumulate(p_event)) { if (!accumulated_events.empty() && accumulated_events.back()->get()->accumulate(p_event)) {
@ -711,8 +707,10 @@ void InputDefault::accumulate_input_event(const Ref<InputEvent> &p_event) {
accumulated_events.push_back(p_event); accumulated_events.push_back(p_event);
} }
void InputDefault::flush_accumulated_events() { void InputDefault::flush_accumulated_events() {
_THREAD_SAFE_METHOD_
while (accumulated_events.front()) { while (accumulated_events.front()) {
parse_input_event(accumulated_events.front()->get()); _parse_input_event_impl(accumulated_events.front()->get(), false);
accumulated_events.pop_front(); accumulated_events.pop_front();
} }
} }
@ -736,7 +734,7 @@ void InputDefault::release_pressed_events() {
} }
InputDefault::InputDefault() { InputDefault::InputDefault() {
use_accumulated_input = true; use_accumulated_input = false;
mouse_button_mask = 0; mouse_button_mask = 0;
emulate_touch_from_mouse = false; emulate_touch_from_mouse = false;
emulate_mouse_from_touch = false; emulate_mouse_from_touch = false;

View file

@ -302,7 +302,6 @@ public:
String get_joy_guid_remapped(int p_device) const; String get_joy_guid_remapped(int p_device) const;
void set_fallback_mapping(String p_guid); void set_fallback_mapping(String p_guid);
virtual void accumulate_input_event(const Ref<InputEvent> &p_event);
virtual void flush_accumulated_events(); virtual void flush_accumulated_events();
virtual void set_use_accumulated_input(bool p_enable); virtual void set_use_accumulated_input(bool p_enable);

View file

@ -3216,7 +3216,7 @@ void OS_OSX::process_key_events() {
void OS_OSX::push_input(const Ref<InputEvent> &p_event) { void OS_OSX::push_input(const Ref<InputEvent> &p_event) {
Ref<InputEvent> ev = p_event; Ref<InputEvent> ev = p_event;
input->accumulate_input_event(ev); input->parse_input_event(ev);
} }
void OS_OSX::force_process_input() { void OS_OSX::force_process_input() {

View file

@ -283,7 +283,7 @@ void OS_Windows::_touch_event(bool p_pressed, float p_x, float p_y, int idx) {
event->set_position(Vector2(p_x, p_y)); event->set_position(Vector2(p_x, p_y));
if (main_loop) { if (main_loop) {
input->accumulate_input_event(event); input->parse_input_event(event);
} }
}; };
@ -303,7 +303,7 @@ void OS_Windows::_drag_event(float p_x, float p_y, int idx) {
event->set_relative(Vector2(p_x, p_y) - curr->get()); event->set_relative(Vector2(p_x, p_y) - curr->get());
if (main_loop) if (main_loop)
input->accumulate_input_event(event); input->parse_input_event(event);
curr->get() = Vector2(p_x, p_y); curr->get() = Vector2(p_x, p_y);
}; };
@ -487,7 +487,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
} }
if (window_has_focus && main_loop && mm->get_relative() != Vector2()) if (window_has_focus && main_loop && mm->get_relative() != Vector2())
input->accumulate_input_event(mm); input->parse_input_event(mm);
} }
delete[] lpb; delete[] lpb;
} break; } break;
@ -575,7 +575,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
old_x = mm->get_position().x; old_x = mm->get_position().x;
old_y = mm->get_position().y; old_y = mm->get_position().y;
if (window_has_focus && main_loop) if (window_has_focus && main_loop)
input->accumulate_input_event(mm); input->parse_input_event(mm);
} }
return 0; return 0;
} }
@ -719,7 +719,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
old_x = mm->get_position().x; old_x = mm->get_position().x;
old_y = mm->get_position().y; old_y = mm->get_position().y;
if (window_has_focus && main_loop) if (window_has_focus && main_loop)
input->accumulate_input_event(mm); input->parse_input_event(mm);
return 0; return 0;
} break; } break;
case WM_MOUSEMOVE: { case WM_MOUSEMOVE: {
@ -821,7 +821,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
old_x = mm->get_position().x; old_x = mm->get_position().x;
old_y = mm->get_position().y; old_y = mm->get_position().y;
if (window_has_focus && main_loop) if (window_has_focus && main_loop)
input->accumulate_input_event(mm); input->parse_input_event(mm);
} break; } break;
case WM_LBUTTONDOWN: case WM_LBUTTONDOWN:
@ -984,14 +984,14 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
mb->set_global_position(mb->get_position()); mb->set_global_position(mb->get_position());
if (main_loop) { if (main_loop) {
input->accumulate_input_event(mb); input->parse_input_event(mb);
if (mb->is_pressed() && mb->get_button_index() > 3 && mb->get_button_index() < 8) { if (mb->is_pressed() && mb->get_button_index() > 3 && mb->get_button_index() < 8) {
//send release for mouse wheel //send release for mouse wheel
Ref<InputEventMouseButton> mbd = mb->duplicate(); Ref<InputEventMouseButton> mbd = mb->duplicate();
last_button_state &= ~(1 << (mbd->get_button_index() - 1)); last_button_state &= ~(1 << (mbd->get_button_index() - 1));
mbd->set_button_mask(last_button_state); mbd->set_button_mask(last_button_state);
mbd->set_pressed(false); mbd->set_pressed(false);
input->accumulate_input_event(mbd); input->parse_input_event(mbd);
} }
} }
} break; } break;
@ -1222,7 +1222,7 @@ void OS_Windows::process_key_events() {
if (k->get_unicode() < 32) if (k->get_unicode() < 32)
k->set_unicode(0); k->set_unicode(0);
input->accumulate_input_event(k); input->parse_input_event(k);
} }
//do nothing //do nothing
@ -1261,7 +1261,7 @@ void OS_Windows::process_key_events() {
k->set_echo((ke.uMsg == WM_KEYDOWN && (ke.lParam & (1 << 30)))); k->set_echo((ke.uMsg == WM_KEYDOWN && (ke.lParam & (1 << 30))));
input->accumulate_input_event(k); input->parse_input_event(k);
} break; } break;
} }

View file

@ -1928,7 +1928,7 @@ void OS_X11::_handle_key_event(XKeyEvent *p_event, LocalVector<XEvent> &p_events
k->set_shift(true); k->set_shift(true);
} }
input->accumulate_input_event(k); input->parse_input_event(k);
} }
memfree(utf8string); memfree(utf8string);
return; return;
@ -2075,7 +2075,7 @@ void OS_X11::_handle_key_event(XKeyEvent *p_event, LocalVector<XEvent> &p_events
} }
//printf("key: %x\n",k->get_scancode()); //printf("key: %x\n",k->get_scancode());
input->accumulate_input_event(k); input->parse_input_event(k);
} }
Atom OS_X11::_process_selection_request_target(Atom p_target, Window p_requestor, Atom p_property) const { Atom OS_X11::_process_selection_request_target(Atom p_target, Window p_requestor, Atom p_property) const {
@ -2491,13 +2491,13 @@ void OS_X11::process_xevents() {
// in a spurious mouse motion event being sent to Godot; remember it to be able to filter it out // in a spurious mouse motion event being sent to Godot; remember it to be able to filter it out
xi.mouse_pos_to_filter = pos; xi.mouse_pos_to_filter = pos;
} }
input->accumulate_input_event(st); input->parse_input_event(st);
} else { } else {
if (!xi.state.has(index)) { // Defensive if (!xi.state.has(index)) { // Defensive
break; break;
} }
xi.state.erase(index); xi.state.erase(index);
input->accumulate_input_event(st); input->parse_input_event(st);
} }
} break; } break;
@ -2513,7 +2513,7 @@ void OS_X11::process_xevents() {
sd->set_index(index); sd->set_index(index);
sd->set_position(pos); sd->set_position(pos);
sd->set_relative(pos - curr_pos_elem->value()); sd->set_relative(pos - curr_pos_elem->value());
input->accumulate_input_event(sd); input->parse_input_event(sd);
curr_pos_elem->value() = pos; curr_pos_elem->value() = pos;
} }
@ -2607,7 +2607,7 @@ void OS_X11::process_xevents() {
st.instance(); st.instance();
st->set_index(E->key()); st->set_index(E->key());
st->set_position(E->get()); st->set_position(E->get());
input->accumulate_input_event(st); input->parse_input_event(st);
} }
xi.state.clear(); xi.state.clear();
#endif #endif
@ -2668,7 +2668,7 @@ void OS_X11::process_xevents() {
} }
} }
input->accumulate_input_event(mb); input->parse_input_event(mb);
} break; } break;
case MotionNotify: { case MotionNotify: {
@ -2783,7 +2783,7 @@ void OS_X11::process_xevents() {
// this is so that the relative motion doesn't get messed up // this is so that the relative motion doesn't get messed up
// after we regain focus. // after we regain focus.
if (window_has_focus || !mouse_mode_grab) { if (window_has_focus || !mouse_mode_grab) {
input->accumulate_input_event(mm); input->parse_input_event(mm);
} }
} break; } break;