Fix menu keyboard and controller navigation.

This commit is contained in:
Pāvels Nadtočajevs 2025-07-21 10:03:07 +03:00
parent 71a9948157
commit 2111ff0e2a
No known key found for this signature in database
GPG key ID: 8413210218EF35D2
4 changed files with 66 additions and 47 deletions

View file

@ -478,11 +478,15 @@ void PopupMenu::_input_from_window_internal(const Ref<InputEvent> &p_event) {
Ref<InputEventJoypadButton> 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<InputEvent> &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);
}