ui: keyboard input was ignored when resuming game if no render

When resuming a game, keyboard is ignored until the next frame is
rendered. This is due to ImGUI not updating its WantCaptureKeyboard flag
until the next frame, which is an issue if the game isn't actively
rendering frames (Zombie Revenge pause screen, Giant Killers)
This commit is contained in:
Flyinghead 2023-09-02 20:00:07 +02:00
parent d29645cc49
commit 8eae6b97fc
6 changed files with 44 additions and 30 deletions

View File

@ -483,7 +483,7 @@ void gui_open_settings()
HideOSD(); HideOSD();
try { try {
emu.stop(); emu.stop();
gui_state = GuiState::Commands; gui_setState(GuiState::Commands);
} catch (const FlycastException& e) { } catch (const FlycastException& e) {
gui_stop_game(e.what()); gui_stop_game(e.what());
} }
@ -495,7 +495,7 @@ void gui_open_settings()
} }
else if (gui_state == GuiState::VJoyEdit) else if (gui_state == GuiState::VJoyEdit)
{ {
gui_state = GuiState::VJoyEditCommands; gui_setState(GuiState::VJoyEditCommands);
} }
else if (gui_state == GuiState::Loading) else if (gui_state == GuiState::Loading)
{ {
@ -503,7 +503,7 @@ void gui_open_settings()
} }
else if (gui_state == GuiState::Commands) else if (gui_state == GuiState::Commands)
{ {
gui_state = GuiState::Closed; gui_setState(GuiState::Closed);
GamepadDevice::load_system_mappings(); GamepadDevice::load_system_mappings();
emu.start(); emu.start();
} }
@ -517,7 +517,7 @@ void gui_start_game(const std::string& path)
chat.reset(); chat.reset();
scanner.stop(); scanner.stop();
gui_state = GuiState::Loading; gui_setState(GuiState::Loading);
gameLoader.load(path); gameLoader.load(path);
} }
@ -528,7 +528,7 @@ void gui_stop_game(const std::string& message)
{ {
// Exit to main menu // Exit to main menu
emu.unloadGame(); emu.unloadGame();
gui_state = GuiState::Main; gui_setState(GuiState::Main);
reset_vmus(); reset_vmus();
if (!message.empty()) if (!message.empty())
gui_error("Flycast has stopped.\n\n" + message); gui_error("Flycast has stopped.\n\n" + message);
@ -570,7 +570,7 @@ static void gui_display_commands()
// Load State // Load State
if (ImGui::Button("Load State", ScaledVec2(110, 50)) && savestateAllowed()) if (ImGui::Button("Load State", ScaledVec2(110, 50)) && savestateAllowed())
{ {
gui_state = GuiState::Closed; gui_setState(GuiState::Closed);
dc_loadstate(config::SavestateSlot); dc_loadstate(config::SavestateSlot);
} }
ImGui::SameLine(); ImGui::SameLine();
@ -594,7 +594,7 @@ static void gui_display_commands()
// Save State // Save State
if (ImGui::Button("Save State", ScaledVec2(110, 50)) && savestateAllowed()) if (ImGui::Button("Save State", ScaledVec2(110, 50)) && savestateAllowed())
{ {
gui_state = GuiState::Closed; gui_setState(GuiState::Closed);
dc_savestate(config::SavestateSlot); dc_savestate(config::SavestateSlot);
} }
} }
@ -604,13 +604,13 @@ static void gui_display_commands()
// Settings // Settings
if (ImGui::Button("Settings", ScaledVec2(150, 50))) if (ImGui::Button("Settings", ScaledVec2(150, 50)))
{ {
gui_state = GuiState::Settings; gui_setState(GuiState::Settings);
} }
ImGui::NextColumn(); ImGui::NextColumn();
if (ImGui::Button("Resume", ScaledVec2(150, 50))) if (ImGui::Button("Resume", ScaledVec2(150, 50)))
{ {
GamepadDevice::load_system_mappings(); GamepadDevice::load_system_mappings();
gui_state = GuiState::Closed; gui_setState(GuiState::Closed);
} }
ImGui::NextColumn(); ImGui::NextColumn();
@ -621,12 +621,12 @@ static void gui_display_commands()
{ {
if (libGDR_GetDiscType() == Open) if (libGDR_GetDiscType() == Open)
{ {
gui_state = GuiState::SelectDisk; gui_setState(GuiState::SelectDisk);
} }
else else
{ {
DiscOpenLid(); DiscOpenLid();
gui_state = GuiState::Closed; gui_setState(GuiState::Closed);
} }
} }
ImGui::NextColumn(); ImGui::NextColumn();
@ -636,7 +636,7 @@ static void gui_display_commands()
DisabledScope scope(settings.network.online); DisabledScope scope(settings.network.online);
if (ImGui::Button("Cheats", ScaledVec2(150, 50)) && !settings.network.online) if (ImGui::Button("Cheats", ScaledVec2(150, 50)) && !settings.network.online)
gui_state = GuiState::Cheats; gui_setState(GuiState::Cheats);
} }
ImGui::Columns(1, nullptr, false); ImGui::Columns(1, nullptr, false);
@ -1424,9 +1424,9 @@ static void gui_display_settings()
if (ImGui::Button("Done", ScaledVec2(100, 30))) if (ImGui::Button("Done", ScaledVec2(100, 30)))
{ {
if (game_started) if (game_started)
gui_state = GuiState::Commands; gui_setState(GuiState::Commands);
else else
gui_state = GuiState::Main; gui_setState(GuiState::Main);
if (maple_devices_changed) if (maple_devices_changed)
{ {
maple_devices_changed = false; maple_devices_changed = false;
@ -1577,7 +1577,7 @@ static void gui_display_settings()
#ifdef __ANDROID__ #ifdef __ANDROID__
ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize("Change").x - ImGui::GetStyle().FramePadding.x); ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize("Change").x - ImGui::GetStyle().FramePadding.x);
if (ImGui::Button("Change")) if (ImGui::Button("Change"))
gui_state = GuiState::Onboarding; gui_setState(GuiState::Onboarding);
#endif #endif
#ifdef TARGET_MAC #ifdef TARGET_MAC
ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize("Reveal in Finder").x - ImGui::GetStyle().FramePadding.x); ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize("Reveal in Finder").x - ImGui::GetStyle().FramePadding.x);
@ -1670,7 +1670,7 @@ static void gui_display_settings()
if (ImGui::Button("Edit")) if (ImGui::Button("Edit"))
{ {
vjoy_start_editing(); vjoy_start_editing();
gui_state = GuiState::VJoyEdit; gui_setState(GuiState::VJoyEdit);
} }
ImGui::SameLine(); ImGui::SameLine();
OptionSlider("Haptic", config::VirtualGamepadVibration, 0, 60); OptionSlider("Haptic", config::VirtualGamepadVibration, 0, 60);
@ -2653,7 +2653,7 @@ static void gui_display_content()
ImGui::SameLine(ImGui::GetContentRegionMax().x - ImGui::CalcTextSize("Settings").x - ImGui::GetStyle().FramePadding.x * 2.0f); ImGui::SameLine(ImGui::GetContentRegionMax().x - ImGui::CalcTextSize("Settings").x - ImGui::GetStyle().FramePadding.x * 2.0f);
#endif #endif
if (ImGui::Button("Settings")) if (ImGui::Button("Settings"))
gui_state = GuiState::Settings; gui_setState(GuiState::Settings);
} }
ImGui::PopStyleVar(); ImGui::PopStyleVar();
@ -2749,7 +2749,7 @@ static void gui_display_content()
settings.content.path = game.path; settings.content.path = game.path;
try { try {
DiscSwap(game.path); DiscSwap(game.path);
gui_state = GuiState::Closed; gui_setState(GuiState::Closed);
} catch (const FlycastException& e) { } catch (const FlycastException& e) {
gui_error(e.what()); gui_error(e.what());
} }
@ -2785,7 +2785,7 @@ static bool systemdir_selected_callback(bool cancelled, std::string selection)
{ {
if (cancelled) if (cancelled)
{ {
gui_state = GuiState::Main; gui_setState(GuiState::Main);
return true; return true;
} }
selection += "/"; selection += "/";
@ -2823,7 +2823,7 @@ static bool systemdir_selected_callback(bool cancelled, std::string selection)
config::Settings::instance().load(false); config::Settings::instance().load(false);
// Make sure the renderer type doesn't change mid-flight // Make sure the renderer type doesn't change mid-flight
config::RendererType = RenderType::OpenGL; config::RendererType = RenderType::OpenGL;
gui_state = GuiState::Main; gui_setState(GuiState::Main);
if (config::ContentPath.get().empty()) if (config::ContentPath.get().empty())
{ {
scanner.stop(); scanner.stop();
@ -2858,7 +2858,7 @@ static void gui_network_start()
ImGui::Text("Starting..."); ImGui::Text("Starting...");
try { try {
if (networkStatus.get()) if (networkStatus.get())
gui_state = GuiState::Closed; gui_setState(GuiState::Closed);
else else
gui_stop_game(); gui_stop_game();
} catch (const FlycastException& e) { } catch (const FlycastException& e) {
@ -2919,11 +2919,11 @@ static void gui_display_loadscreen()
if (NetworkHandshake::instance != nullptr) if (NetworkHandshake::instance != nullptr)
{ {
networkStatus = NetworkHandshake::instance->start(); networkStatus = NetworkHandshake::instance->start();
gui_state = GuiState::NetworkStart; gui_setState(GuiState::NetworkStart);
} }
else else
{ {
gui_state = GuiState::Closed; gui_setState(GuiState::Closed);
ImGui::Text("%s", label); ImGui::Text("%s", label);
} }
} }
@ -3126,7 +3126,7 @@ void gui_display_profiler()
void gui_open_onboarding() void gui_open_onboarding()
{ {
gui_state = GuiState::Onboarding; gui_setState(GuiState::Onboarding);
} }
void gui_cancel_load() void gui_cancel_load()
@ -3215,6 +3215,18 @@ void gui_saveState()
} }
} }
void gui_setState(GuiState newState)
{
gui_state = newState;
if (newState == GuiState::Closed)
{
// If the game isn't rendering any frame, these flags won't be updated and keyboard/mouse input will be ignored.
// So we force them false here. They will be set in the next ImGUI::NewFrame() anyway
ImGuiIO& io = ImGui::GetIO();
io.WantCaptureKeyboard = false;
io.WantCaptureMouse = false;
}
}
#ifdef TARGET_UWP #ifdef TARGET_UWP
// Ugly but a good workaround for MS stupidity // Ugly but a good workaround for MS stupidity

