mirror of
https://github.com/patchzyy/wiicompiled
synced 2026-10-01 16:01:23 -04:00
Add Exit button + controller led fix (#221)
This commit is contained in:
@@ -58,6 +58,7 @@ inline void Flush(bool force = false) {
|
||||
// still active. A window close is an intentional successful exit, so end the
|
||||
// process directly and do not run the crash/atexit paths.
|
||||
[[noreturn]] inline void ExitForAuroraWindowClose() noexcept {
|
||||
settings_overlay::ReleaseControllers();
|
||||
WindowPlacementPersistence::Flush(true);
|
||||
#if defined(_WIN32)
|
||||
::ExitProcess(0);
|
||||
|
||||
@@ -12,4 +12,6 @@ void Draw() noexcept;
|
||||
bool StartupScreenVisible() noexcept;
|
||||
void NotifyStrapInputAccepted() noexcept;
|
||||
void AdvancePresentedFrame() noexcept;
|
||||
// Put host controllers back to a neutral state before the process ends.
|
||||
void ReleaseControllers() noexcept;
|
||||
} // namespace settings_overlay
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "settings_overlay.h"
|
||||
#include "audio_backend.h"
|
||||
#include "aurora_events.h"
|
||||
#include "controller_button_names.h"
|
||||
#include "controller_mapping_wizard.h"
|
||||
#include "input_bindings.h"
|
||||
@@ -15,6 +16,7 @@
|
||||
#include <SDL3/SDL_keyboard.h>
|
||||
#include <SDL3/SDL_mouse.h>
|
||||
#include <SDL3/SDL_scancode.h>
|
||||
#include <SDL3/SDL_timer.h>
|
||||
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
@@ -70,6 +72,7 @@ const char* GraphicsApiDisplayName() {
|
||||
}
|
||||
|
||||
bool g_topBarVisible = false;
|
||||
bool g_exitPromptOpen = false;
|
||||
bool g_rumbleEnabled = RuntimeConfigFile::RumbleEnabled(true);
|
||||
int g_controllerPort = 0;
|
||||
float g_resolutionScale = RuntimeConfigFile::ResolutionMultiplier(1.0f);
|
||||
@@ -1175,6 +1178,18 @@ void DrawStartupScreen() {
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
void DrawExitPrompt() {
|
||||
constexpr const char* kTitle = "Exit";
|
||||
if (g_exitPromptOpen && !ImGui::IsPopupOpen(kTitle)) ImGui::OpenPopup(kTitle);
|
||||
if (!ImGui::BeginPopupModal(kTitle, &g_exitPromptOpen, ImGuiWindowFlags_AlwaysAutoResize)) return;
|
||||
ImGui::TextUnformatted("Quit the game?");
|
||||
if (ImGui::Button("Exit", ImVec2(120.0f, 0.0f))) ExitForAuroraWindowClose();
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Cancel", ImVec2(120.0f, 0.0f))) g_exitPromptOpen = false;
|
||||
if (!g_exitPromptOpen) ImGui::CloseCurrentPopup();
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
void DrawTopBar() {
|
||||
if (!g_topBarVisible) {
|
||||
return;
|
||||
@@ -1243,11 +1258,17 @@ void DrawTopBar() {
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
const float hideWidth = ImGui::CalcTextSize("Hide (F10)").x + ImGui::GetStyle().FramePadding.x * 2.0f;
|
||||
ImGui::SetCursorPosX(std::max(ImGui::GetCursorPosX(), ImGui::GetWindowWidth() - hideWidth - 8.0f));
|
||||
const ImGuiStyle& style = ImGui::GetStyle();
|
||||
const float hideWidth = ImGui::CalcTextSize("Hide (F10)").x + style.FramePadding.x * 2.0f;
|
||||
const float exitWidth = ImGui::CalcTextSize("X").x + style.FramePadding.x * 2.0f;
|
||||
ImGui::SetCursorPosX(std::max(ImGui::GetCursorPosX(),
|
||||
ImGui::GetWindowWidth() - hideWidth - exitWidth - style.ItemSpacing.x - 8.0f));
|
||||
if (ImGui::MenuItem("Hide (F10)")) {
|
||||
SetTopBarVisible(false);
|
||||
}
|
||||
if (ImGui::MenuItem("X")) {
|
||||
g_exitPromptOpen = true;
|
||||
}
|
||||
ImGui::EndMainMenuBar();
|
||||
}
|
||||
|
||||
@@ -1342,12 +1363,36 @@ void HandleEvents(const AuroraEvent* events) noexcept {
|
||||
if (!g_rebind.active && IsToggleKey(ev->sdl, SDL_SCANCODE_F10)) {
|
||||
SetTopBarVisible(!g_topBarVisible);
|
||||
}
|
||||
if (!g_rebind.active && !g_topBarVisible && IsToggleKey(ev->sdl, SDL_SCANCODE_ESCAPE)) {
|
||||
g_exitPromptOpen = true;
|
||||
}
|
||||
if (IsMouseActivity(ev->sdl)) {
|
||||
g_lastMouseActivity = Clock::now();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReleaseControllers() noexcept {
|
||||
// Aurora drives the LED white on first PADRead and never clears it, and the
|
||||
// exit paths terminate the process outright, so do it here.
|
||||
bool queued = false;
|
||||
for (uint32_t port = 0; port < PAD_MAX_CONTROLLERS; ++port) {
|
||||
const s32 index = PADGetIndexForPort(port);
|
||||
if (index < 0) continue;
|
||||
if (SDL_Gamepad* pad = PADGetSDLGamepadForIndex(static_cast<u32>(index))) {
|
||||
SDL_SetGamepadLED(pad, 0, 0, 0);
|
||||
queued = true;
|
||||
}
|
||||
}
|
||||
constexpr std::array<uint32_t, PAD_MAX_CONTROLLERS> stopAll{
|
||||
PAD_MOTOR_STOP_HARD, PAD_MOTOR_STOP_HARD, PAD_MOTOR_STOP_HARD, PAD_MOTOR_STOP_HARD};
|
||||
PADControlAllMotors(stopAll.data());
|
||||
// SDL hands LED and rumble reports to its own HIDAPI sender thread rather
|
||||
// than writing them here, so without this the process dies before the
|
||||
// controller ever receives them.
|
||||
if (queued) SDL_Delay(120);
|
||||
}
|
||||
|
||||
void Draw() noexcept {
|
||||
// Wait for the frame worker's DONE phase: it has replayed the previous frame's ImGui draw lists
|
||||
// and started the next ImGui frame, so all overlay callers can now safely issue ImGui commands.
|
||||
@@ -1365,6 +1410,7 @@ void Draw() noexcept {
|
||||
}
|
||||
DrawFpsOverlay();
|
||||
DrawTopBar();
|
||||
DrawExitPrompt();
|
||||
controller_mapping_wizard::Draw();
|
||||
// The wizard captures raw presses; keep them out of the game.
|
||||
const bool inputBlocked = controller_mapping_wizard::IsActive() || g_rebind.active;
|
||||
|
||||
Reference in New Issue
Block a user