Skip to content

Commit ad4e7a0

Browse files
committed
Merge pull request #108820 from bruvzg/menu_arr_nav
Fix menu keyboard and controller navigation.
2 parents ebb322a + 2111ff0 commit ad4e7a0

File tree

4 files changed

+65
-46
lines changed

4 files changed

+65
-46
lines changed

scene/gui/popup_menu.cpp

Lines changed: 55 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -478,11 +478,15 @@ void PopupMenu::_input_from_window_internal(const Ref<InputEvent> &p_event) {
478478
Ref<InputEventJoypadButton> joypadbutton_event = p_event;
479479
bool is_joypad_event = (joypadmotion_event.is_valid() || joypadbutton_event.is_valid());
480480

481+
if (is_joypad_event && !has_focus_or_active_popup()) {
482+
return;
483+
}
481484
if (p_event->is_action("ui_down", true) && p_event->is_pressed()) {
482485
if (is_joypad_event) {
483486
if (!input->is_action_just_pressed("ui_down", true)) {
484487
return;
485488
}
489+
joypad_event_process = true;
486490
set_process_internal(true);
487491
}
488492
int search_from = mouse_over + 1;
@@ -525,6 +529,7 @@ void PopupMenu::_input_from_window_internal(const Ref<InputEvent> &p_event) {
525529
if (!input->is_action_just_pressed("ui_up", true)) {
526530
return;
527531
}
532+
joypad_event_process = true;
528533
set_process_internal(true);
529534
}
530535
int search_from = mouse_over - 1;
@@ -1291,76 +1296,79 @@ void PopupMenu::_notification(int p_what) {
12911296
case NOTIFICATION_INTERNAL_PROCESS: {
12921297
Input *input = Input::get_singleton();
12931298

1294-
if (input->is_action_just_released("ui_up") || input->is_action_just_released("ui_down")) {
1295-
gamepad_event_delay_ms = DEFAULT_GAMEPAD_EVENT_DELAY_MS;
1296-
set_process_internal(false);
1297-
return;
1298-
}
1299-
gamepad_event_delay_ms -= get_process_delta_time();
1300-
if (gamepad_event_delay_ms <= 0) {
1301-
if (input->is_action_pressed("ui_down")) {
1302-
gamepad_event_delay_ms = GAMEPAD_EVENT_REPEAT_RATE_MS + gamepad_event_delay_ms;
1303-
int search_from = mouse_over + 1;
1304-
if (search_from >= items.size()) {
1305-
search_from = 0;
1306-
}
1299+
if (joypad_event_process && has_focus_or_active_popup()) {
1300+
if (input->is_action_just_released("ui_up") || input->is_action_just_released("ui_down")) {
1301+
gamepad_event_delay_ms = DEFAULT_GAMEPAD_EVENT_DELAY_MS;
1302+
set_process_internal(false);
1303+
return;
1304+
}
13071305

1308-
bool match_found = false;
1309-
for (int i = search_from; i < items.size(); i++) {
1310-
if (!items[i].separator && !items[i].disabled) {
1311-
mouse_over = i;
1312-
emit_signal(SNAME("id_focused"), items[i].id);
1313-
scroll_to_item(i);
1314-
control->queue_redraw();
1315-
match_found = true;
1316-
break;
1306+
gamepad_event_delay_ms -= get_process_delta_time();
1307+
if (gamepad_event_delay_ms <= 0) {
1308+
if (input->is_action_pressed("ui_down")) {
1309+
gamepad_event_delay_ms = GAMEPAD_EVENT_REPEAT_RATE_MS + gamepad_event_delay_ms;
1310+
int search_from = mouse_over + 1;
1311+
if (search_from >= items.size()) {
1312+
search_from = 0;
13171313
}
1318-
}
13191314

1320-
if (!match_found) {
1321-
// If the last item is not selectable, try re-searching from the start.
1322-
for (int i = 0; i < search_from; i++) {
1315+
bool match_found = false;
1316+
for (int i = search_from; i < items.size(); i++) {
13231317
if (!items[i].separator && !items[i].disabled) {
13241318
mouse_over = i;
13251319
emit_signal(SNAME("id_focused"), items[i].id);
13261320
scroll_to_item(i);
13271321
control->queue_redraw();
1322+
match_found = true;
13281323
break;
13291324
}
13301325
}
1331-
}
1332-
}
13331326

1334-
if (input->is_action_pressed("ui_up")) {
1335-
gamepad_event_delay_ms = GAMEPAD_EVENT_REPEAT_RATE_MS + gamepad_event_delay_ms;
1336-
int search_from = mouse_over - 1;
1337-
if (search_from < 0) {
1338-
search_from = items.size() - 1;
1327+
if (!match_found) {
1328+
// If the last item is not selectable, try re-searching from the start.
1329+
for (int i = 0; i < search_from; i++) {
1330+
if (!items[i].separator && !items[i].disabled) {
1331+
mouse_over = i;
1332+
emit_signal(SNAME("id_focused"), items[i].id);
1333+
scroll_to_item(i);
1334+
control->queue_redraw();
1335+
break;
1336+
}
1337+
}
1338+
}
13391339
}
13401340

1341-
bool match_found = false;
1342-
for (int i = search_from; i >= 0; i--) {
1343-
if (!items[i].separator && !items[i].disabled) {
1344-
mouse_over = i;
1345-
emit_signal(SNAME("id_focused"), items[i].id);
1346-
scroll_to_item(i);
1347-
control->queue_redraw();
1348-
match_found = true;
1349-
break;
1341+
if (input->is_action_pressed("ui_up")) {
1342+
gamepad_event_delay_ms = GAMEPAD_EVENT_REPEAT_RATE_MS + gamepad_event_delay_ms;
1343+
int search_from = mouse_over - 1;
1344+
if (search_from < 0) {
1345+
search_from = items.size() - 1;
13501346
}
1351-
}
13521347

1353-
if (!match_found) {
1354-
// If the first item is not selectable, try re-searching from the end.
1355-
for (int i = items.size() - 1; i >= search_from; i--) {
1348+
bool match_found = false;
1349+
for (int i = search_from; i >= 0; i--) {
13561350
if (!items[i].separator && !items[i].disabled) {
13571351
mouse_over = i;
13581352
emit_signal(SNAME("id_focused"), items[i].id);
13591353
scroll_to_item(i);
13601354
control->queue_redraw();
1355+
match_found = true;
13611356
break;
13621357
}
13631358
}
1359+
1360+
if (!match_found) {
1361+
// If the first item is not selectable, try re-searching from the end.
1362+
for (int i = items.size() - 1; i >= search_from; i--) {
1363+
if (!items[i].separator && !items[i].disabled) {
1364+
mouse_over = i;
1365+
emit_signal(SNAME("id_focused"), items[i].id);
1366+
scroll_to_item(i);
1367+
control->queue_redraw();
1368+
break;
1369+
}
1370+
}
1371+
}
13641372
}
13651373
}
13661374
}
@@ -1408,6 +1416,7 @@ void PopupMenu::_notification(int p_what) {
14081416
}
14091417
} else {
14101418
if (!is_embedded()) {
1419+
joypad_event_process = false;
14111420
set_process_internal(true);
14121421
}
14131422

scene/gui/popup_menu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ class PopupMenu : public Popup {
168168
const float DEFAULT_GAMEPAD_EVENT_DELAY_MS = 0.5;
169169
const float GAMEPAD_EVENT_REPEAT_RATE_MS = 1.0 / 20;
170170
float gamepad_event_delay_ms = DEFAULT_GAMEPAD_EVENT_DELAY_MS;
171+
bool joypad_event_process = false;
171172

172173
struct ThemeCache {
173174
Ref<StyleBox> panel_style;

scene/main/window.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2111,6 +2111,14 @@ bool Window::has_focus() const {
21112111
return focused;
21122112
}
21132113

2114+
bool Window::has_focus_or_active_popup() const {
2115+
ERR_READ_THREAD_GUARD_V(false);
2116+
if (window_id != DisplayServer::INVALID_WINDOW_ID) {
2117+
return DisplayServer::get_singleton()->window_is_focused(window_id) || (DisplayServer::get_singleton()->window_get_active_popup() == window_id);
2118+
}
2119+
return focused;
2120+
}
2121+
21142122
void Window::start_drag() {
21152123
ERR_MAIN_THREAD_GUARD;
21162124
if (window_id != DisplayServer::INVALID_WINDOW_ID) {

scene/main/window.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,7 @@ class Window : public Viewport {
419419

420420
void grab_focus();
421421
bool has_focus() const;
422+
bool has_focus_or_active_popup() const;
422423

423424
void start_drag();
424425
void start_resize(DisplayServer::WindowResizeEdge p_edge);

0 commit comments

Comments
 (0)