You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-12-05 17:15:09 +00:00
Fix menu keyboard and controller navigation.
This commit is contained in:
@@ -478,11 +478,15 @@ void PopupMenu::_input_from_window_internal(const Ref<InputEvent> &p_event) {
|
|||||||
Ref<InputEventJoypadButton> joypadbutton_event = p_event;
|
Ref<InputEventJoypadButton> joypadbutton_event = p_event;
|
||||||
bool is_joypad_event = (joypadmotion_event.is_valid() || joypadbutton_event.is_valid());
|
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 (p_event->is_action("ui_down", true) && p_event->is_pressed()) {
|
||||||
if (is_joypad_event) {
|
if (is_joypad_event) {
|
||||||
if (!input->is_action_just_pressed("ui_down", true)) {
|
if (!input->is_action_just_pressed("ui_down", true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
joypad_event_process = true;
|
||||||
set_process_internal(true);
|
set_process_internal(true);
|
||||||
}
|
}
|
||||||
int search_from = mouse_over + 1;
|
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)) {
|
if (!input->is_action_just_pressed("ui_up", true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
joypad_event_process = true;
|
||||||
set_process_internal(true);
|
set_process_internal(true);
|
||||||
}
|
}
|
||||||
int search_from = mouse_over - 1;
|
int search_from = mouse_over - 1;
|
||||||
@@ -1291,76 +1296,79 @@ void PopupMenu::_notification(int p_what) {
|
|||||||
case NOTIFICATION_INTERNAL_PROCESS: {
|
case NOTIFICATION_INTERNAL_PROCESS: {
|
||||||
Input *input = Input::get_singleton();
|
Input *input = Input::get_singleton();
|
||||||
|
|
||||||
if (input->is_action_just_released("ui_up") || input->is_action_just_released("ui_down")) {
|
if (joypad_event_process && has_focus_or_active_popup()) {
|
||||||
gamepad_event_delay_ms = DEFAULT_GAMEPAD_EVENT_DELAY_MS;
|
if (input->is_action_just_released("ui_up") || input->is_action_just_released("ui_down")) {
|
||||||
set_process_internal(false);
|
gamepad_event_delay_ms = DEFAULT_GAMEPAD_EVENT_DELAY_MS;
|
||||||
return;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool match_found = false;
|
gamepad_event_delay_ms -= get_process_delta_time();
|
||||||
for (int i = search_from; i < items.size(); i++) {
|
if (gamepad_event_delay_ms <= 0) {
|
||||||
if (!items[i].separator && !items[i].disabled) {
|
if (input->is_action_pressed("ui_down")) {
|
||||||
mouse_over = i;
|
gamepad_event_delay_ms = GAMEPAD_EVENT_REPEAT_RATE_MS + gamepad_event_delay_ms;
|
||||||
emit_signal(SNAME("id_focused"), items[i].id);
|
int search_from = mouse_over + 1;
|
||||||
scroll_to_item(i);
|
if (search_from >= items.size()) {
|
||||||
control->queue_redraw();
|
search_from = 0;
|
||||||
match_found = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!match_found) {
|
bool match_found = false;
|
||||||
// If the last item is not selectable, try re-searching from the start.
|
for (int i = search_from; i < items.size(); i++) {
|
||||||
for (int i = 0; i < search_from; i++) {
|
|
||||||
if (!items[i].separator && !items[i].disabled) {
|
if (!items[i].separator && !items[i].disabled) {
|
||||||
mouse_over = i;
|
mouse_over = i;
|
||||||
emit_signal(SNAME("id_focused"), items[i].id);
|
emit_signal(SNAME("id_focused"), items[i].id);
|
||||||
scroll_to_item(i);
|
scroll_to_item(i);
|
||||||
control->queue_redraw();
|
control->queue_redraw();
|
||||||
|
match_found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input->is_action_pressed("ui_up")) {
|
if (!match_found) {
|
||||||
gamepad_event_delay_ms = GAMEPAD_EVENT_REPEAT_RATE_MS + gamepad_event_delay_ms;
|
// If the last item is not selectable, try re-searching from the start.
|
||||||
int search_from = mouse_over - 1;
|
for (int i = 0; i < search_from; i++) {
|
||||||
if (search_from < 0) {
|
if (!items[i].separator && !items[i].disabled) {
|
||||||
search_from = items.size() - 1;
|
mouse_over = i;
|
||||||
}
|
emit_signal(SNAME("id_focused"), items[i].id);
|
||||||
|
scroll_to_item(i);
|
||||||
bool match_found = false;
|
control->queue_redraw();
|
||||||
for (int i = search_from; i >= 0; i--) {
|
break;
|
||||||
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 (input->is_action_pressed("ui_up")) {
|
||||||
// If the first item is not selectable, try re-searching from the end.
|
gamepad_event_delay_ms = GAMEPAD_EVENT_REPEAT_RATE_MS + gamepad_event_delay_ms;
|
||||||
for (int i = items.size() - 1; i >= search_from; i--) {
|
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) {
|
if (!items[i].separator && !items[i].disabled) {
|
||||||
mouse_over = i;
|
mouse_over = i;
|
||||||
emit_signal(SNAME("id_focused"), items[i].id);
|
emit_signal(SNAME("id_focused"), items[i].id);
|
||||||
scroll_to_item(i);
|
scroll_to_item(i);
|
||||||
control->queue_redraw();
|
control->queue_redraw();
|
||||||
|
match_found = true;
|
||||||
break;
|
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 {
|
} else {
|
||||||
if (!is_embedded()) {
|
if (!is_embedded()) {
|
||||||
|
joypad_event_process = false;
|
||||||
set_process_internal(true);
|
set_process_internal(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -168,6 +168,7 @@ class PopupMenu : public Popup {
|
|||||||
const float DEFAULT_GAMEPAD_EVENT_DELAY_MS = 0.5;
|
const float DEFAULT_GAMEPAD_EVENT_DELAY_MS = 0.5;
|
||||||
const float GAMEPAD_EVENT_REPEAT_RATE_MS = 1.0 / 20;
|
const float GAMEPAD_EVENT_REPEAT_RATE_MS = 1.0 / 20;
|
||||||
float gamepad_event_delay_ms = DEFAULT_GAMEPAD_EVENT_DELAY_MS;
|
float gamepad_event_delay_ms = DEFAULT_GAMEPAD_EVENT_DELAY_MS;
|
||||||
|
bool joypad_event_process = false;
|
||||||
|
|
||||||
struct ThemeCache {
|
struct ThemeCache {
|
||||||
Ref<StyleBox> panel_style;
|
Ref<StyleBox> panel_style;
|
||||||
|
|||||||
@@ -2111,6 +2111,14 @@ bool Window::has_focus() const {
|
|||||||
return focused;
|
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() {
|
void Window::start_drag() {
|
||||||
ERR_MAIN_THREAD_GUARD;
|
ERR_MAIN_THREAD_GUARD;
|
||||||
if (window_id != DisplayServer::INVALID_WINDOW_ID) {
|
if (window_id != DisplayServer::INVALID_WINDOW_ID) {
|
||||||
|
|||||||
@@ -419,6 +419,7 @@ public:
|
|||||||
|
|
||||||
void grab_focus();
|
void grab_focus();
|
||||||
bool has_focus() const;
|
bool has_focus() const;
|
||||||
|
bool has_focus_or_active_popup() const;
|
||||||
|
|
||||||
void start_drag();
|
void start_drag();
|
||||||
void start_resize(DisplayServer::WindowResizeEdge p_edge);
|
void start_resize(DisplayServer::WindowResizeEdge p_edge);
|
||||||
|
|||||||
Reference in New Issue
Block a user