View File

@ -66,6 +66,8 @@ enum class GuiState {
}; };
extern GuiState gui_state; extern GuiState gui_state;
void gui_setState(GuiState newState);
static inline bool gui_is_open() static inline bool gui_is_open()
{ {
return gui_state != GuiState::Closed && gui_state != GuiState::VJoyEdit; return gui_state != GuiState::Closed && gui_state != GuiState::VJoyEdit;

View File

@ -39,20 +39,20 @@ void gui_display_vjoy_commands()
if (ImGui::Button("Save", ScaledVec2(150, 50))) if (ImGui::Button("Save", ScaledVec2(150, 50)))
{ {
vjoy_stop_editing(false); vjoy_stop_editing(false);
gui_state = GuiState::Settings; gui_setState(GuiState::Settings);
} }
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Button("Reset", ScaledVec2(150, 50))) if (ImGui::Button("Reset", ScaledVec2(150, 50)))
{ {
vjoy_reset_editing(); vjoy_reset_editing();
gui_state = GuiState::VJoyEdit; gui_setState(GuiState::VJoyEdit);
} }
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Button("Cancel", ScaledVec2(150, 50))) if (ImGui::Button("Cancel", ScaledVec2(150, 50)))
{ {
vjoy_stop_editing(true); vjoy_stop_editing(true);
gui_state = GuiState::Settings; gui_setState(GuiState::Settings);
} }
ImGui::End(); ImGui::End();
} }

View File

@ -112,7 +112,7 @@ void gui_cheats()
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Button("Close")) if (ImGui::Button("Close"))
gui_state = GuiState::Commands; gui_setState(GuiState::Commands);
ImGui::Unindent(10 * settings.display.uiScale); ImGui::Unindent(10 * settings.display.uiScale);
ImGui::PopStyleVar(); ImGui::PopStyleVar();

View File

@ -92,7 +92,7 @@ public:
} catch (const FlycastException&) { } catch (const FlycastException&) {
} }
emu.unloadGame(); emu.unloadGame();
gui_state = GuiState::Main; gui_setState(GuiState::Main);
} }
bool ready() bool ready()

View File

@ -111,7 +111,7 @@ static bool emulatorRunning;
} }
if ([url startAccessingSecurityScopedResource]) if ([url startAccessingSecurityScopedResource])
openedURL = url; openedURL = url;
gui_state = GuiState::Closed; gui_setState(GuiState::Closed);
gui_start_game(url.fileSystemRepresentation); gui_start_game(url.fileSystemRepresentation);
return true; return true;