CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Windows/MainWindowMenu.cpp
Views: 1401
1
#include "ppsspp_config.h"
2
#include <algorithm>
3
#include <string>
4
#include <sstream>
5
#include <unordered_map>
6
7
#include "CommonWindows.h"
8
#include <shellapi.h>
9
10
#include "resource.h"
11
12
#include "Common/GPU/OpenGL/GLFeatures.h"
13
14
#include "Common/Data/Text/I18n.h"
15
#include "Common/Data/Encoding/Utf8.h"
16
#include "Common/System/System.h"
17
#include "Common/System/OSD.h"
18
#include "Common/System/NativeApp.h"
19
#include "Common/System/Request.h"
20
#include "Common/File/FileUtil.h"
21
#include "Common/Log.h"
22
#include "Common/Log/LogManager.h"
23
#include "Common/Log/ConsoleListener.h"
24
#include "Common/OSVersion.h"
25
#include "Common/GPU/Vulkan/VulkanLoader.h"
26
#include "Common/StringUtils.h"
27
#if PPSSPP_API(ANY_GL)
28
#include "GPU/GLES/TextureCacheGLES.h"
29
#include "GPU/GLES/FramebufferManagerGLES.h"
30
#endif
31
#include "UI/OnScreenDisplay.h"
32
#include "GPU/Common/PostShader.h"
33
#include "GPU/Common/FramebufferManagerCommon.h"
34
#include "GPU/Common/TextureDecoder.h"
35
#include "GPU/Common/TextureScalerCommon.h"
36
37
#include "Core/Config.h"
38
#include "Core/ConfigValues.h"
39
#include "Core/FileSystems/MetaFileSystem.h"
40
#include "Core/KeyMap.h"
41
#include "UI/OnScreenDisplay.h"
42
#include "Windows/MainWindowMenu.h"
43
#include "Windows/MainWindow.h"
44
#include "Windows/W32Util/DialogManager.h"
45
#include "Windows/W32Util/ShellUtil.h"
46
#include "Windows/W32Util/Misc.h"
47
#include "Windows/InputBox.h"
48
#include "Windows/main.h"
49
#include "Windows/W32Util/DarkMode.h"
50
51
#include "Core/HLE/sceUmd.h"
52
#include "Core/SaveState.h"
53
#include "Core/Core.h"
54
#include "Core/RetroAchievements.h"
55
56
#ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION
57
#include "ext/rcheevos/include/rc_client_raintegration.h"
58
#endif
59
60
extern bool g_TakeScreenshot;
61
62
namespace MainWindow {
63
extern HINSTANCE hInst;
64
extern bool noFocusPause;
65
static bool browsePauseAfter;
66
67
static std::unordered_map<int, std::string> initialMenuKeys;
68
static std::vector<std::string> availableShaders;
69
static std::string menuLanguageID = "";
70
static int menuKeymapGeneration = -1;
71
static bool menuShaderInfoLoaded = false;
72
std::vector<ShaderInfo> menuShaderInfo;
73
74
LRESULT CALLBACK AboutDlgProc(HWND, UINT, WPARAM, LPARAM);
75
76
void SetIngameMenuItemStates(HMENU menu, const GlobalUIState state) {
77
bool menuEnableBool = state == UISTATE_INGAME || state == UISTATE_EXCEPTION;
78
79
bool loadStateEnableBool = menuEnableBool;
80
bool saveStateEnableBool = menuEnableBool;
81
if (Achievements::HardcoreModeActive()) {
82
loadStateEnableBool = false;
83
if (!g_Config.bAchievementsSaveStateInHardcoreMode) {
84
saveStateEnableBool = false;
85
}
86
}
87
88
UINT menuEnable = menuEnableBool ? MF_ENABLED : MF_GRAYED;
89
UINT loadStateEnable = loadStateEnableBool ? MF_ENABLED : MF_GRAYED;
90
UINT saveStateEnable = saveStateEnableBool ? MF_ENABLED : MF_GRAYED;
91
UINT menuInGameEnable = state == UISTATE_INGAME ? MF_ENABLED : MF_GRAYED;
92
UINT umdSwitchEnable = state == UISTATE_INGAME && getUMDReplacePermit() ? MF_ENABLED : MF_GRAYED;
93
94
EnableMenuItem(menu, ID_FILE_SAVESTATE_SLOT_MENU, saveStateEnable);
95
EnableMenuItem(menu, ID_FILE_SAVESTATEFILE, saveStateEnable);
96
EnableMenuItem(menu, ID_FILE_LOADSTATEFILE, loadStateEnable);
97
EnableMenuItem(menu, ID_FILE_QUICKSAVESTATE, saveStateEnable);
98
EnableMenuItem(menu, ID_FILE_QUICKLOADSTATE, loadStateEnable);
99
EnableMenuItem(menu, ID_EMULATION_PAUSE, menuEnable);
100
EnableMenuItem(menu, ID_EMULATION_STOP, menuEnable);
101
EnableMenuItem(menu, ID_EMULATION_RESET, menuEnable);
102
EnableMenuItem(menu, ID_EMULATION_SWITCH_UMD, umdSwitchEnable);
103
EnableMenuItem(menu, ID_EMULATION_CHAT, g_Config.bEnableNetworkChat ? menuInGameEnable : MF_GRAYED);
104
EnableMenuItem(menu, ID_TOGGLE_BREAK, menuEnable);
105
EnableMenuItem(menu, ID_DEBUG_LOADMAPFILE, menuEnable);
106
EnableMenuItem(menu, ID_DEBUG_SAVEMAPFILE, menuEnable);
107
EnableMenuItem(menu, ID_DEBUG_LOADSYMFILE, menuEnable);
108
EnableMenuItem(menu, ID_DEBUG_SAVESYMFILE, menuEnable);
109
EnableMenuItem(menu, ID_DEBUG_RESETSYMBOLTABLE, menuEnable);
110
EnableMenuItem(menu, ID_DEBUG_SHOWDEBUGSTATISTICS, menuInGameEnable);
111
EnableMenuItem(menu, ID_DEBUG_EXTRACTFILE, menuEnable);
112
EnableMenuItem(menu, ID_DEBUG_MEMORYBASE, menuInGameEnable);
113
114
// While playing, this pop up doesn't work - and probably doesn't make sense.
115
EnableMenuItem(menu, ID_OPTIONS_LANGUAGE, state == UISTATE_INGAME ? MF_GRAYED : MF_ENABLED);
116
}
117
118
static HMENU GetSubmenuById(HMENU menu, int menuID) {
119
MENUITEMINFO menuInfo{ sizeof(MENUITEMINFO), MIIM_SUBMENU };
120
if (GetMenuItemInfo(menu, menuID, MF_BYCOMMAND, &menuInfo) != FALSE) {
121
return menuInfo.hSubMenu;
122
}
123
return nullptr;
124
}
125
126
static void EmptySubMenu(HMENU menu) {
127
int c = GetMenuItemCount(menu);
128
for (int i = 0; i < c; ++i) {
129
RemoveMenu(menu, 0, MF_BYPOSITION);
130
}
131
}
132
133
static std::string GetMenuItemText(HMENU menu, int menuID) {
134
MENUITEMINFO menuInfo{ sizeof(menuInfo), MIIM_STRING };
135
std::string retVal;
136
if (GetMenuItemInfo(menu, menuID, MF_BYCOMMAND, &menuInfo) != FALSE) {
137
wchar_t *buffer = new wchar_t[++menuInfo.cch];
138
menuInfo.dwTypeData = buffer;
139
GetMenuItemInfo(menu, menuID, MF_BYCOMMAND, &menuInfo);
140
retVal = ConvertWStringToUTF8(menuInfo.dwTypeData);
141
delete[] buffer;
142
}
143
144
return retVal;
145
}
146
147
const std::string &GetMenuItemInitialText(HMENU menu, const int menuID) {
148
if (initialMenuKeys.find(menuID) == initialMenuKeys.end()) {
149
initialMenuKeys[menuID] = GetMenuItemText(menu, menuID);
150
}
151
return initialMenuKeys[menuID];
152
}
153
154
void CreateHelpMenu(HMENU menu) {
155
auto des = GetI18NCategory(I18NCat::DESKTOPUI);
156
157
const std::wstring visitMainWebsite = ConvertUTF8ToWString(des->T("www.ppsspp.org"));
158
const std::wstring visitForum = ConvertUTF8ToWString(des->T("PPSSPP Forums"));
159
const std::wstring buyGold = ConvertUTF8ToWString(des->T("Buy Gold"));
160
const std::wstring gitHub = ConvertUTF8ToWString(des->T("GitHub"));
161
const std::wstring discord = ConvertUTF8ToWString(des->T("Discord"));
162
const std::wstring aboutPPSSPP = ConvertUTF8ToWString(des->T("About PPSSPP..."));
163
164
HMENU helpMenu = GetSubmenuById(menu, ID_HELP_MENU);
165
EmptySubMenu(helpMenu);
166
167
AppendMenu(helpMenu, MF_STRING | MF_BYCOMMAND, ID_HELP_OPENWEBSITE, visitMainWebsite.c_str());
168
AppendMenu(helpMenu, MF_STRING | MF_BYCOMMAND, ID_HELP_OPENFORUM, visitForum.c_str());
169
// Repeat the process for other languages, if necessary.
170
AppendMenu(helpMenu, MF_STRING | MF_BYCOMMAND, ID_HELP_BUYGOLD, buyGold.c_str());
171
AppendMenu(helpMenu, MF_STRING | MF_BYCOMMAND, ID_HELP_GITHUB, gitHub.c_str());
172
AppendMenu(helpMenu, MF_STRING | MF_BYCOMMAND, ID_HELP_DISCORD, discord.c_str());
173
AppendMenu(helpMenu, MF_SEPARATOR, 0, 0);
174
AppendMenu(helpMenu, MF_STRING | MF_BYCOMMAND, ID_HELP_ABOUT, aboutPPSSPP.c_str());
175
}
176
177
static void TranslateMenuItem(const HMENU hMenu, const int menuID, const std::wstring& accelerator = L"", const char *key = nullptr) {
178
auto des = GetI18NCategory(I18NCat::DESKTOPUI);
179
180
std::wstring translated;
181
if (key == nullptr || !strcmp(key, "")) {
182
translated = ConvertUTF8ToWString(des->T(GetMenuItemInitialText(hMenu, menuID)));
183
} else {
184
translated = ConvertUTF8ToWString(des->T(key));
185
}
186
translated.append(accelerator);
187
188
ModifyMenu(hMenu, menuID, MF_STRING | MF_BYCOMMAND, menuID, translated.c_str());
189
}
190
191
void DoTranslateMenus(HWND hWnd, HMENU menu) {
192
auto useDefHotkey = [](int virtKey) {
193
return !KeyMap::PspButtonHasMappings(virtKey);
194
};
195
196
TranslateMenuItem(menu, ID_FILE_MENU);
197
TranslateMenuItem(menu, ID_EMULATION_MENU);
198
TranslateMenuItem(menu, ID_DEBUG_MENU);
199
TranslateMenuItem(menu, ID_OPTIONS_MENU);
200
TranslateMenuItem(menu, ID_HELP_MENU);
201
202
// File menu
203
TranslateMenuItem(menu, ID_FILE_LOAD);
204
TranslateMenuItem(menu, ID_FILE_LOAD_DIR);
205
TranslateMenuItem(menu, ID_FILE_LOAD_MEMSTICK);
206
TranslateMenuItem(menu, ID_FILE_OPEN_NEW_INSTANCE);
207
TranslateMenuItem(menu, ID_FILE_MEMSTICK);
208
TranslateMenuItem(menu, ID_FILE_SAVESTATE_SLOT_MENU, useDefHotkey(VIRTKEY_NEXT_SLOT) ? L"\tF3" : L"");
209
TranslateMenuItem(menu, ID_FILE_QUICKLOADSTATE, useDefHotkey(VIRTKEY_LOAD_STATE) ? L"\tF4" : L"");
210
TranslateMenuItem(menu, ID_FILE_QUICKSAVESTATE, useDefHotkey(VIRTKEY_SAVE_STATE) ? L"\tF2" : L"");
211
TranslateMenuItem(menu, ID_FILE_LOADSTATEFILE);
212
TranslateMenuItem(menu, ID_FILE_SAVESTATEFILE);
213
TranslateMenuItem(menu, ID_FILE_RECORD_MENU);
214
TranslateMenuItem(menu, ID_FILE_EXIT, L"\tAlt+F4");
215
216
// Emulation menu
217
TranslateMenuItem(menu, ID_EMULATION_PAUSE);
218
TranslateMenuItem(menu, ID_EMULATION_STOP, g_Config.bSystemControls ? L"\tCtrl+W" : L"");
219
TranslateMenuItem(menu, ID_EMULATION_RESET, g_Config.bSystemControls ? L"\tCtrl+B" : L"");
220
TranslateMenuItem(menu, ID_EMULATION_SWITCH_UMD, g_Config.bSystemControls ? L"\tCtrl+U" : L"");
221
TranslateMenuItem(menu, ID_EMULATION_ROTATION_MENU);
222
TranslateMenuItem(menu, ID_EMULATION_ROTATION_H);
223
TranslateMenuItem(menu, ID_EMULATION_ROTATION_V);
224
TranslateMenuItem(menu, ID_EMULATION_ROTATION_H_R);
225
TranslateMenuItem(menu, ID_EMULATION_ROTATION_V_R);
226
227
// Debug menu
228
TranslateMenuItem(menu, ID_TOGGLE_BREAK, g_Config.bSystemControls ? L"\tF8" : L"", "Break");
229
TranslateMenuItem(menu, ID_DEBUG_BREAKONLOAD);
230
TranslateMenuItem(menu, ID_DEBUG_IGNOREILLEGALREADS);
231
TranslateMenuItem(menu, ID_DEBUG_LOADMAPFILE);
232
TranslateMenuItem(menu, ID_DEBUG_SAVEMAPFILE);
233
TranslateMenuItem(menu, ID_DEBUG_LOADSYMFILE);
234
TranslateMenuItem(menu, ID_DEBUG_SAVESYMFILE);
235
TranslateMenuItem(menu, ID_DEBUG_RESETSYMBOLTABLE);
236
TranslateMenuItem(menu, ID_DEBUG_TAKESCREENSHOT, g_Config.bSystemControls ? L"\tF12" : L"");
237
TranslateMenuItem(menu, ID_DEBUG_DUMPNEXTFRAME);
238
TranslateMenuItem(menu, ID_DEBUG_SHOWDEBUGSTATISTICS);
239
TranslateMenuItem(menu, ID_DEBUG_RESTARTGRAPHICS);
240
TranslateMenuItem(menu, ID_DEBUG_DISASSEMBLY, g_Config.bSystemControls ? L"\tCtrl+D" : L"");
241
TranslateMenuItem(menu, ID_DEBUG_GEDEBUGGER, g_Config.bSystemControls ? L"\tCtrl+G" : L"");
242
TranslateMenuItem(menu, ID_DEBUG_EXTRACTFILE);
243
TranslateMenuItem(menu, ID_DEBUG_LOG, g_Config.bSystemControls ? L"\tCtrl+L" : L"");
244
TranslateMenuItem(menu, ID_DEBUG_MEMORYBASE);
245
TranslateMenuItem(menu, ID_DEBUG_MEMORYVIEW, g_Config.bSystemControls ? L"\tCtrl+M" : L"");
246
247
// Options menu
248
TranslateMenuItem(menu, ID_OPTIONS_LANGUAGE);
249
TranslateMenuItem(menu, ID_OPTIONS_TOPMOST);
250
TranslateMenuItem(menu, ID_OPTIONS_PAUSE_FOCUS);
251
TranslateMenuItem(menu, ID_OPTIONS_IGNOREWINKEY);
252
TranslateMenuItem(menu, ID_OPTIONS_MORE_SETTINGS);
253
TranslateMenuItem(menu, ID_OPTIONS_CONTROLS);
254
TranslateMenuItem(menu, ID_OPTIONS_DISPLAY_LAYOUT);
255
256
// Movie menu
257
TranslateMenuItem(menu, ID_FILE_DUMPFRAMES);
258
TranslateMenuItem(menu, ID_FILE_USEFFV1);
259
TranslateMenuItem(menu, ID_FILE_DUMP_VIDEO_OUTPUT);
260
TranslateMenuItem(menu, ID_FILE_DUMPAUDIO);
261
262
// Skip display multipliers x1-x10
263
TranslateMenuItem(menu, ID_OPTIONS_FULLSCREEN, g_Config.bSystemControls ? L"\tAlt+Return, F11" : L"");
264
TranslateMenuItem(menu, ID_OPTIONS_VSYNC);
265
TranslateMenuItem(menu, ID_OPTIONS_SCREEN_MENU, g_Config.bSystemControls ? L"\tCtrl+1" : L"");
266
TranslateMenuItem(menu, ID_OPTIONS_SCREENAUTO);
267
// Skip rendering resolution 2x-5x..
268
TranslateMenuItem(menu, ID_OPTIONS_WINDOW_MENU);
269
// Skip window size 1x-4x..
270
TranslateMenuItem(menu, ID_OPTIONS_BACKEND_MENU);
271
TranslateMenuItem(menu, ID_OPTIONS_DIRECT3D11);
272
TranslateMenuItem(menu, ID_OPTIONS_DIRECT3D9);
273
TranslateMenuItem(menu, ID_OPTIONS_OPENGL);
274
TranslateMenuItem(menu, ID_OPTIONS_VULKAN);
275
276
TranslateMenuItem(menu, ID_OPTIONS_RENDERMODE_MENU);
277
TranslateMenuItem(menu, ID_OPTIONS_SKIP_BUFFER_EFFECTS);
278
TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIP_MENU, g_Config.bSystemControls ? L"\tF7" : L"");
279
TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIP_AUTO);
280
TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIP_0);
281
TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIPTYPE_MENU);
282
TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIPTYPE_COUNT);
283
TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIPTYPE_PRCNT);
284
// Skip frameskipping 1-8..
285
TranslateMenuItem(menu, ID_OPTIONS_TEXTUREFILTERING_MENU);
286
TranslateMenuItem(menu, ID_OPTIONS_TEXTUREFILTERING_AUTO);
287
TranslateMenuItem(menu, ID_OPTIONS_NEARESTFILTERING);
288
TranslateMenuItem(menu, ID_OPTIONS_LINEARFILTERING);
289
TranslateMenuItem(menu, ID_OPTIONS_AUTOMAXQUALITYFILTERING);
290
TranslateMenuItem(menu, ID_OPTIONS_SMART2DTEXTUREFILTERING);
291
TranslateMenuItem(menu, ID_OPTIONS_SCREENFILTER_MENU);
292
TranslateMenuItem(menu, ID_OPTIONS_BUFLINEARFILTER);
293
TranslateMenuItem(menu, ID_OPTIONS_BUFNEARESTFILTER);
294
TranslateMenuItem(menu, ID_OPTIONS_TEXTURESCALING_MENU);
295
TranslateMenuItem(menu, ID_TEXTURESCALING_OFF);
296
// Skip texture scaling 2x-5x...
297
TranslateMenuItem(menu, ID_TEXTURESCALING_XBRZ);
298
TranslateMenuItem(menu, ID_TEXTURESCALING_HYBRID);
299
TranslateMenuItem(menu, ID_TEXTURESCALING_BICUBIC);
300
TranslateMenuItem(menu, ID_TEXTURESCALING_HYBRID_BICUBIC);
301
TranslateMenuItem(menu, ID_TEXTURESCALING_DEPOSTERIZE);
302
TranslateMenuItem(menu, ID_OPTIONS_HARDWARETRANSFORM);
303
TranslateMenuItem(menu, ID_EMULATION_SOUND);
304
TranslateMenuItem(menu, ID_EMULATION_CHEATS, g_Config.bSystemControls ? L"\tCtrl+T" : L"");
305
TranslateMenuItem(menu, ID_EMULATION_CHAT, g_Config.bSystemControls ? L"\tCtrl+C" : L"");
306
307
// Help menu: it's translated in CreateHelpMenu.
308
CreateHelpMenu(menu);
309
}
310
311
void TranslateMenus(HWND hWnd, HMENU menu) {
312
bool changed = false;
313
314
const std::string curLanguageID = g_i18nrepo.LanguageID();
315
if (curLanguageID != menuLanguageID || KeyMap::HasChanged(menuKeymapGeneration)) {
316
DoTranslateMenus(hWnd, menu);
317
menuLanguageID = curLanguageID;
318
changed = true;
319
}
320
321
if (changed) {
322
DrawMenuBar(hWnd);
323
}
324
}
325
326
void BrowseAndBootDone(std::string filename);
327
328
void BrowseAndBoot(RequesterToken token, std::string defaultPath, bool browseDirectory) {
329
browsePauseAfter = false;
330
if (GetUIState() == UISTATE_INGAME) {
331
browsePauseAfter = Core_IsStepping();
332
if (!browsePauseAfter)
333
Core_EnableStepping(true, "ui.boot", 0);
334
}
335
auto mm = GetI18NCategory(I18NCat::MAINMENU);
336
337
W32Util::MakeTopMost(GetHWND(), false);
338
339
if (browseDirectory) {
340
System_BrowseForFolder(token, mm->T("Load"), Path(), [](const std::string &value, int) {
341
BrowseAndBootDone(value);
342
});
343
} else {
344
System_BrowseForFile(token, mm->T("Load"), BrowseFileType::BOOTABLE, [](const std::string &value, int) {
345
BrowseAndBootDone(value);
346
});
347
}
348
}
349
350
void BrowseAndBootDone(std::string filename) {
351
if (GetUIState() == UISTATE_INGAME || GetUIState() == UISTATE_EXCEPTION || GetUIState() == UISTATE_PAUSEMENU) {
352
Core_EnableStepping(false);
353
}
354
filename = ReplaceAll(filename, "\\", "/");
355
System_PostUIMessage(UIMessage::REQUEST_GAME_BOOT, filename);
356
W32Util::MakeTopMost(GetHWND(), g_Config.bTopMost);
357
}
358
359
static void UmdSwitchAction(RequesterToken token) {
360
auto mm = GetI18NCategory(I18NCat::MAINMENU);
361
System_BrowseForFile(token, mm->T("Switch UMD"), BrowseFileType::BOOTABLE, [](const std::string &value, int) {
362
__UmdReplace(Path(value));
363
});
364
}
365
366
static void SaveStateActionFinished(SaveState::Status status, std::string_view message, void *userdata) {
367
if (!message.empty() && (!g_Config.bDumpFrames || !g_Config.bDumpVideoOutput)) {
368
g_OSD.Show(status == SaveState::Status::SUCCESS ? OSDType::MESSAGE_SUCCESS : OSDType::MESSAGE_ERROR, message, status == SaveState::Status::SUCCESS ? 2.0 : 5.0);
369
}
370
PostMessage(MainWindow::GetHWND(), WM_USER_SAVESTATE_FINISH, 0, 0);
371
}
372
373
// not static
374
void setTexScalingMultiplier(int level) {
375
g_Config.iTexScalingLevel = level;
376
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
377
}
378
379
static void setTexScalingType(int type) {
380
g_Config.iTexScalingType = type;
381
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
382
}
383
384
static void setSkipBufferEffects(bool skip) {
385
g_Config.bSkipBufferEffects = skip;
386
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
387
}
388
389
static void setFrameSkipping(int framesToSkip = -1) {
390
if (framesToSkip >= FRAMESKIP_OFF)
391
g_Config.iFrameSkip = framesToSkip;
392
else {
393
if (++g_Config.iFrameSkip > FRAMESKIP_MAX)
394
g_Config.iFrameSkip = FRAMESKIP_OFF;
395
}
396
397
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
398
399
std::ostringstream messageStream;
400
messageStream << gr->T("Frame Skipping") << ":" << " ";
401
402
if (g_Config.iFrameSkip == FRAMESKIP_OFF)
403
messageStream << gr->T("Off");
404
else
405
messageStream << g_Config.iFrameSkip;
406
407
g_OSD.Show(OSDType::MESSAGE_INFO, messageStream.str());
408
}
409
410
static void setFrameSkippingType(int fskipType = -1) {
411
if (fskipType >= 0 && fskipType <= 1) {
412
g_Config.iFrameSkipType = fskipType;
413
} else {
414
g_Config.iFrameSkipType = 0;
415
}
416
417
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
418
419
std::ostringstream messageStream;
420
messageStream << gr->T("Frame Skipping Type") << ":" << " ";
421
422
if (g_Config.iFrameSkipType == 0)
423
messageStream << gr->T("Number of Frames");
424
else
425
messageStream << gr->T("Percent of FPS");
426
427
g_OSD.Show(OSDType::MESSAGE_INFO, messageStream.str());
428
}
429
430
static void RestartApp() {
431
if (System_GetPropertyBool(SYSPROP_DEBUGGER_PRESENT)) {
432
PostMessage(MainWindow::GetHWND(), WM_USER_RESTART_EMUTHREAD, 0, 0);
433
} else {
434
g_Config.bRestartRequired = true;
435
PostMessage(MainWindow::GetHWND(), WM_CLOSE, 0, 0);
436
}
437
}
438
439
void MainWindowMenu_Process(HWND hWnd, WPARAM wParam) {
440
std::string fn;
441
442
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
443
444
int wmId = LOWORD(wParam);
445
// Parse the menu selections:
446
switch (wmId) {
447
case ID_FILE_LOAD:
448
BrowseAndBoot(NON_EPHEMERAL_TOKEN, "", false);
449
break;
450
451
case ID_FILE_LOAD_DIR:
452
BrowseAndBoot(NON_EPHEMERAL_TOKEN, "", true);
453
break;
454
455
case ID_FILE_LOAD_MEMSTICK:
456
BrowseAndBoot(NON_EPHEMERAL_TOKEN, GetSysDirectory(DIRECTORY_GAME).ToString());
457
break;
458
459
case ID_FILE_OPEN_NEW_INSTANCE:
460
W32Util::SpawnNewInstance(false);
461
break;
462
463
case ID_FILE_MEMSTICK:
464
ShellExecute(NULL, L"open", g_Config.memStickDirectory.ToWString().c_str(), 0, 0, SW_SHOWNORMAL);
465
break;
466
467
case ID_TOGGLE_BREAK:
468
if (GetUIState() == UISTATE_PAUSEMENU) {
469
// Causes hang (outdated comment?)
470
// System_PostUIMessage(UIMessage::REQUEST_GAME_RUN, "");
471
472
if (disasmWindow)
473
SendMessage(disasmWindow->GetDlgHandle(), WM_COMMAND, IDC_STOPGO, 0);
474
} else if (Core_IsStepping()) { // It is paused, then continue to run.
475
if (disasmWindow)
476
SendMessage(disasmWindow->GetDlgHandle(), WM_COMMAND, IDC_STOPGO, 0);
477
else
478
Core_EnableStepping(false);
479
} else {
480
if (disasmWindow)
481
SendMessage(disasmWindow->GetDlgHandle(), WM_COMMAND, IDC_STOPGO, 0);
482
else
483
Core_EnableStepping(true, "ui.break", 0);
484
}
485
noFocusPause = !noFocusPause; // If we pause, override pause on lost focus
486
break;
487
488
case ID_EMULATION_PAUSE:
489
System_PostUIMessage(UIMessage::REQUEST_GAME_PAUSE);
490
break;
491
492
case ID_EMULATION_STOP:
493
if (Core_IsStepping())
494
Core_EnableStepping(false);
495
496
Core_Stop();
497
System_PostUIMessage(UIMessage::REQUEST_GAME_STOP);
498
Core_WaitInactive();
499
break;
500
501
case ID_EMULATION_RESET:
502
System_PostUIMessage(UIMessage::REQUEST_GAME_RESET);
503
Core_EnableStepping(false);
504
break;
505
506
case ID_EMULATION_SWITCH_UMD:
507
UmdSwitchAction(NON_EPHEMERAL_TOKEN);
508
break;
509
510
case ID_EMULATION_ROTATION_H: g_Config.iInternalScreenRotation = ROTATION_LOCKED_HORIZONTAL; break;
511
case ID_EMULATION_ROTATION_V: g_Config.iInternalScreenRotation = ROTATION_LOCKED_VERTICAL; break;
512
case ID_EMULATION_ROTATION_H_R: g_Config.iInternalScreenRotation = ROTATION_LOCKED_HORIZONTAL180; break;
513
case ID_EMULATION_ROTATION_V_R: g_Config.iInternalScreenRotation = ROTATION_LOCKED_VERTICAL180; break;
514
515
case ID_EMULATION_CHEATS:
516
g_Config.bEnableCheats = !g_Config.bEnableCheats;
517
g_OSD.ShowOnOff(gr->T("Cheats"), g_Config.bEnableCheats);
518
break;
519
520
case ID_EMULATION_CHAT:
521
if (GetUIState() == UISTATE_INGAME) {
522
System_PostUIMessage(UIMessage::SHOW_CHAT_SCREEN);
523
}
524
break;
525
case ID_FILE_LOADSTATEFILE:
526
if (!Achievements::WarnUserIfHardcoreModeActive(false)) {
527
if (W32Util::BrowseForFileName(true, hWnd, L"Load state", 0, L"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0", L"ppst", fn)) {
528
SetCursor(LoadCursor(0, IDC_WAIT));
529
SaveState::Load(Path(fn), -1, SaveStateActionFinished);
530
}
531
}
532
break;
533
case ID_FILE_SAVESTATEFILE:
534
if (!Achievements::WarnUserIfHardcoreModeActive(true)) {
535
if (W32Util::BrowseForFileName(false, hWnd, L"Save state", 0, L"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0", L"ppst", fn)) {
536
SetCursor(LoadCursor(0, IDC_WAIT));
537
SaveState::Save(Path(fn), -1, SaveStateActionFinished);
538
}
539
}
540
break;
541
542
case ID_FILE_SAVESTATE_NEXT_SLOT:
543
{
544
if (!Achievements::WarnUserIfHardcoreModeActive(true)) {
545
SaveState::NextSlot();
546
System_PostUIMessage(UIMessage::SAVESTATE_DISPLAY_SLOT);
547
}
548
break;
549
}
550
551
case ID_FILE_SAVESTATE_NEXT_SLOT_HC:
552
{
553
if (!Achievements::WarnUserIfHardcoreModeActive(true)) {
554
if (!KeyMap::PspButtonHasMappings(VIRTKEY_NEXT_SLOT)) {
555
SaveState::NextSlot();
556
System_PostUIMessage(UIMessage::SAVESTATE_DISPLAY_SLOT);
557
}
558
}
559
break;
560
}
561
562
case ID_FILE_SAVESTATE_SLOT_1:
563
case ID_FILE_SAVESTATE_SLOT_2:
564
case ID_FILE_SAVESTATE_SLOT_3:
565
case ID_FILE_SAVESTATE_SLOT_4:
566
case ID_FILE_SAVESTATE_SLOT_5:
567
if (!Achievements::WarnUserIfHardcoreModeActive(true)) {
568
g_Config.iCurrentStateSlot = wmId - ID_FILE_SAVESTATE_SLOT_1;
569
}
570
break;
571
572
case ID_FILE_QUICKLOADSTATE:
573
if (!Achievements::WarnUserIfHardcoreModeActive(false)) {
574
SetCursor(LoadCursor(0, IDC_WAIT));
575
SaveState::LoadSlot(PSP_CoreParameter().fileToStart, g_Config.iCurrentStateSlot, SaveStateActionFinished);
576
}
577
break;
578
579
case ID_FILE_QUICKLOADSTATE_HC:
580
{
581
if (!Achievements::WarnUserIfHardcoreModeActive(false)) {
582
if (!KeyMap::PspButtonHasMappings(VIRTKEY_LOAD_STATE)) {
583
SetCursor(LoadCursor(0, IDC_WAIT));
584
SaveState::LoadSlot(PSP_CoreParameter().fileToStart, g_Config.iCurrentStateSlot, SaveStateActionFinished);
585
}
586
}
587
break;
588
}
589
case ID_FILE_QUICKSAVESTATE:
590
{
591
if (!Achievements::WarnUserIfHardcoreModeActive(true)) {
592
SetCursor(LoadCursor(0, IDC_WAIT));
593
SaveState::SaveSlot(PSP_CoreParameter().fileToStart, g_Config.iCurrentStateSlot, SaveStateActionFinished);
594
}
595
break;
596
}
597
598
case ID_FILE_QUICKSAVESTATE_HC:
599
{
600
if (!Achievements::WarnUserIfHardcoreModeActive(true)) {
601
if (!KeyMap::PspButtonHasMappings(VIRTKEY_SAVE_STATE))
602
{
603
SetCursor(LoadCursor(0, IDC_WAIT));
604
SaveState::SaveSlot(PSP_CoreParameter().fileToStart, g_Config.iCurrentStateSlot, SaveStateActionFinished);
605
break;
606
}
607
}
608
break;
609
}
610
611
case ID_OPTIONS_LANGUAGE:
612
System_PostUIMessage(UIMessage::SHOW_LANGUAGE_SCREEN);
613
break;
614
615
case ID_OPTIONS_IGNOREWINKEY:
616
g_Config.bIgnoreWindowsKey = !g_Config.bIgnoreWindowsKey;
617
break;
618
619
case ID_OPTIONS_SCREENAUTO: SetInternalResolution(RESOLUTION_AUTO); break;
620
case ID_OPTIONS_SCREEN1X: SetInternalResolution(RESOLUTION_NATIVE); break;
621
case ID_OPTIONS_SCREEN2X: SetInternalResolution(RESOLUTION_2X); break;
622
case ID_OPTIONS_SCREEN3X: SetInternalResolution(RESOLUTION_3X); break;
623
case ID_OPTIONS_SCREEN4X: SetInternalResolution(RESOLUTION_4X); break;
624
case ID_OPTIONS_SCREEN5X: SetInternalResolution(RESOLUTION_5X); break;
625
case ID_OPTIONS_SCREEN6X: SetInternalResolution(RESOLUTION_6X); break;
626
case ID_OPTIONS_SCREEN7X: SetInternalResolution(RESOLUTION_7X); break;
627
case ID_OPTIONS_SCREEN8X: SetInternalResolution(RESOLUTION_8X); break;
628
case ID_OPTIONS_SCREEN9X: SetInternalResolution(RESOLUTION_9X); break;
629
case ID_OPTIONS_SCREEN10X: SetInternalResolution(RESOLUTION_MAX); break;
630
631
case ID_OPTIONS_WINDOW1X: SetWindowSize(1); break;
632
case ID_OPTIONS_WINDOW2X: SetWindowSize(2); break;
633
case ID_OPTIONS_WINDOW3X: SetWindowSize(3); break;
634
case ID_OPTIONS_WINDOW4X: SetWindowSize(4); break;
635
case ID_OPTIONS_WINDOW5X: SetWindowSize(5); break;
636
case ID_OPTIONS_WINDOW6X: SetWindowSize(6); break;
637
case ID_OPTIONS_WINDOW7X: SetWindowSize(7); break;
638
case ID_OPTIONS_WINDOW8X: SetWindowSize(8); break;
639
case ID_OPTIONS_WINDOW9X: SetWindowSize(9); break;
640
case ID_OPTIONS_WINDOW10X: SetWindowSize(10); break;
641
642
case ID_OPTIONS_RESOLUTIONDUMMY:
643
{
644
SetInternalResolution();
645
break;
646
}
647
648
case ID_OPTIONS_VSYNC:
649
g_Config.bVSync = !g_Config.bVSync;
650
NativeResized();
651
break;
652
653
case ID_OPTIONS_FRAMESKIP_AUTO:
654
g_Config.bAutoFrameSkip = !g_Config.bAutoFrameSkip;
655
if (g_Config.bAutoFrameSkip && g_Config.bSkipBufferEffects) {
656
g_Config.bSkipBufferEffects = false;
657
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
658
}
659
break;
660
661
case ID_TEXTURESCALING_OFF: setTexScalingMultiplier(TEXSCALING_OFF); break;
662
case ID_TEXTURESCALING_2X: setTexScalingMultiplier(TEXSCALING_2X); break;
663
case ID_TEXTURESCALING_3X: setTexScalingMultiplier(TEXSCALING_3X); break;
664
case ID_TEXTURESCALING_4X: setTexScalingMultiplier(TEXSCALING_4X); break;
665
case ID_TEXTURESCALING_5X: setTexScalingMultiplier(TEXSCALING_MAX); break;
666
667
case ID_TEXTURESCALING_XBRZ: setTexScalingType(TextureScalerCommon::XBRZ); break;
668
case ID_TEXTURESCALING_HYBRID: setTexScalingType(TextureScalerCommon::HYBRID); break;
669
case ID_TEXTURESCALING_BICUBIC: setTexScalingType(TextureScalerCommon::BICUBIC); break;
670
case ID_TEXTURESCALING_HYBRID_BICUBIC: setTexScalingType(TextureScalerCommon::HYBRID_BICUBIC); break;
671
672
case ID_TEXTURESCALING_DEPOSTERIZE:
673
g_Config.bTexDeposterize = !g_Config.bTexDeposterize;
674
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
675
break;
676
677
case ID_OPTIONS_DIRECT3D9:
678
g_Config.iGPUBackend = (int)GPUBackend::DIRECT3D9;
679
g_Config.Save("gpu_choice");
680
RestartApp();
681
break;
682
683
case ID_OPTIONS_DIRECT3D11:
684
g_Config.iGPUBackend = (int)GPUBackend::DIRECT3D11;
685
g_Config.Save("gpu_choice");
686
RestartApp();
687
break;
688
689
case ID_OPTIONS_OPENGL:
690
g_Config.iGPUBackend = (int)GPUBackend::OPENGL;
691
g_Config.Save("gpu_choice");
692
RestartApp();
693
break;
694
695
case ID_OPTIONS_VULKAN:
696
g_Config.iGPUBackend = (int)GPUBackend::VULKAN;
697
g_Config.Save("gpu_choice");
698
RestartApp();
699
break;
700
701
case ID_OPTIONS_SKIP_BUFFER_EFFECTS:
702
g_Config.bSkipBufferEffects = !g_Config.bSkipBufferEffects;
703
System_PostUIMessage(UIMessage::GPU_RENDER_RESIZED);
704
g_OSD.ShowOnOff(gr->T("Skip Buffer Effects"), g_Config.bSkipBufferEffects);
705
break;
706
707
case ID_DEBUG_SHOWDEBUGSTATISTICS:
708
// This is still useful as a shortcut to tell users to use.
709
// So let's fake the enum.
710
if ((DebugOverlay)g_Config.iDebugOverlay == DebugOverlay::DEBUG_STATS) {
711
g_Config.iDebugOverlay = (int)DebugOverlay::OFF;
712
} else {
713
g_Config.iDebugOverlay = (int)DebugOverlay::DEBUG_STATS;
714
}
715
System_PostUIMessage(UIMessage::REQUEST_CLEAR_JIT);
716
break;
717
718
case ID_OPTIONS_HARDWARETRANSFORM:
719
g_Config.bHardwareTransform = !g_Config.bHardwareTransform;
720
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
721
g_OSD.ShowOnOff(gr->T("Hardware Transform"), g_Config.bHardwareTransform);
722
break;
723
724
case ID_OPTIONS_DISPLAY_LAYOUT:
725
System_PostUIMessage(UIMessage::SHOW_DISPLAY_LAYOUT_EDITOR);
726
break;
727
728
729
case ID_OPTIONS_FRAMESKIP_0: setFrameSkipping(FRAMESKIP_OFF); break;
730
case ID_OPTIONS_FRAMESKIP_1: setFrameSkipping(FRAMESKIP_1); break;
731
case ID_OPTIONS_FRAMESKIP_2: setFrameSkipping(FRAMESKIP_2); break;
732
case ID_OPTIONS_FRAMESKIP_3: setFrameSkipping(FRAMESKIP_3); break;
733
case ID_OPTIONS_FRAMESKIP_4: setFrameSkipping(FRAMESKIP_4); break;
734
case ID_OPTIONS_FRAMESKIP_5: setFrameSkipping(FRAMESKIP_5); break;
735
case ID_OPTIONS_FRAMESKIP_6: setFrameSkipping(FRAMESKIP_6); break;
736
case ID_OPTIONS_FRAMESKIP_7: setFrameSkipping(FRAMESKIP_7); break;
737
case ID_OPTIONS_FRAMESKIP_8: setFrameSkipping(FRAMESKIP_MAX); break;
738
739
case ID_OPTIONS_FRAMESKIPTYPE_COUNT: setFrameSkippingType(FRAMESKIPTYPE_COUNT); break;
740
case ID_OPTIONS_FRAMESKIPTYPE_PRCNT: setFrameSkippingType(FRAMESKIPTYPE_PRCNT); break;
741
742
case ID_OPTIONS_FRAMESKIPDUMMY:
743
setFrameSkipping();
744
setFrameSkippingType();
745
break;
746
747
case ID_FILE_EXIT:
748
PostMessage(hWnd, WM_CLOSE, 0, 0);
749
break;
750
751
case ID_DEBUG_BREAKONLOAD:
752
g_Config.bAutoRun = !g_Config.bAutoRun;
753
break;
754
755
case ID_DEBUG_DUMPNEXTFRAME:
756
System_PostUIMessage(UIMessage::REQUEST_GPU_DUMP_NEXT_FRAME);
757
break;
758
759
case ID_DEBUG_LOADMAPFILE:
760
if (W32Util::BrowseForFileName(true, hWnd, L"Load .ppmap", 0, L"Maps\0*.ppmap\0All files\0*.*\0\0", L"ppmap", fn)) {
761
g_symbolMap->LoadSymbolMap(Path(fn));
762
NotifyDebuggerMapLoaded();
763
}
764
break;
765
766
case ID_DEBUG_SAVEMAPFILE:
767
if (W32Util::BrowseForFileName(false, hWnd, L"Save .ppmap", 0, L"Maps\0*.ppmap\0All files\0*.*\0\0", L"ppmap", fn))
768
g_symbolMap->SaveSymbolMap(Path(fn));
769
break;
770
771
case ID_DEBUG_LOADSYMFILE:
772
if (W32Util::BrowseForFileName(true, hWnd, L"Load .sym", 0, L"Symbols\0*.sym\0All files\0*.*\0\0", L"sym", fn)) {
773
g_symbolMap->LoadNocashSym(Path(fn));
774
NotifyDebuggerMapLoaded();
775
}
776
break;
777
778
case ID_DEBUG_SAVESYMFILE:
779
if (W32Util::BrowseForFileName(false, hWnd, L"Save .sym", 0, L"Symbols\0*.sym\0All files\0*.*\0\0", L"sym", fn))
780
g_symbolMap->SaveNocashSym(Path(fn));
781
break;
782
783
case ID_DEBUG_RESETSYMBOLTABLE:
784
g_symbolMap->Clear();
785
NotifyDebuggerMapLoaded();
786
break;
787
788
case ID_DEBUG_DISASSEMBLY:
789
CreateDisasmWindow();
790
if (disasmWindow)
791
disasmWindow->Show(true);
792
break;
793
794
case ID_DEBUG_GEDEBUGGER:
795
#if PPSSPP_API(ANY_GL)
796
CreateGeDebuggerWindow();
797
if (geDebuggerWindow)
798
geDebuggerWindow->Show(true);
799
#endif
800
break;
801
802
case ID_DEBUG_MEMORYVIEW:
803
CreateMemoryWindow();
804
if (memoryWindow)
805
memoryWindow->Show(true);
806
break;
807
808
case ID_DEBUG_MEMORYBASE:
809
{
810
W32Util::CopyTextToClipboard(hWnd, ConvertUTF8ToWString(StringFromFormat("%016llx", (uint64_t)(uintptr_t)Memory::base)));
811
break;
812
}
813
814
case ID_DEBUG_EXTRACTFILE:
815
{
816
std::string filename;
817
if (!InputBox_GetString(hInst, hWnd, L"Disc filename", filename, filename)) {
818
break;
819
}
820
821
const char *lastSlash = strrchr(filename.c_str(), '/');
822
if (lastSlash) {
823
fn = lastSlash + 1;
824
} else {
825
fn.clear();
826
}
827
828
PSPFileInfo info = pspFileSystem.GetFileInfo(filename);
829
if (!info.exists) {
830
MessageBox(hWnd, L"File does not exist.", L"Sorry", 0);
831
} else if (info.type == FILETYPE_DIRECTORY) {
832
MessageBox(hWnd, L"Cannot extract directories.", L"Sorry", 0);
833
} else if (W32Util::BrowseForFileName(false, hWnd, L"Save file as...", 0, L"All files\0*.*\0\0", L"", fn)) {
834
u32 handle = pspFileSystem.OpenFile(filename, FILEACCESS_READ, "");
835
// Note: len may be in blocks.
836
size_t len = pspFileSystem.SeekFile(handle, 0, FILEMOVE_END);
837
bool isBlockMode = pspFileSystem.DevType(handle) & PSPDevType::BLOCK;
838
839
FILE *fp = File::OpenCFile(Path(fn), "wb");
840
pspFileSystem.SeekFile(handle, 0, FILEMOVE_BEGIN);
841
u8 buffer[4096];
842
size_t bufferSize = isBlockMode ? sizeof(buffer) / 2048 : sizeof(buffer);
843
while (len > 0) {
844
// This is all in blocks, not bytes, if isBlockMode.
845
size_t remain = std::min(len, bufferSize);
846
size_t readSize = pspFileSystem.ReadFile(handle, buffer, remain);
847
if (readSize == 0)
848
break;
849
size_t bytes = isBlockMode ? readSize * 2048 : readSize;
850
fwrite(buffer, 1, bytes, fp);
851
len -= readSize;
852
}
853
pspFileSystem.CloseFile(handle);
854
fclose(fp);
855
}
856
}
857
break;
858
859
case ID_DEBUG_LOG:
860
LogManager::GetInstance()->GetConsoleListener()->Show(LogManager::GetInstance()->GetConsoleListener()->Hidden());
861
break;
862
863
case ID_DEBUG_IGNOREILLEGALREADS:
864
g_Config.bIgnoreBadMemAccess = !g_Config.bIgnoreBadMemAccess;
865
break;
866
867
case ID_OPTIONS_FULLSCREEN:
868
SendToggleFullscreen(!g_Config.UseFullScreen());
869
break;
870
871
case ID_OPTIONS_TEXTUREFILTERING_AUTO: g_Config.iTexFiltering = TEX_FILTER_AUTO; break;
872
case ID_OPTIONS_NEARESTFILTERING: g_Config.iTexFiltering = TEX_FILTER_FORCE_NEAREST; break;
873
case ID_OPTIONS_LINEARFILTERING: g_Config.iTexFiltering = TEX_FILTER_FORCE_LINEAR; break;
874
case ID_OPTIONS_AUTOMAXQUALITYFILTERING: g_Config.iTexFiltering = TEX_FILTER_AUTO_MAX_QUALITY; break;
875
876
case ID_OPTIONS_SMART2DTEXTUREFILTERING: g_Config.bSmart2DTexFiltering = !g_Config.bSmart2DTexFiltering; break;
877
878
case ID_OPTIONS_BUFLINEARFILTER: g_Config.iDisplayFilter = SCALE_LINEAR; break;
879
case ID_OPTIONS_BUFNEARESTFILTER: g_Config.iDisplayFilter = SCALE_NEAREST; break;
880
881
case ID_OPTIONS_TOPMOST:
882
g_Config.bTopMost = !g_Config.bTopMost;
883
W32Util::MakeTopMost(hWnd, g_Config.bTopMost);
884
break;
885
886
case ID_OPTIONS_PAUSE_FOCUS:
887
g_Config.bPauseOnLostFocus = !g_Config.bPauseOnLostFocus;
888
break;
889
890
case ID_OPTIONS_CONTROLS:
891
System_PostUIMessage(UIMessage::SHOW_CONTROL_MAPPING);
892
break;
893
894
case ID_OPTIONS_MORE_SETTINGS:
895
System_PostUIMessage(UIMessage::SHOW_SETTINGS);
896
break;
897
898
case ID_EMULATION_SOUND:
899
g_Config.bEnableSound = !g_Config.bEnableSound;
900
break;
901
902
case ID_HELP_OPENWEBSITE:
903
ShellExecute(NULL, L"open", L"https://www.ppsspp.org/", NULL, NULL, SW_SHOWNORMAL);
904
break;
905
906
case ID_HELP_BUYGOLD:
907
ShellExecute(NULL, L"open", L"https://www.ppsspp.org/buygold", NULL, NULL, SW_SHOWNORMAL);
908
break;
909
910
case ID_HELP_OPENFORUM:
911
ShellExecute(NULL, L"open", L"https://forums.ppsspp.org/", NULL, NULL, SW_SHOWNORMAL);
912
break;
913
914
case ID_HELP_GITHUB:
915
ShellExecute(NULL, L"open", L"https://github.com/hrydgard/ppsspp/", NULL, NULL, SW_SHOWNORMAL);
916
break;
917
918
case ID_HELP_DISCORD:
919
ShellExecute(NULL, L"open", L"https://discord.gg/5NJB6dD", NULL, NULL, SW_SHOWNORMAL);
920
break;
921
922
case ID_HELP_ABOUT:
923
DialogManager::EnableAll(FALSE);
924
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)AboutDlgProc);
925
DialogManager::EnableAll(TRUE);
926
break;
927
928
case ID_DEBUG_TAKESCREENSHOT:
929
g_TakeScreenshot = true;
930
break;
931
932
case ID_DEBUG_RESTARTGRAPHICS:
933
System_PostUIMessage(UIMessage::RESTART_GRAPHICS);
934
break;
935
936
case ID_FILE_DUMPFRAMES:
937
g_Config.bDumpFrames = !g_Config.bDumpFrames;
938
break;
939
940
case ID_FILE_USEFFV1:
941
g_Config.bUseFFV1 = !g_Config.bUseFFV1;
942
break;
943
944
case ID_FILE_DUMP_VIDEO_OUTPUT:
945
g_Config.bDumpVideoOutput = !g_Config.bDumpVideoOutput;
946
break;
947
948
case ID_FILE_DUMPAUDIO:
949
g_Config.bDumpAudio = !g_Config.bDumpAudio;
950
break;
951
952
default:
953
#ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION
954
if (rc_client_raintegration_activate_menu_item(Achievements::GetClient(), LOWORD(wParam))) {
955
break;
956
}
957
#endif
958
MessageBox(hWnd, L"Unhandled menu item", L"Sorry", 0);
959
break;
960
}
961
}
962
963
void UpdateMenus(bool isMenuSelect) {
964
if (isMenuSelect) {
965
menuShaderInfoLoaded = false;
966
}
967
968
HMENU menu = GetMenu(GetHWND());
969
#define CHECKITEM(item,value) CheckMenuItem(menu,item,MF_BYCOMMAND | ((value) ? MF_CHECKED : MF_UNCHECKED));
970
CHECKITEM(ID_DEBUG_IGNOREILLEGALREADS, g_Config.bIgnoreBadMemAccess);
971
CHECKITEM(ID_DEBUG_SHOWDEBUGSTATISTICS, (DebugOverlay)g_Config.iDebugOverlay == DebugOverlay::DEBUG_STATS);
972
CHECKITEM(ID_OPTIONS_HARDWARETRANSFORM, g_Config.bHardwareTransform);
973
CHECKITEM(ID_DEBUG_BREAKONLOAD, !g_Config.bAutoRun);
974
CHECKITEM(ID_OPTIONS_FRAMESKIP_AUTO, g_Config.bAutoFrameSkip);
975
CHECKITEM(ID_OPTIONS_FRAMESKIP, g_Config.iFrameSkip != FRAMESKIP_OFF);
976
CHECKITEM(ID_OPTIONS_FRAMESKIPTYPE_COUNT, g_Config.iFrameSkipType == FRAMESKIPTYPE_COUNT);
977
CHECKITEM(ID_OPTIONS_FRAMESKIPTYPE_PRCNT, g_Config.iFrameSkipType == FRAMESKIPTYPE_PRCNT);
978
CHECKITEM(ID_OPTIONS_VSYNC, g_Config.bVSync);
979
CHECKITEM(ID_OPTIONS_TOPMOST, g_Config.bTopMost);
980
CHECKITEM(ID_OPTIONS_PAUSE_FOCUS, g_Config.bPauseOnLostFocus);
981
CHECKITEM(ID_OPTIONS_SMART2DTEXTUREFILTERING, g_Config.bSmart2DTexFiltering);
982
CHECKITEM(ID_EMULATION_SOUND, g_Config.bEnableSound);
983
CHECKITEM(ID_TEXTURESCALING_DEPOSTERIZE, g_Config.bTexDeposterize);
984
CHECKITEM(ID_EMULATION_CHEATS, g_Config.bEnableCheats);
985
CHECKITEM(ID_OPTIONS_IGNOREWINKEY, g_Config.bIgnoreWindowsKey);
986
CHECKITEM(ID_FILE_DUMPFRAMES, g_Config.bDumpFrames);
987
CHECKITEM(ID_FILE_USEFFV1, g_Config.bUseFFV1);
988
CHECKITEM(ID_FILE_DUMP_VIDEO_OUTPUT, g_Config.bDumpVideoOutput);
989
CHECKITEM(ID_FILE_DUMPAUDIO, g_Config.bDumpAudio);
990
CHECKITEM(ID_OPTIONS_SKIP_BUFFER_EFFECTS, g_Config.bSkipBufferEffects);
991
992
static const int displayrotationitems[] = {
993
ID_EMULATION_ROTATION_H,
994
ID_EMULATION_ROTATION_V,
995
ID_EMULATION_ROTATION_H_R,
996
ID_EMULATION_ROTATION_V_R
997
};
998
if (g_Config.iInternalScreenRotation < ROTATION_LOCKED_HORIZONTAL)
999
g_Config.iInternalScreenRotation = ROTATION_LOCKED_HORIZONTAL;
1000
1001
else if (g_Config.iInternalScreenRotation > ROTATION_LOCKED_VERTICAL180)
1002
g_Config.iInternalScreenRotation = ROTATION_LOCKED_VERTICAL180;
1003
1004
for (int i = 0; i < ARRAY_SIZE(displayrotationitems); i++) {
1005
CheckMenuItem(menu, displayrotationitems[i], MF_BYCOMMAND | ((i + 1) == g_Config.iInternalScreenRotation ? MF_CHECKED : MF_UNCHECKED));
1006
}
1007
1008
static const int zoomitems[11] = {
1009
ID_OPTIONS_SCREENAUTO,
1010
ID_OPTIONS_SCREEN1X,
1011
ID_OPTIONS_SCREEN2X,
1012
ID_OPTIONS_SCREEN3X,
1013
ID_OPTIONS_SCREEN4X,
1014
ID_OPTIONS_SCREEN5X,
1015
ID_OPTIONS_SCREEN6X,
1016
ID_OPTIONS_SCREEN7X,
1017
ID_OPTIONS_SCREEN8X,
1018
ID_OPTIONS_SCREEN9X,
1019
ID_OPTIONS_SCREEN10X,
1020
};
1021
if (g_Config.iInternalResolution < RESOLUTION_AUTO)
1022
g_Config.iInternalResolution = RESOLUTION_AUTO;
1023
1024
else if (g_Config.iInternalResolution > RESOLUTION_MAX)
1025
g_Config.iInternalResolution = RESOLUTION_MAX;
1026
1027
for (int i = 0; i < ARRAY_SIZE(zoomitems); i++) {
1028
CheckMenuItem(menu, zoomitems[i], MF_BYCOMMAND | ((i == g_Config.iInternalResolution) ? MF_CHECKED : MF_UNCHECKED));
1029
}
1030
1031
static const int windowSizeItems[10] = {
1032
ID_OPTIONS_WINDOW1X,
1033
ID_OPTIONS_WINDOW2X,
1034
ID_OPTIONS_WINDOW3X,
1035
ID_OPTIONS_WINDOW4X,
1036
ID_OPTIONS_WINDOW5X,
1037
ID_OPTIONS_WINDOW6X,
1038
ID_OPTIONS_WINDOW7X,
1039
ID_OPTIONS_WINDOW8X,
1040
ID_OPTIONS_WINDOW9X,
1041
ID_OPTIONS_WINDOW10X,
1042
};
1043
1044
RECT rc;
1045
GetClientRect(GetHWND(), &rc);
1046
1047
int checkW = g_Config.IsPortrait() ? 272 : 480;
1048
int checkH = g_Config.IsPortrait() ? 480 : 272;
1049
1050
for (int i = 0; i < ARRAY_SIZE(windowSizeItems); i++) {
1051
bool check = (i + 1) * checkW == rc.right - rc.left || (i + 1) * checkH == rc.bottom - rc.top;
1052
CheckMenuItem(menu, windowSizeItems[i], MF_BYCOMMAND | (check ? MF_CHECKED : MF_UNCHECKED));
1053
}
1054
1055
static const int texscalingitems[] = {
1056
ID_TEXTURESCALING_OFF,
1057
ID_TEXTURESCALING_2X,
1058
ID_TEXTURESCALING_3X,
1059
ID_TEXTURESCALING_4X,
1060
ID_TEXTURESCALING_5X,
1061
};
1062
if (g_Config.iTexScalingLevel < TEXSCALING_OFF)
1063
g_Config.iTexScalingLevel = TEXSCALING_OFF;
1064
1065
else if (g_Config.iTexScalingLevel > TEXSCALING_MAX)
1066
g_Config.iTexScalingLevel = TEXSCALING_MAX;
1067
1068
for (int i = 0; i < ARRAY_SIZE(texscalingitems); i++) {
1069
// OFF is 1, skip 0.
1070
bool selected = i + 1 == g_Config.iTexScalingLevel;
1071
CheckMenuItem(menu, texscalingitems[i], MF_BYCOMMAND | (selected ? MF_CHECKED : MF_UNCHECKED));
1072
}
1073
1074
if (g_Config.iGPUBackend == (int)GPUBackend::OPENGL && !gl_extensions.OES_texture_npot) {
1075
EnableMenuItem(menu, ID_TEXTURESCALING_3X, MF_GRAYED);
1076
EnableMenuItem(menu, ID_TEXTURESCALING_5X, MF_GRAYED);
1077
} else {
1078
EnableMenuItem(menu, ID_TEXTURESCALING_3X, MF_ENABLED);
1079
EnableMenuItem(menu, ID_TEXTURESCALING_5X, MF_ENABLED);
1080
}
1081
1082
static const int texscalingtypeitems[] = {
1083
ID_TEXTURESCALING_XBRZ,
1084
ID_TEXTURESCALING_HYBRID,
1085
ID_TEXTURESCALING_BICUBIC,
1086
ID_TEXTURESCALING_HYBRID_BICUBIC,
1087
};
1088
if (g_Config.iTexScalingType < TextureScalerCommon::XBRZ)
1089
g_Config.iTexScalingType = TextureScalerCommon::XBRZ;
1090
1091
else if (g_Config.iTexScalingType > TextureScalerCommon::HYBRID_BICUBIC)
1092
g_Config.iTexScalingType = TextureScalerCommon::HYBRID_BICUBIC;
1093
1094
for (int i = 0; i < ARRAY_SIZE(texscalingtypeitems); i++) {
1095
CheckMenuItem(menu, texscalingtypeitems[i], MF_BYCOMMAND | ((i == g_Config.iTexScalingType) ? MF_CHECKED : MF_UNCHECKED));
1096
}
1097
1098
static const int texfilteringitems[] = {
1099
ID_OPTIONS_TEXTUREFILTERING_AUTO,
1100
ID_OPTIONS_NEARESTFILTERING,
1101
ID_OPTIONS_LINEARFILTERING,
1102
ID_OPTIONS_AUTOMAXQUALITYFILTERING,
1103
};
1104
if (g_Config.iTexFiltering < TEX_FILTER_AUTO)
1105
g_Config.iTexFiltering = TEX_FILTER_AUTO;
1106
else if (g_Config.iTexFiltering > TEX_FILTER_AUTO_MAX_QUALITY)
1107
g_Config.iTexFiltering = TEX_FILTER_AUTO_MAX_QUALITY;
1108
1109
for (int i = 0; i < ARRAY_SIZE(texfilteringitems); i++) {
1110
CheckMenuItem(menu, texfilteringitems[i], MF_BYCOMMAND | ((i + 1) == g_Config.iTexFiltering ? MF_CHECKED : MF_UNCHECKED));
1111
}
1112
1113
static const int bufferfilteritems[] = {
1114
ID_OPTIONS_BUFLINEARFILTER,
1115
ID_OPTIONS_BUFNEARESTFILTER,
1116
};
1117
if (g_Config.iDisplayFilter < SCALE_LINEAR)
1118
g_Config.iDisplayFilter = SCALE_LINEAR;
1119
1120
else if (g_Config.iDisplayFilter > SCALE_NEAREST)
1121
g_Config.iDisplayFilter = SCALE_NEAREST;
1122
1123
for (int i = 0; i < ARRAY_SIZE(bufferfilteritems); i++) {
1124
CheckMenuItem(menu, bufferfilteritems[i], MF_BYCOMMAND | ((i + 1) == g_Config.iDisplayFilter ? MF_CHECKED : MF_UNCHECKED));
1125
}
1126
1127
static const int frameskipping[] = {
1128
ID_OPTIONS_FRAMESKIP_0,
1129
ID_OPTIONS_FRAMESKIP_1,
1130
ID_OPTIONS_FRAMESKIP_2,
1131
ID_OPTIONS_FRAMESKIP_3,
1132
ID_OPTIONS_FRAMESKIP_4,
1133
ID_OPTIONS_FRAMESKIP_5,
1134
ID_OPTIONS_FRAMESKIP_6,
1135
ID_OPTIONS_FRAMESKIP_7,
1136
ID_OPTIONS_FRAMESKIP_8,
1137
};
1138
1139
static const int frameskippingType[] = {
1140
ID_OPTIONS_FRAMESKIPTYPE_COUNT,
1141
ID_OPTIONS_FRAMESKIPTYPE_PRCNT,
1142
};
1143
1144
if (g_Config.iFrameSkip < FRAMESKIP_OFF)
1145
g_Config.iFrameSkip = FRAMESKIP_OFF;
1146
1147
else if (g_Config.iFrameSkip > FRAMESKIP_MAX)
1148
g_Config.iFrameSkip = FRAMESKIP_MAX;
1149
1150
for (int i = 0; i < ARRAY_SIZE(frameskipping); i++) {
1151
CheckMenuItem(menu, frameskipping[i], MF_BYCOMMAND | ((i == g_Config.iFrameSkip) ? MF_CHECKED : MF_UNCHECKED));
1152
}
1153
1154
for (int i = 0; i < ARRAY_SIZE(frameskippingType); i++) {
1155
CheckMenuItem(menu, frameskippingType[i], MF_BYCOMMAND | ((i == g_Config.iFrameSkipType) ? MF_CHECKED : MF_UNCHECKED));
1156
}
1157
1158
static const int savestateSlot[] = {
1159
ID_FILE_SAVESTATE_SLOT_1,
1160
ID_FILE_SAVESTATE_SLOT_2,
1161
ID_FILE_SAVESTATE_SLOT_3,
1162
ID_FILE_SAVESTATE_SLOT_4,
1163
ID_FILE_SAVESTATE_SLOT_5,
1164
};
1165
1166
if (g_Config.iCurrentStateSlot < 0)
1167
g_Config.iCurrentStateSlot = 0;
1168
1169
else if (g_Config.iCurrentStateSlot >= SaveState::NUM_SLOTS)
1170
g_Config.iCurrentStateSlot = SaveState::NUM_SLOTS - 1;
1171
1172
for (int i = 0; i < ARRAY_SIZE(savestateSlot); i++) {
1173
CheckMenuItem(menu, savestateSlot[i], MF_BYCOMMAND | ((i == g_Config.iCurrentStateSlot) ? MF_CHECKED : MF_UNCHECKED));
1174
}
1175
1176
bool allowD3D9 = g_Config.IsBackendEnabled(GPUBackend::DIRECT3D9);
1177
bool allowD3D11 = g_Config.IsBackendEnabled(GPUBackend::DIRECT3D11);
1178
bool allowOpenGL = g_Config.IsBackendEnabled(GPUBackend::OPENGL);
1179
bool allowVulkan = g_Config.IsBackendEnabled(GPUBackend::VULKAN);
1180
1181
switch (GetGPUBackend()) {
1182
case GPUBackend::DIRECT3D9:
1183
EnableMenuItem(menu, ID_OPTIONS_DIRECT3D9, MF_GRAYED);
1184
EnableMenuItem(menu, ID_OPTIONS_DIRECT3D11, allowD3D11 ? MF_ENABLED : MF_GRAYED);
1185
EnableMenuItem(menu, ID_OPTIONS_OPENGL, allowOpenGL ? MF_ENABLED : MF_GRAYED);
1186
EnableMenuItem(menu, ID_OPTIONS_VULKAN, allowVulkan ? MF_ENABLED : MF_GRAYED);
1187
CheckMenuItem(menu, ID_OPTIONS_DIRECT3D9, MF_CHECKED);
1188
CheckMenuItem(menu, ID_OPTIONS_DIRECT3D11, MF_UNCHECKED);
1189
CheckMenuItem(menu, ID_OPTIONS_OPENGL, MF_UNCHECKED);
1190
CheckMenuItem(menu, ID_OPTIONS_VULKAN, MF_UNCHECKED);
1191
break;
1192
case GPUBackend::OPENGL:
1193
EnableMenuItem(menu, ID_OPTIONS_DIRECT3D9, allowD3D9 ? MF_ENABLED : MF_GRAYED);
1194
EnableMenuItem(menu, ID_OPTIONS_DIRECT3D11, allowD3D11 ? MF_ENABLED : MF_GRAYED);
1195
EnableMenuItem(menu, ID_OPTIONS_OPENGL, MF_GRAYED);
1196
EnableMenuItem(menu, ID_OPTIONS_VULKAN, allowVulkan ? MF_ENABLED : MF_GRAYED);
1197
CheckMenuItem(menu, ID_OPTIONS_DIRECT3D9, MF_UNCHECKED);
1198
CheckMenuItem(menu, ID_OPTIONS_DIRECT3D11, MF_UNCHECKED);
1199
CheckMenuItem(menu, ID_OPTIONS_OPENGL, MF_CHECKED);
1200
CheckMenuItem(menu, ID_OPTIONS_VULKAN, MF_UNCHECKED);
1201
break;
1202
case GPUBackend::VULKAN:
1203
EnableMenuItem(menu, ID_OPTIONS_DIRECT3D9, allowD3D9 ? MF_ENABLED : MF_GRAYED);
1204
EnableMenuItem(menu, ID_OPTIONS_DIRECT3D11, allowD3D11 ? MF_ENABLED : MF_GRAYED);
1205
EnableMenuItem(menu, ID_OPTIONS_OPENGL, allowOpenGL ? MF_ENABLED : MF_GRAYED);
1206
EnableMenuItem(menu, ID_OPTIONS_VULKAN, MF_GRAYED);
1207
CheckMenuItem(menu, ID_OPTIONS_DIRECT3D9, MF_UNCHECKED);
1208
CheckMenuItem(menu, ID_OPTIONS_DIRECT3D11, MF_UNCHECKED);
1209
CheckMenuItem(menu, ID_OPTIONS_OPENGL, MF_UNCHECKED);
1210
CheckMenuItem(menu, ID_OPTIONS_VULKAN, MF_CHECKED);
1211
break;
1212
case GPUBackend::DIRECT3D11:
1213
EnableMenuItem(menu, ID_OPTIONS_DIRECT3D9, allowD3D9 ? MF_ENABLED : MF_GRAYED);
1214
EnableMenuItem(menu, ID_OPTIONS_DIRECT3D11, MF_GRAYED);
1215
EnableMenuItem(menu, ID_OPTIONS_OPENGL, allowOpenGL ? MF_ENABLED : MF_GRAYED);
1216
EnableMenuItem(menu, ID_OPTIONS_VULKAN, allowVulkan ? MF_ENABLED : MF_GRAYED);
1217
CheckMenuItem(menu, ID_OPTIONS_DIRECT3D9, MF_UNCHECKED);
1218
CheckMenuItem(menu, ID_OPTIONS_DIRECT3D11, MF_CHECKED);
1219
CheckMenuItem(menu, ID_OPTIONS_OPENGL, MF_UNCHECKED);
1220
CheckMenuItem(menu, ID_OPTIONS_VULKAN, MF_UNCHECKED);
1221
break;
1222
}
1223
1224
#if !PPSSPP_API(ANY_GL)
1225
EnableMenuItem(menu, ID_DEBUG_GEDEBUGGER, MF_GRAYED);
1226
#endif
1227
1228
UpdateCommands();
1229
}
1230
1231
void UpdateCommands() {
1232
static GlobalUIState lastGlobalUIState = UISTATE_PAUSEMENU;
1233
static CoreState lastCoreState = CORE_BOOT_ERROR;
1234
1235
HMENU menu = GetMenu(GetHWND());
1236
EnableMenuItem(menu, ID_DEBUG_LOG, g_Config.bEnableLogging ? MF_ENABLED : MF_GRAYED);
1237
SetIngameMenuItemStates(menu, GetUIState());
1238
1239
if (lastGlobalUIState == GetUIState() && lastCoreState == coreState)
1240
return;
1241
1242
lastCoreState = coreState;
1243
lastGlobalUIState = GetUIState();
1244
1245
bool isPaused = Core_IsStepping() && GetUIState() == UISTATE_INGAME;
1246
TranslateMenuItem(menu, ID_TOGGLE_BREAK, L"\tF8", isPaused ? "Run" : "Break");
1247
}
1248
1249
void UpdateSwitchUMD() {
1250
HMENU menu = GetMenu(GetHWND());
1251
GlobalUIState state = GetUIState();
1252
UINT umdSwitchEnable = state == UISTATE_INGAME && getUMDReplacePermit() ? MF_ENABLED : MF_GRAYED;
1253
EnableMenuItem(menu, ID_EMULATION_SWITCH_UMD, umdSwitchEnable);
1254
}
1255
1256
// Message handler for about box.
1257
LRESULT CALLBACK AboutDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
1258
switch (message) {
1259
case WM_INITDIALOG:
1260
{
1261
W32Util::CenterWindow(hDlg);
1262
HWND versionBox = GetDlgItem(hDlg, IDC_VERSION);
1263
std::string windowText = System_GetPropertyBool(SYSPROP_APP_GOLD) ? "PPSSPP Gold " : "PPSSPP ";
1264
windowText.append(PPSSPP_GIT_VERSION);
1265
SetWindowText(versionBox, ConvertUTF8ToWString(windowText).c_str());
1266
DarkModeInitDialog(hDlg);
1267
return TRUE;
1268
}
1269
1270
case WM_COMMAND:
1271
{
1272
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
1273
EndDialog(hDlg, LOWORD(wParam));
1274
return TRUE;
1275
}
1276
break;
1277
return FALSE;
1278
}
1279
1280
default:
1281
return DarkModeDlgProc(hDlg, message, wParam, lParam);
1282
}
1283
return FALSE;
1284
}
1285
}
1286
1287