Files
ppsspp/ext/imgui/imgui_impl_platform.cpp
T
Henrik RydgårdandClaude Opus 5.5 70988aa50c ImGui: Keep the context and debugger state when Android switches away
NativeShutdownGraphics, which Android runs whenever the app loses its
surface, destroyed the imgui context and the ImDebugger along with the
device objects, so window layout and debugger state reset on return.
Now only the device objects go there (the backend already recreates
them), and the context and debugger are torn down in NativeShutdown.
Both configs are still saved on device loss, in case the app is killed
in the background.

imgui.ini is now read and written through our File API rather than
imgui's fopen, which can't reach a memstick behind a content URI.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 14:14:42 +02:00

280 lines
8.7 KiB
C++

#include "ext/imgui/imgui.h"
#include "Common/File/Path.h"
#include "Common/File/FileUtil.h"
#include "Common/Input/KeyCodes.h"
#include "Common/Data/Encoding/Utf8.h"
#include "Common/System/Display.h"
#include "Common/TimeUtil.h"
#include "Common/StringUtils.h"
#include "Common/Log.h"
#include "imgui_impl_platform.h"
static ImGuiMouseCursor g_cursor = ImGuiMouseCursor_Arrow;
static Path g_iniPath;
void ImGui_ImplPlatform_KeyEvent(const KeyInput &key) {
ImGuiIO &io = ImGui::GetIO();
if (key.flags & KeyInputFlags::DOWN) {
// Specially handle scroll events and any other special keys.
switch (key.keyCode) {
case NKCODE_EXT_MOUSEWHEEL_UP:
io.AddMouseWheelEvent(0, key.Delta() * 0.010f);
break;
case NKCODE_EXT_MOUSEWHEEL_DOWN:
io.AddMouseWheelEvent(0, -key.Delta() * 0.010f);
break;
default:
{
ImGuiKey keyCode = KeyCodeToImGui(key.keyCode);
if (keyCode != ImGuiKey_None) {
io.AddKeyEvent(keyCode, true);
}
break;
}
}
}
if (key.flags & KeyInputFlags::UP) {
ImGuiKey keyCode = KeyCodeToImGui(key.keyCode);
if (keyCode != ImGuiKey_None) {
io.AddKeyEvent(keyCode, false);
}
}
if (key.flags & KeyInputFlags::CHAR) {
const int unichar = key.unicodeChar;
if (unichar >= 0x20) {
// Insert it! (todo: do it with a string insert)
char buf[16];
buf[u8_wc_toutf8(buf, unichar)] = '\0';
io.AddInputCharactersUTF8(buf);
}
}
}
void ImGui_ImplPlatform_TouchEvent(const TouchInput &touch) {
ImGuiIO& io = ImGui::GetIO();
// We use real pixels in the imgui, no DPI adjustment yet.
float x = touch.x / g_display.dpi_scale_x;
float y = touch.y / g_display.dpi_scale_y;
if (touch.flags & TouchInputFlags::MOVE) {
io.AddMousePosEvent(x, y);
}
if (touch.flags & TouchInputFlags::DOWN) {
io.AddMousePosEvent(x, y);
if (touch.flags & TouchInputFlags::MOUSE) {
if (touch.buttons & 1)
io.AddMouseButtonEvent(0, true);
if (touch.buttons & 2)
io.AddMouseButtonEvent(1, true);
} else {
io.AddMouseButtonEvent(0, true);
}
}
if (touch.flags & TouchInputFlags::UP) {
io.AddMousePosEvent(x, y);
if (touch.flags & TouchInputFlags::MOUSE) {
if (touch.buttons & 1)
io.AddMouseButtonEvent(0, false);
if (touch.buttons & 2)
io.AddMouseButtonEvent(1, false);
} else {
io.AddMouseButtonEvent(0, false);
}
}
}
void ImGui_ImplPlatform_Init(const Path &configPath) {
// imgui's own ini handling uses fopen, which can't reach a memstick behind an Android content URI.
g_iniPath = configPath;
ImGui::GetIO().IniFilename = nullptr;
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_DockingEnable;
std::string data;
if (File::ReadTextFileToString(g_iniPath, &data)) {
ImGui::LoadIniSettingsFromMemory(data.data(), data.size());
}
}
void ImGui_ImplPlatform_SaveIni(bool force) {
ImGuiIO &io = ImGui::GetIO();
if (!force && !io.WantSaveIniSettings) {
return;
}
size_t size = 0;
const char *data = ImGui::SaveIniSettingsToMemory(&size);
if (!File::WriteDataToFile(true, data, size, g_iniPath)) {
WARN_LOG(Log::System, "Failed to save imgui settings to '%s'", g_iniPath.c_str());
}
io.WantSaveIniSettings = false;
}
void ImGui_ImplPlatform_AxisEvent(const AxisInput &axis) {
// Ignore for now.
}
void ImGui_ImplPlatform_NewFrame() {
static double lastTime = 0.0;
if (lastTime == 0.0) {
lastTime = time_now_d();
}
double now = time_now_d();
g_cursor = ImGui::GetMouseCursor();
ImGuiIO &io = ImGui::GetIO();
io.DisplaySize = ImVec2(g_display.pixel_xres, g_display.pixel_yres);
io.DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
io.DeltaTime = now - lastTime;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
lastTime = now;
}
ImGuiMouseCursor ImGui_ImplPlatform_GetCursor() {
return g_cursor;
}
// Written by chatgpt
ImGuiKey KeyCodeToImGui(InputKeyCode keyCode) {
switch (keyCode) {
case NKCODE_DPAD_UP: return ImGuiKey_UpArrow;
case NKCODE_DPAD_DOWN: return ImGuiKey_DownArrow;
case NKCODE_DPAD_LEFT: return ImGuiKey_LeftArrow;
case NKCODE_DPAD_RIGHT: return ImGuiKey_RightArrow;
case NKCODE_ENTER: return ImGuiKey_Enter;
case NKCODE_ESCAPE: return ImGuiKey_Escape;
case NKCODE_SHIFT_LEFT: return ImGuiKey_LeftShift;
case NKCODE_SHIFT_RIGHT: return ImGuiKey_RightShift;
case NKCODE_ALT_LEFT: return ImGuiKey_LeftAlt;
case NKCODE_ALT_RIGHT: return ImGuiKey_RightAlt;
case NKCODE_CTRL_LEFT: return ImGuiKey_LeftCtrl;
case NKCODE_CTRL_RIGHT: return ImGuiKey_RightCtrl;
case NKCODE_META_LEFT: return ImGuiKey_LeftSuper;
case NKCODE_META_RIGHT: return ImGuiKey_RightSuper;
case NKCODE_TAB: return ImGuiKey_Tab;
case NKCODE_MENU: return ImGuiKey_Menu;
case NKCODE_DEL: return ImGuiKey_Backspace;
case NKCODE_FORWARD_DEL: return ImGuiKey_Delete;
case NKCODE_CAPS_LOCK: return ImGuiKey_CapsLock;
case NKCODE_SPACE: return ImGuiKey_Space;
case NKCODE_PAGE_UP: return ImGuiKey_PageUp;
case NKCODE_PAGE_DOWN: return ImGuiKey_PageDown;
case NKCODE_MOVE_HOME: return ImGuiKey_Home;
case NKCODE_MOVE_END: return ImGuiKey_End;
case NKCODE_INSERT: return ImGuiKey_Insert;
// Numeric keys
case NKCODE_0: return ImGuiKey_0;
case NKCODE_1: return ImGuiKey_1;
case NKCODE_2: return ImGuiKey_2;
case NKCODE_3: return ImGuiKey_3;
case NKCODE_4: return ImGuiKey_4;
case NKCODE_5: return ImGuiKey_5;
case NKCODE_6: return ImGuiKey_6;
case NKCODE_7: return ImGuiKey_7;
case NKCODE_8: return ImGuiKey_8;
case NKCODE_9: return ImGuiKey_9;
// Letter keys
case NKCODE_A: return ImGuiKey_A;
case NKCODE_B: return ImGuiKey_B;
case NKCODE_C: return ImGuiKey_C;
case NKCODE_D: return ImGuiKey_D;
case NKCODE_E: return ImGuiKey_E;
case NKCODE_F: return ImGuiKey_F;
case NKCODE_G: return ImGuiKey_G;
case NKCODE_H: return ImGuiKey_H;
case NKCODE_I: return ImGuiKey_I;
case NKCODE_J: return ImGuiKey_J;
case NKCODE_K: return ImGuiKey_K;
case NKCODE_L: return ImGuiKey_L;
case NKCODE_M: return ImGuiKey_M;
case NKCODE_N: return ImGuiKey_N;
case NKCODE_O: return ImGuiKey_O;
case NKCODE_P: return ImGuiKey_P;
case NKCODE_Q: return ImGuiKey_Q;
case NKCODE_R: return ImGuiKey_R;
case NKCODE_S: return ImGuiKey_S;
case NKCODE_T: return ImGuiKey_T;
case NKCODE_U: return ImGuiKey_U;
case NKCODE_V: return ImGuiKey_V;
case NKCODE_W: return ImGuiKey_W;
case NKCODE_X: return ImGuiKey_X;
case NKCODE_Y: return ImGuiKey_Y;
case NKCODE_Z: return ImGuiKey_Z;
// Symbols
case NKCODE_COMMA: return ImGuiKey_Comma;
case NKCODE_PERIOD: return ImGuiKey_Period;
case NKCODE_MINUS: return ImGuiKey_Minus;
case NKCODE_PLUS: return ImGuiKey_Equal; // Hmm
case NKCODE_EQUALS: return ImGuiKey_Equal;
case NKCODE_LEFT_BRACKET: return ImGuiKey_LeftBracket;
case NKCODE_RIGHT_BRACKET: return ImGuiKey_RightBracket;
case NKCODE_BACKSLASH: return ImGuiKey_Backslash;
case NKCODE_SEMICOLON: return ImGuiKey_Semicolon;
case NKCODE_APOSTROPHE: return ImGuiKey_Apostrophe;
case NKCODE_SLASH: return ImGuiKey_Slash;
case NKCODE_GRAVE: return ImGuiKey_GraveAccent;
// Function keys
case NKCODE_F1: return ImGuiKey_F1;
case NKCODE_F2: return ImGuiKey_F2;
case NKCODE_F3: return ImGuiKey_F3;
case NKCODE_F4: return ImGuiKey_F4;
case NKCODE_F5: return ImGuiKey_F5;
case NKCODE_F6: return ImGuiKey_F6;
case NKCODE_F7: return ImGuiKey_F7;
case NKCODE_F8: return ImGuiKey_F8;
case NKCODE_F9: return ImGuiKey_F9;
case NKCODE_F10: return ImGuiKey_F10;
case NKCODE_F11: return ImGuiKey_F11;
case NKCODE_F12: return ImGuiKey_F12;
// Keypad
case NKCODE_NUMPAD_0: return ImGuiKey_Keypad0;
case NKCODE_NUMPAD_1: return ImGuiKey_Keypad1;
case NKCODE_NUMPAD_2: return ImGuiKey_Keypad2;
case NKCODE_NUMPAD_3: return ImGuiKey_Keypad3;
case NKCODE_NUMPAD_4: return ImGuiKey_Keypad4;
case NKCODE_NUMPAD_5: return ImGuiKey_Keypad5;
case NKCODE_NUMPAD_6: return ImGuiKey_Keypad6;
case NKCODE_NUMPAD_7: return ImGuiKey_Keypad7;
case NKCODE_NUMPAD_8: return ImGuiKey_Keypad8;
case NKCODE_NUMPAD_9: return ImGuiKey_Keypad9;
case NKCODE_NUMPAD_DIVIDE: return ImGuiKey_KeypadDivide;
case NKCODE_NUMPAD_MULTIPLY: return ImGuiKey_KeypadMultiply;
case NKCODE_NUMPAD_SUBTRACT: return ImGuiKey_KeypadSubtract;
case NKCODE_NUMPAD_ADD: return ImGuiKey_KeypadAdd;
case NKCODE_NUMPAD_ENTER: return ImGuiKey_KeypadEnter;
case NKCODE_NUMPAD_EQUALS: return ImGuiKey_KeypadEqual;
// Lock keys
case NKCODE_NUM_LOCK: return ImGuiKey_NumLock;
case NKCODE_SCROLL_LOCK: return ImGuiKey_ScrollLock;
case NKCODE_EXT_MOUSEBUTTON_1:
case NKCODE_EXT_MOUSEBUTTON_2:
case NKCODE_EXT_MOUSEBUTTON_3:
case NKCODE_EXT_MOUSEBUTTON_4:
case NKCODE_EXT_MOUSEBUTTON_5:
case NKCODE_EXT_MOUSEWHEEL_DOWN:
case NKCODE_EXT_MOUSEWHEEL_UP:
// Keys ignored for imgui
return ImGuiKey_None;
case NKCODE_PRINTSCREEN:
return ImGuiKey_PrintScreen;
case NKCODE_EXT_PIPE:
// No valid mapping exists.
return ImGuiKey_None;
default:
WARN_LOG(Log::System, "Unmapped ImGui keycode conversion from %d", keyCode);
return ImGuiKey_None;
}
}