diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 79ff3b07c24..864896b6442 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -478,11 +478,15 @@ void PopupMenu::_input_from_window_internal(const Ref &p_event) { Ref joypadbutton_event = p_event; bool is_joypad_event = (joypadmotion_event.is_valid() || joypadbutton_event.is_valid()); + if (is_joypad_event && !has_focus_or_active_popup()) { + return; + } if (p_event->is_action("ui_down", true) && p_event->is_pressed()) { if (is_joypad_event) { if (!input->is_action_just_pressed("ui_down", true)) { return; } + joypad_event_process = true; set_process_internal(true); } int search_from = mouse_over + 1; @@ -525,6 +529,7 @@ void PopupMenu::_input_from_window_internal(const Ref &p_event) { if (!input->is_action_just_pressed("ui_up", true)) { return; } + joypad_event_process = true; set_process_internal(true); } int search_from = mouse_over - 1; @@ -1291,76 +1296,79 @@ void PopupMenu::_notification(int p_what) { case NOTIFICATION_INTERNAL_PROCESS: { Input *input = Input::get_singleton(); - if (input->is_action_just_released("ui_up") || input->is_action_just_released("ui_down")) { - gamepad_event_delay_ms = DEFAULT_GAMEPAD_EVENT_DELAY_MS; - set_process_internal(false); - return; - } - gamepad_event_delay_ms -= get_process_delta_time(); - if (gamepad_event_delay_ms <= 0) { - if (input->is_action_pressed("ui_down")) { - gamepad_event_delay_ms = GAMEPAD_EVENT_REPEAT_RATE_MS + gamepad_event_delay_ms; - int search_from = mouse_over + 1; - if (search_from >= items.size()) { - search_from = 0; - } + if (joypad_event_process && has_focus_or_active_popup()) { + if (input->is_action_just_released("ui_up") || input->is_action_just_released("ui_down")) { + gamepad_event_delay_ms = DEFAULT_GAMEPAD_EVENT_DELAY_MS; + set_process_internal(false); + return; + } - bool match_found = false; - for (int i = search_from; i < items.size(); i++) { - if (!items[i].separator && !items[i].disabled) { - mouse_over = i; - emit_signal(SNAME("id_focused"), items[i].id); - scroll_to_item(i); - control->queue_redraw(); - match_found = true; - break; + gamepad_event_delay_ms -= get_process_delta_time(); + if (gamepad_event_delay_ms <= 0) { + if (input->is_action_pressed("ui_down")) { + gamepad_event_delay_ms = GAMEPAD_EVENT_REPEAT_RATE_MS + gamepad_event_delay_ms; + int search_from = mouse_over + 1; + if (search_from >= items.size()) { + search_from = 0; } - } - if (!match_found) { - // If the last item is not selectable, try re-searching from the start. - for (int i = 0; i < search_from; i++) { + bool match_found = false; + for (int i = search_from; i < items.size(); i++) { if (!items[i].separator && !items[i].disabled) { mouse_over = i; emit_signal(SNAME("id_focused"), items[i].id); scroll_to_item(i); control->queue_redraw(); + match_found = true; break; } } - } - } - if (input->is_action_pressed("ui_up")) { - gamepad_event_delay_ms = GAMEPAD_EVENT_REPEAT_RATE_MS + gamepad_event_delay_ms; - int search_from = mouse_over - 1; - if (search_from < 0) { - search_from = items.size() - 1; - } - - bool match_found = false; - for (int i = search_from; i >= 0; i--) { - if (!items[i].separator && !items[i].disabled) { - mouse_over = i; - emit_signal(SNAME("id_focused"), items[i].id); - scroll_to_item(i); - control->queue_redraw(); - match_found = true; - break; + if (!match_found) { + // If the last item is not selectable, try re-searching from the start. + for (int i = 0; i < search_from; i++) { + if (!items[i].separator && !items[i].disabled) { + mouse_over = i; + emit_signal(SNAME("id_focused"), items[i].id); + scroll_to_item(i); + control->queue_redraw(); + break; + } + } } } - if (!match_found) { - // If the first item is not selectable, try re-searching from the end. - for (int i = items.size() - 1; i >= search_from; i--) { + if (input->is_action_pressed("ui_up")) { + gamepad_event_delay_ms = GAMEPAD_EVENT_REPEAT_RATE_MS + gamepad_event_delay_ms; + int search_from = mouse_over - 1; + if (search_from < 0) { + search_from = items.size() - 1; + } + + bool match_found = false; + for (int i = search_from; i >= 0; i--) { if (!items[i].separator && !items[i].disabled) { mouse_over = i; emit_signal(SNAME("id_focused"), items[i].id); scroll_to_item(i); control->queue_redraw(); + match_found = true; break; } } + + if (!match_found) { + // If the first item is not selectable, try re-searching from the end. + for (int i = items.size() - 1; i >= search_from; i--) { + if (!items[i].separator && !items[i].disabled) { + mouse_over = i; + emit_signal(SNAME("id_focused"), items[i].id); + scroll_to_item(i); + control->queue_redraw(); + break; + } + } + } } } } @@ -1408,6 +1416,7 @@ void PopupMenu::_notification(int p_what) { } } else { if (!is_embedded()) { + joypad_event_process = false; set_process_internal(true); } diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index f4f534b097e..bd7c2214082 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -168,6 +168,7 @@ class PopupMenu : public Popup { const float DEFAULT_GAMEPAD_EVENT_DELAY_MS = 0.5; const float GAMEPAD_EVENT_REPEAT_RATE_MS = 1.0 / 20; float gamepad_event_delay_ms = DEFAULT_GAMEPAD_EVENT_DELAY_MS; + bool joypad_event_process = false; struct ThemeCache { Ref panel_style; diff --git a/scene/main/window.cpp b/scene/main/window.cpp index ec04feca747..4b0e4dbc0a5 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -2111,6 +2111,14 @@ bool Window::has_focus() const { return focused; } +bool Window::has_focus_or_active_popup() const { + ERR_READ_THREAD_GUARD_V(false); + if (window_id != DisplayServer::INVALID_WINDOW_ID) { + return DisplayServer::get_singleton()->window_is_focused(window_id) || (DisplayServer::get_singleton()->window_get_active_popup() == window_id); + } + return focused; +} + void Window::start_drag() { ERR_MAIN_THREAD_GUARD; if (window_id != DisplayServer::INVALID_WINDOW_ID) { diff --git a/scene/main/window.h b/scene/main/window.h index bebd77eeceb..444019cb440 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -419,6 +419,7 @@ public: void grab_focus(); bool has_focus() const; + bool has_focus_or_active_popup() const; void start_drag(); void start_resize(DisplayServer::WindowResizeEdge p_edge);