ppsspp/Windows/WndMainWindow.cpp
Unknown W. Brackets ee86347610 Hide pop up windows in full screen.
Otherwise, they get in the way even though you can't see them.
2013-05-26 15:00:40 -07:00

1559 lines
46 KiB
C++

// NOTE: Apologies for the quality of this code, this is really from pre-opensource Dolphin - that is, 2003.
#include <windows.h>
#include <tchar.h>
#include "base/NativeApp.h"
#include "Globals.h"
#include "shellapi.h"
#include "commctrl.h"
#include "input/input_state.h"
#include "Core/Debugger/SymbolMap.h"
#include "Windows/OpenGLBase.h"
#include "Windows/Debugger/Debugger_Disasm.h"
#include "Windows/Debugger/Debugger_MemoryDlg.h"
#include "main.h"
#include "Core/Core.h"
#include "Core/MemMap.h"
#include "Core/SaveState.h"
#include "Core/System.h"
#include "Core/Config.h"
#include "Windows/EmuThread.h"
#include "resource.h"
#include "Windows/WndMainWindow.h"
#include "Common/LogManager.h"
#include "Common/ConsoleListener.h"
#include "Windows/W32Util/DialogManager.h"
#include "Windows/W32Util/ShellUtil.h"
#include "Windows/W32Util/Misc.h"
#include "GPU/GPUInterface.h"
#include "GPU/GPUState.h"
#include "native/image/png_load.h"
#include "GPU/GLES/TextureScaler.h"
#include "ControlMapping.h"
#include "UI/OnScreenDisplay.h"
#include "i18n/i18n.h"
#ifdef THEMES
#include "XPTheme.h"
#endif
#define ENABLE_TOUCH 0
BOOL g_bFullScreen = FALSE;
static RECT g_normalRC = {0};
extern InputState input_state;
extern const char * getVirtualKeyName(unsigned char key);
extern const char * getXinputButtonName(unsigned int button);
#define TIMER_CURSORUPDATE 1
#define CURSORUPDATE_INTERVAL_MS 50
namespace MainWindow
{
HWND hwndMain;
HWND hwndDisplay;
HWND hwndGameList;
static HMENU menu;
static HINSTANCE hInst;
static int cursorCounter = 0;
//W32Util::LayeredWindow *layer;
#define MAX_LOADSTRING 100
const TCHAR *szTitle = TEXT("PPSSPP");
const TCHAR *szWindowClass = TEXT("PPSSPPWnd");
const TCHAR *szDisplayClass = TEXT("PPSSPPDisplay");
// Forward declarations of functions included in this code module:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK DisplayProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK Controls(HWND, UINT, WPARAM, LPARAM);
HWND GetHWND()
{
return hwndMain;
}
HWND GetDisplayHWND()
{
return hwndDisplay;
}
void Init(HINSTANCE hInstance)
{
#ifdef THEMES
WTL::CTheme::IsThemingSupported();
#endif
//Register classes
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_PPSSPP);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wcex.lpszMenuName = (LPCSTR)IDR_MENU1;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = (HICON)LoadImage(hInstance, (LPCTSTR)IDI_PPSSPP, IMAGE_ICON, 16,16,LR_SHARED);
RegisterClassEx(&wcex);
wcex.style = CS_HREDRAW | CS_VREDRAW;;
wcex.lpfnWndProc = (WNDPROC)DisplayProc;
wcex.hIcon = 0;
wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wcex.lpszMenuName = 0;
wcex.lpszClassName = szDisplayClass;
wcex.hIconSm = 0;
RegisterClassEx(&wcex);
}
void GetWindowRectAtZoom(int zoom, RECT &rcInner, RECT &rcOuter) {
// GetWindowRect(hwndMain, &rcInner);
rcInner.left = 0;
rcInner.top = 0;
rcInner.right=480*zoom;//+client edge
rcInner.bottom=272*zoom; //+client edge
rcOuter=rcInner;
AdjustWindowRect(&rcOuter, WS_OVERLAPPEDWINDOW, TRUE);
rcOuter.right += g_Config.iWindowX - rcOuter.left;
rcOuter.bottom += g_Config.iWindowY - rcOuter.top;
rcOuter.left = g_Config.iWindowX;
rcOuter.top = g_Config.iWindowY;
}
void SavePosition() {
WINDOWPLACEMENT placement;
GetWindowPlacement(hwndMain, &placement);
if (placement.showCmd == SW_SHOWNORMAL) {
RECT rc;
GetWindowRect(hwndMain, &rc);
g_Config.iWindowX = rc.left;
g_Config.iWindowY = rc.top;
}
}
void ResizeDisplay(bool noWindowMovement = false) {
RECT rc;
GetClientRect(hwndMain, &rc);
if (!noWindowMovement) {
if ((rc.right - rc.left) == PSP_CoreParameter().pixelWidth &&
(rc.bottom - rc.top) == PSP_CoreParameter().pixelHeight)
return;
PSP_CoreParameter().pixelWidth = rc.right - rc.left;
PSP_CoreParameter().pixelHeight = rc.bottom - rc.top;
MoveWindow(hwndDisplay, 0, 0, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight, TRUE);
}
// round up to a zoom factor for the render size.
int zoom = (rc.right - rc.left + 479) / 480;
if (g_Config.SSAntiAliasing) zoom *= 2;
PSP_CoreParameter().renderWidth = 480 * zoom;
PSP_CoreParameter().renderHeight = 272 * zoom;
PSP_CoreParameter().outputWidth = 480 * zoom;
PSP_CoreParameter().outputHeight = 272 * zoom;
if (gpu)
gpu->Resized();
}
void SetZoom(float zoom) {
if (zoom < 5)
g_Config.iWindowZoom = (int) zoom;
RECT rc, rcOuter;
GetWindowRectAtZoom((int) zoom, rc, rcOuter);
MoveWindow(hwndMain, rcOuter.left, rcOuter.top, rcOuter.right - rcOuter.left, rcOuter.bottom - rcOuter.top, TRUE);
ResizeDisplay();
}
void CorrectCursor() {
if (g_bFullScreen && globalUIState == UISTATE_INGAME) {
while (cursorCounter >= 0) {
cursorCounter = ShowCursor(FALSE);
}
} else {
if (cursorCounter < 0) {
cursorCounter = ShowCursor(TRUE);
SetCursor(LoadCursor(NULL, IDC_ARROW));
}
}
}
void setTexScalingLevel(int num) {
g_Config.iTexScalingLevel = num;
if(gpu) gpu->ClearCacheNextFrame();
}
void setTexScalingType(int num) {
g_Config.iTexScalingType = num;
if(gpu) gpu->ClearCacheNextFrame();
}
void setFpsLimit(int fps) {
g_Config.iFpsLimit = fps;
}
BOOL Show(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
int zoom = g_Config.iWindowZoom;
if (zoom < 1) zoom = 1;
if (zoom > 4) zoom = 4;
RECT rc,rcOrig;
GetWindowRectAtZoom(zoom, rcOrig, rc);
u32 style = WS_OVERLAPPEDWINDOW;
hwndMain = CreateWindowEx(0,szWindowClass, "", style,
rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, NULL, NULL, hInstance, NULL);
SetTimer(hwndMain, TIMER_CURSORUPDATE, CURSORUPDATE_INTERVAL_MS, 0);
SetPlaying(0);
if (!hwndMain)
return FALSE;
menu = GetMenu(hwndMain);
#ifdef FINAL
RemoveMenu(menu,2,MF_BYPOSITION);
RemoveMenu(menu,2,MF_BYPOSITION);
#endif
MENUINFO info;
ZeroMemory(&info,sizeof(MENUINFO));
info.cbSize = sizeof(MENUINFO);
info.cyMax = 0;
info.dwStyle = MNS_CHECKORBMP;
info.fMask = MIM_STYLE;
for (int i = 0; i < GetMenuItemCount(menu); i++)
{
SetMenuInfo(GetSubMenu(menu,i),&info);
}
hwndDisplay = CreateWindowEx(0,szDisplayClass,TEXT(""),
WS_CHILD|WS_VISIBLE,
0,0,/*rcOrig.left,rcOrig.top,*/rcOrig.right-rcOrig.left,rcOrig.bottom-rcOrig.top,hwndMain,0,hInstance,0);
ShowWindow(hwndMain, nCmdShow);
//accept dragged files
DragAcceptFiles(hwndMain, TRUE);
#if ENABLE_TOUCH
RegisterTouchWindow(hwndDisplay, TWF_WANTPALM);
#endif
SetFocus(hwndMain);
SetFocus(hwndDisplay);
return TRUE;
}
void BrowseAndBoot(std::string defaultPath)
{
std::string fn;
std::string filter = "PSP ROMs (*.iso *.cso *.pbp *.elf)|*.pbp;*.elf;*.iso;*.cso;*.prx|All files (*.*)|*.*||";
for (int i=0; i<(int)filter.length(); i++)
{
if (filter[i] == '|')
filter[i] = '\0';
}
if (W32Util::BrowseForFileName(true, GetHWND(), "Load File", defaultPath.size() ? defaultPath.c_str() : 0, filter.c_str(),"*.pbp;*.elf;*.iso;*.cso;",fn))
{
// decode the filename with fullpath
std::string fullpath = fn;
char drive[MAX_PATH];
char dir[MAX_PATH];
char fname[MAX_PATH];
char ext[MAX_PATH];
_splitpath(fullpath.c_str(), drive, dir, fname, ext);
std::string executable = std::string(drive) + std::string(dir) + std::string(fname) + std::string(ext);
NativeMessageReceived("boot", executable.c_str());
}
}
LRESULT CALLBACK DisplayProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_ACTIVATE:
break;
case WM_SETFOCUS:
break;
case WM_SIZE:
break;
case WM_ERASEBKGND:
return DefWindowProc(hWnd, message, wParam, lParam);
case WM_LBUTTONDOWN:
{
lock_guard guard(input_state.lock);
input_state.mouse_valid = true;
input_state.pointer_down[0] = true;
input_state.pointer_x[0] = GET_X_LPARAM(lParam);
input_state.pointer_y[0] = GET_Y_LPARAM(lParam);
if (g_Config.iWindowZoom == 1)
{
input_state.pointer_x[0] *= 2;
input_state.pointer_y[0] *= 2;
}
}
break;
case WM_MOUSEMOVE:
{
lock_guard guard(input_state.lock);
input_state.pointer_x[0] = GET_X_LPARAM(lParam);
input_state.pointer_y[0] = GET_Y_LPARAM(lParam);
if (g_Config.iWindowZoom == 1)
{
input_state.pointer_x[0] *= 2;
input_state.pointer_y[0] *= 2;
}
}
break;
case WM_LBUTTONUP:
{
lock_guard guard(input_state.lock);
input_state.pointer_down[0] = false;
input_state.pointer_x[0] = GET_X_LPARAM(lParam);
input_state.pointer_y[0] = GET_Y_LPARAM(lParam);
if (g_Config.iWindowZoom == 1)
{
input_state.pointer_x[0] *= 2;
input_state.pointer_y[0] *= 2;
}
}
break;
case WM_TOUCH:
{
// TODO: Enabling this section will probably break things on Windows XP.
// We probably need to manually fetch pointers to GetTouchInputInfo and CloseTouchInputHandle.
#if ENABLE_TOUCH
UINT inputCount = LOWORD(wParam);
TOUCHINPUT *inputs = new TOUCHINPUT[inputCount];
if (GetTouchInputInfo((HTOUCHINPUT)lParam,
inputCount,
inputs,
sizeof(TOUCHINPUT)))
{
for (int i = 0; i < inputCount; i++) {
// TODO: process inputs here!
}
if (!CloseTouchInputHandle((HTOUCHINPUT)lParam))
{
// error handling
}
}
else
{
// GetLastError() and error handling
}
delete [] inputs;
return DefWindowProc(hWnd, message, wParam, lParam);
#endif
}
case WM_PAINT:
return DefWindowProc(hWnd, message, wParam, lParam);
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
std::string fn;
I18NCategory *g = GetI18NCategory("Graphics");
switch (message)
{
case WM_CREATE:
loadControlsFromFile();
break;
case WM_MOVE:
SavePosition();
ResizeDisplay();
break;
case WM_SIZE:
SavePosition();
ResizeDisplay();
break;
case WM_TIMER:
// Hack: Take the opportunity to also show/hide the mouse cursor in fullscreen mode.
CorrectCursor();
SetTimer(hWnd, TIMER_CURSORUPDATE, CURSORUPDATE_INTERVAL_MS, 0);
return 0;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case ID_FILE_LOAD:
BrowseAndBoot("");
break;
case ID_FILE_LOAD_MEMSTICK:
{
std::string memStickDir, flash0dir;
GetSysDirectories(memStickDir, flash0dir);
memStickDir += "PSP\\GAME\\";
BrowseAndBoot(memStickDir);
}
break;
case ID_FILE_REFRESHGAMELIST:
break;
case ID_FILE_MEMSTICK:
{
std::string memStickDir, flash0dir;
GetSysDirectories(memStickDir, flash0dir);
ShellExecuteA(NULL, "open", memStickDir.c_str(), 0, 0, SW_SHOW);
}
break;
case ID_EMULATION_RUN:
if (Core_IsStepping()) {
Core_EnableStepping(false);
} else {
NativeMessageReceived("run", "");
}
if (disasmWindow[0])
SendMessage(disasmWindow[0]->GetDlgHandle(), WM_COMMAND, IDC_GO, 0);
break;
case ID_EMULATION_STOP:
if (memoryWindow[0]) {
SendMessage(memoryWindow[0]->GetDlgHandle(), WM_CLOSE, 0, 0);
}
if (disasmWindow[0]) {
SendMessage(disasmWindow[0]->GetDlgHandle(), WM_CLOSE, 0, 0);
}
if (Core_IsStepping()) {
Core_EnableStepping(false);
}
NativeMessageReceived("stop", "");
SetPlaying(0);
Update();
break;
case ID_EMULATION_PAUSE:
if (disasmWindow[0])
{
SendMessage(disasmWindow[0]->GetDlgHandle(), WM_COMMAND, IDC_STOP, 0);
} else if (globalUIState == UISTATE_INGAME) {
Core_EnableStepping(true);
}
break;
case ID_EMULATION_RESET:
NativeMessageReceived("reset", "");
break;
case ID_EMULATION_SPEEDLIMIT:
g_Config.bSpeedLimit = !g_Config.bSpeedLimit;
break;
case ID_FILE_LOADSTATEFILE:
if (W32Util::BrowseForFileName(true, hWnd, "Load state",0,"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0","ppst",fn))
{
SetCursor(LoadCursor(0,IDC_WAIT));
SaveState::Load(fn, SaveStateActionFinished);
}
break;
case ID_FILE_SAVESTATEFILE:
if (W32Util::BrowseForFileName(false, hWnd, "Save state",0,"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0","ppst",fn))
{
SetCursor(LoadCursor(0,IDC_WAIT));
SaveState::Save(fn, SaveStateActionFinished);
}
break;
// TODO: Add UI for multiple slots
case ID_FILE_QUICKLOADSTATE:
SetCursor(LoadCursor(0,IDC_WAIT));
SaveState::LoadSlot(0, SaveStateActionFinished);
break;
case ID_FILE_QUICKSAVESTATE:
SetCursor(LoadCursor(0,IDC_WAIT));
SaveState::SaveSlot(0, SaveStateActionFinished);
break;
case ID_OPTIONS_SCREEN1X:
SetZoom(1);
break;
case ID_OPTIONS_SCREEN2X:
SetZoom(2);
break;
case ID_OPTIONS_SCREEN3X:
SetZoom(3);
break;
case ID_OPTIONS_SCREEN4X:
SetZoom(4);
break;
case ID_OPTIONS_MIPMAP:
g_Config.bMipMap = !g_Config.bMipMap;
break;
case ID_TEXTURESCALING_OFF:
setTexScalingLevel(1);
break;
case ID_TEXTURESCALING_2X:
setTexScalingLevel(2);
break;
case ID_TEXTURESCALING_3X:
setTexScalingLevel(3);
break;
case ID_TEXTURESCALING_4X:
setTexScalingLevel(4);
break;
case ID_TEXTURESCALING_5X:
setTexScalingLevel(5);
break;
case ID_TEXTURESCALING_XBRZ:
setTexScalingType(TextureScaler::XBRZ);
break;
case ID_TEXTURESCALING_HYBRID:
setTexScalingType(TextureScaler::HYBRID);
break;
case ID_TEXTURESCALING_BICUBIC:
setTexScalingType(TextureScaler::BICUBIC);
break;
case ID_TEXTURESCALING_HYBRID_BICUBIC:
setTexScalingType(TextureScaler::HYBRID_BICUBIC);
break;
case ID_TEXTURESCALING_DEPOSTERIZE:
g_Config.bTexDeposterize = !g_Config.bTexDeposterize;
if(gpu) gpu->ClearCacheNextFrame();
break;
case ID_OPTIONS_BUFFEREDRENDERING:
g_Config.bBufferedRendering = !g_Config.bBufferedRendering;
osm.ShowOnOff(g->T("Buffered Rendering"), g_Config.bBufferedRendering);
if (gpu)
gpu->Resized(); // easy way to force a clear...
break;
case ID_OPTIONS_SHOWDEBUGSTATISTICS:
g_Config.bShowDebugStats = !g_Config.bShowDebugStats;
break;
case ID_OPTIONS_HARDWARETRANSFORM:
g_Config.bHardwareTransform = !g_Config.bHardwareTransform;
osm.ShowOnOff(g->T("Hardware Transform"), g_Config.bHardwareTransform);
break;
case ID_OPTIONS_STRETCHDISPLAY:
g_Config.bStretchToDisplay = !g_Config.bStretchToDisplay;
if (gpu)
gpu->Resized(); // easy way to force a clear...
break;
case ID_OPTIONS_FRAMESKIP:
g_Config.iFrameSkip = g_Config.iFrameSkip == 0 ? 1 : 0;
osm.ShowOnOff(g->T("Frame Skipping"), g_Config.iFrameSkip != 0);
break;
case ID_OPTIONS_USEMEDIAENGINE:
g_Config.bUseMediaEngine = !g_Config.bUseMediaEngine;
osm.ShowOnOff(g->T("Media Engine"), g_Config.bUseMediaEngine);
break;
case ID_FILE_EXIT:
DestroyWindow(hWnd);
break;
case ID_CPU_DYNAREC:
g_Config.bJit = true;
osm.ShowOnOff(g->T("Dynarec", "Dynarec (JIT)"), g_Config.bJit);
break;
case ID_CPU_INTERPRETER:
g_Config.bJit = false;
break;
case ID_EMULATION_RUNONLOAD:
g_Config.bAutoRun = !g_Config.bAutoRun;
break;
case ID_DEBUG_DUMPNEXTFRAME:
if (gpu)
gpu->DumpNextFrame();
break;
case ID_DEBUG_LOADMAPFILE:
if (W32Util::BrowseForFileName(true, hWnd, "Load .MAP",0,"Maps\0*.map\0All files\0*.*\0\0","map",fn)) {
symbolMap.LoadSymbolMap(fn.c_str());
// HLE_PatchFunctions();
if (disasmWindow[0])
disasmWindow[0]->NotifyMapLoaded();
if (memoryWindow[0])
memoryWindow[0]->NotifyMapLoaded();
}
break;
case ID_DEBUG_SAVEMAPFILE:
if (W32Util::BrowseForFileName(false, hWnd, "Save .MAP",0,"Maps\0*.map\0All files\0*.*\0\0","map",fn))
symbolMap.SaveSymbolMap(fn.c_str());
break;
case ID_DEBUG_RESETSYMBOLTABLE:
symbolMap.ResetSymbolMap();
for (int i=0; i<numCPUs; i++)
if (disasmWindow[i])
disasmWindow[i]->NotifyMapLoaded();
for (int i=0; i<numCPUs; i++)
if (memoryWindow[i])
memoryWindow[i]->NotifyMapLoaded();
break;
case ID_DEBUG_DISASSEMBLY:
if (disasmWindow[0])
disasmWindow[0]->Show(true);
break;
case ID_DEBUG_MEMORYVIEW:
if (memoryWindow[0])
memoryWindow[0]->Show(true);
break;
case ID_DEBUG_LOG:
LogManager::GetInstance()->GetConsoleListener()->Show(LogManager::GetInstance()->GetConsoleListener()->Hidden());
break;
case ID_OPTIONS_IGNOREILLEGALREADS:
g_Config.bIgnoreBadMemAccess = !g_Config.bIgnoreBadMemAccess;
break;
case ID_OPTIONS_FULLSCREEN:
g_Config.bFullScreen = !g_Config.bFullScreen ;
if(g_bFullScreen) {
_ViewNormal(hWnd);
} else {
_ViewFullScreen(hWnd);
}
break;
case ID_OPTIONS_VERTEXCACHE:
g_Config.bVertexCache = !g_Config.bVertexCache;
break;
case ID_OPTIONS_SHOWFPS:
g_Config.bShowFPSCounter = !g_Config.bShowFPSCounter;
break;
case ID_OPTIONS_DISPLAYRAWFRAMEBUFFER:
g_Config.bDisplayFramebuffer = !g_Config.bDisplayFramebuffer;
break;
case ID_OPTIONS_FASTMEMORY:
g_Config.bFastMemory = !g_Config.bFastMemory;
break;
case ID_OPTIONS_USEVBO:
g_Config.bUseVBO = !g_Config.bUseVBO;
break;
case ID_OPTIONS_LINEARFILTERING:
g_Config.bLinearFiltering = !g_Config.bLinearFiltering;
break;
case ID_OPTIONS_SIMPLE2XSSAA:
g_Config.SSAntiAliasing = !g_Config.SSAntiAliasing;
ResizeDisplay(true);
break;
case ID_OPTIONS_CONTROLS:
DialogManager::EnableAll(FALSE);
DialogBox(hInst, (LPCTSTR)IDD_CONTROLS, hWnd, (DLGPROC)Controls);
DialogManager::EnableAll(TRUE);
break;
case ID_EMULATION_SOUND:
g_Config.bEnableSound = !g_Config.bEnableSound;
break;
case ID_HELP_OPENWEBSITE:
ShellExecute(NULL, "open", "http://www.ppsspp.org/", NULL, NULL, SW_SHOWNORMAL);
break;
case ID_HELP_ABOUT:
DialogManager::EnableAll(FALSE);
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
DialogManager::EnableAll(TRUE);
break;
default:
{
MessageBox(hwndMain,"Unimplemented","Sorry",0);
}
break;
}
break;
case WM_KEYDOWN:
return 0;
case WM_DROPFILES:
{
HDROP hdrop = (HDROP)wParam;
int count = DragQueryFile(hdrop,0xFFFFFFFF,0,0);
if (count != 1)
{
MessageBox(hwndMain,"You can only load one file at a time","Error",MB_ICONINFORMATION);
}
else
{
TCHAR filename[512];
DragQueryFile(hdrop,0,filename,512);
TCHAR *type = filename+_tcslen(filename)-3;
SendMessage(hWnd, WM_COMMAND, ID_EMULATION_STOP, 0);
// Ugly, need to wait for the stop message to process in the EmuThread.
Sleep(20);
MainWindow::SetPlaying(filename);
MainWindow::Update();
NativeMessageReceived("boot", filename);
}
}
break;
case WM_CLOSE:
Core_Stop();
Core_WaitInactive(200);
EmuThread_Stop();
/*
if (g_Config.bConfirmOnQuit && CCore::IsRunning())
{
if (IDNO==MessageBox(hwndMain,"A game is in progress. Are you sure you want to exit?","Are you sure?",MB_YESNO|MB_ICONQUESTION))
return 1;//or 1?
else
return DefWindowProc(hWnd,message,wParam,lParam);
break;
}
else
*/
return DefWindowProc(hWnd,message,wParam,lParam);
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_USER+1:
if (disasmWindow[0])
SendMessage(disasmWindow[0]->GetDlgHandle(), WM_CLOSE, 0, 0);
if (memoryWindow[0])
SendMessage(memoryWindow[0]->GetDlgHandle(), WM_CLOSE, 0, 0);
disasmWindow[0] = new CDisasm(MainWindow::GetHInstance(), MainWindow::GetHWND(), currentDebugMIPS);
DialogManager::AddDlg(disasmWindow[0]);
disasmWindow[0]->Show(g_Config.bShowDebuggerOnLoad);
if (g_Config.bFullScreen)
_ViewFullScreen(hWnd);
memoryWindow[0] = new CMemoryDlg(MainWindow::GetHInstance(), MainWindow::GetHWND(), currentDebugMIPS);
DialogManager::AddDlg(memoryWindow[0]);
if (disasmWindow[0])
disasmWindow[0]->NotifyMapLoaded();
if (memoryWindow[0])
memoryWindow[0]->NotifyMapLoaded();
SetForegroundWindow(hwndMain);
break;
case WM_MENUSELECT:
// Unfortunately, accelerate keys (hotkeys) shares the same enabled/disabled states
// with corresponding menu items.
UpdateMenus();
break;
// Turn off the screensaver.
// Note that if there's a screensaver password, this simple method
// doesn't work on Vista or higher.
case WM_SYSCOMMAND:
{
switch (wParam)
{
case SC_SCREENSAVE:
return 0;
case SC_MONITORPOWER:
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
void UpdateMenus()
{
HMENU menu = GetMenu(GetHWND());
#define CHECKITEM(item,value) CheckMenuItem(menu,item,MF_BYCOMMAND | ((value) ? MF_CHECKED : MF_UNCHECKED));
CHECKITEM(ID_EMULATION_SPEEDLIMIT,g_Config.bSpeedLimit);
// CHECK(ID_OPTIONS_ENABLEFRAMEBUFFER,g_Config.bEnableFrameBuffer);
// CHECK(ID_OPTIONS_EMULATESYSCALL,g_bEmulateSyscall);
CHECKITEM(ID_OPTIONS_DISPLAYRAWFRAMEBUFFER, g_Config.bDisplayFramebuffer);
CHECKITEM(ID_OPTIONS_IGNOREILLEGALREADS,g_Config.bIgnoreBadMemAccess);
CHECKITEM(ID_CPU_INTERPRETER,g_Config.bJit == false);
CHECKITEM(ID_CPU_DYNAREC,g_Config.bJit == true);
CHECKITEM(ID_OPTIONS_BUFFEREDRENDERING, g_Config.bBufferedRendering);
CHECKITEM(ID_OPTIONS_SHOWDEBUGSTATISTICS, g_Config.bShowDebugStats);
CHECKITEM(ID_OPTIONS_HARDWARETRANSFORM, g_Config.bHardwareTransform);
CHECKITEM(ID_OPTIONS_FASTMEMORY, g_Config.bFastMemory);
CHECKITEM(ID_OPTIONS_LINEARFILTERING, g_Config.bLinearFiltering);
CHECKITEM(ID_OPTIONS_SIMPLE2XSSAA, g_Config.SSAntiAliasing);
CHECKITEM(ID_OPTIONS_STRETCHDISPLAY, g_Config.bStretchToDisplay);
CHECKITEM(ID_EMULATION_RUNONLOAD, g_Config.bAutoRun);
CHECKITEM(ID_OPTIONS_USEVBO, g_Config.bUseVBO);
CHECKITEM(ID_OPTIONS_VERTEXCACHE, g_Config.bVertexCache);
CHECKITEM(ID_OPTIONS_SHOWFPS, g_Config.bShowFPSCounter);
CHECKITEM(ID_OPTIONS_FRAMESKIP, g_Config.iFrameSkip != 0);
CHECKITEM(ID_OPTIONS_USEMEDIAENGINE, g_Config.bUseMediaEngine);
CHECKITEM(ID_OPTIONS_MIPMAP, g_Config.bMipMap);
CHECKITEM(ID_EMULATION_SOUND, g_Config.bEnableSound);
CHECKITEM(ID_TEXTURESCALING_DEPOSTERIZE, g_Config.bTexDeposterize);
static const int zoomitems[4] = {
ID_OPTIONS_SCREEN1X,
ID_OPTIONS_SCREEN2X,
ID_OPTIONS_SCREEN3X,
ID_OPTIONS_SCREEN4X,
};
for (int i = 0; i < 4; i++) {
CheckMenuItem(menu, zoomitems[i], MF_BYCOMMAND | ((i == g_Config.iWindowZoom - 1) ? MF_CHECKED : MF_UNCHECKED));
}
static const int texscalingitems[] = {
ID_TEXTURESCALING_OFF,
ID_TEXTURESCALING_2X,
ID_TEXTURESCALING_3X,
ID_TEXTURESCALING_4X,
ID_TEXTURESCALING_5X,
};
for (int i = 0; i < 5; i++) {
CheckMenuItem(menu, texscalingitems[i], MF_BYCOMMAND | ((i == g_Config.iTexScalingLevel-1) ? MF_CHECKED : MF_UNCHECKED));
}
static const int texscalingtypeitems[] = {
ID_TEXTURESCALING_XBRZ,
ID_TEXTURESCALING_HYBRID,
ID_TEXTURESCALING_BICUBIC,
ID_TEXTURESCALING_HYBRID_BICUBIC,
};
for (int i = 0; i < 4; i++) {
CheckMenuItem(menu, texscalingtypeitems[i], MF_BYCOMMAND | ((i == g_Config.iTexScalingType) ? MF_CHECKED : MF_UNCHECKED));
}
UpdateCommands();
}
void UpdateCommands()
{
static GlobalUIState lastGlobalUIState = UISTATE_PAUSEMENU;
static CoreState lastCoreState = CORE_ERROR;
if (lastGlobalUIState == globalUIState && lastCoreState == coreState)
return;
lastCoreState = coreState;
lastGlobalUIState = globalUIState;
HMENU menu = GetMenu(GetHWND());
EnableMenuItem(menu,ID_EMULATION_RUN, (Core_IsStepping() || globalUIState == UISTATE_PAUSEMENU) ? MF_ENABLED : MF_GRAYED);
UINT ingameEnable = globalUIState == UISTATE_INGAME ? MF_ENABLED : MF_GRAYED;
EnableMenuItem(menu,ID_EMULATION_PAUSE, ingameEnable);
EnableMenuItem(menu,ID_EMULATION_STOP, ingameEnable);
EnableMenuItem(menu,ID_EMULATION_RESET, ingameEnable);
UINT menuEnable = globalUIState == UISTATE_MENU ? MF_ENABLED : MF_GRAYED;
EnableMenuItem(menu,ID_FILE_LOAD, menuEnable);
EnableMenuItem(menu,ID_FILE_LOAD_MEMSTICK, menuEnable);
EnableMenuItem(menu,ID_FILE_SAVESTATEFILE, !menuEnable);
EnableMenuItem(menu,ID_FILE_LOADSTATEFILE, !menuEnable);
EnableMenuItem(menu,ID_FILE_QUICKSAVESTATE, !menuEnable);
EnableMenuItem(menu,ID_FILE_QUICKLOADSTATE, !menuEnable);
EnableMenuItem(menu,ID_CPU_DYNAREC, menuEnable);
EnableMenuItem(menu,ID_CPU_INTERPRETER, menuEnable);
EnableMenuItem(menu,ID_EMULATION_STOP, !menuEnable);
}
// Message handler for about box.
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
W32Util::CenterWindow(hDlg);
{
HWND versionBox = GetDlgItem(hDlg, IDC_VERSION);
char temp[256];
sprintf(temp, "PPSSPP %s", PPSSPP_GIT_VERSION);
SetWindowText(versionBox, temp);
}
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
}
#define CONTROLS_IDC_EDIT_BEGIN IDC_EDIT_KEY_MENU
#define CONTROLS_IDC_EDIT_END IDC_EDIT_KEY_ANALOG_RIGHT
#define CONTROLS_BUTTONS_COUNT (IDC_EDIT_KEYRIGHT - CONTROLS_IDC_EDIT_BEGIN + 1)
#define CONTROLS_BUTTONNAME_MAX 16
// for controls dialog device polling and bind update.
#define TIMER_CONTROLS_BINDUPDATE 1
#define BINDUPDATE_INTERVAL_MS 50
static const char *controllist[] = {
"Menu", // Open PauseScreen
"Back", // Toggle PauseScreen & Back Setting Page.
"Triangle",
"Rectangle",
"Cross",
"Circle",
"Select",
"Start",
"Left Trigger",
"Right Trigger",
"Turbo", // LBUMPER (Turbo)
"Reserved", // RBUMPER (Open PauseScreen)
"Up",
"Down",
"Left",
"Right",
"LY+",
"LY-",
"LX-",
"LX+",
};
struct ControlsDlgState {
HHOOK pKeydownHook;
HBITMAP hbmPspImage;
HWND hCtrlTab;
UINT_PTR timerId;
WNDPROC orgPSPImageProc;
WNDPROC orgEditProc;
ControlMapping *pCtrlMap;
HWND hStaticPspImage;
};
static ControlsDlgState *pCtrlDlgState;
RECT getRedrawRect(HWND hWnd) {
RECT rc;
HWND hDlg = GetParent(hWnd);
GetWindowRect(hWnd, &rc);
POINT pt = {0, 0};
ScreenToClient(hDlg, &pt);
rc.left += pt.x;
rc.right += pt.x;
rc.top += pt.y;
rc.bottom += pt.y;
return rc;
}
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (pCtrlDlgState->pCtrlMap->GetTargetDevice() == CONTROLS_KEYBOARD_INDEX) {
HWND hEdit = GetFocus();
UINT nCtrlID = GetDlgCtrlID(hEdit);
if (nCtrlID < CONTROLS_IDC_EDIT_BEGIN || nCtrlID > CONTROLS_IDC_EDIT_END) {
return CallNextHookEx(pCtrlDlgState->pKeydownHook, nCode, wParam, lParam);
}
if (!(lParam&(1<<31))) {
// key down
HWND hDlg = GetParent(hEdit);
const char *str = getVirtualKeyName(wParam);
if (str) {
if (nCtrlID >= IDC_EDIT_KEY_ANALOG_UP) {
pCtrlDlgState->pCtrlMap->SetBindCode(wParam, CONTROLS_KEYBOARD_ANALOG_INDEX,
nCtrlID - IDC_EDIT_KEY_ANALOG_UP);
} else {
pCtrlDlgState->pCtrlMap->SetBindCode(wParam);
}
SetWindowTextA(hEdit, str);
RECT rc = getRedrawRect(hEdit);
InvalidateRect(hDlg, &rc, false);
}
else
MessageBoxA(hDlg, "Not supported!", "controller", MB_OK);
}
}
return 1;
}
HBITMAP LoadImageFromResource(HINSTANCE hInstance,LPCTSTR pszResourceName, LPCTSTR lpType)
{
HRSRC hrsrc = FindResource(hInstance, pszResourceName, lpType);
if (!hrsrc)
return FALSE;
DWORD dwlen = SizeofResource(hInstance, hrsrc);
BYTE *lpRsrc = (BYTE*)LoadResource(hInstance, hrsrc);
if (!lpRsrc)
return FALSE;
int width, height;
unsigned char *image_data = 0;
bool bResult = pngLoadPtr(lpRsrc, dwlen, &width, &height, &image_data, false) != 0;
FreeResource(lpRsrc);
if (!bResult)
return 0;
HBITMAP hbm = CreateBitmap(width, height, 1, 32, image_data);
free(image_data);
return hbm;
}
void BitBlt(HBITMAP hbm, HDC dstDC, int dstX, int dstY, int width, int height, int srcX, int srcY)
{
HDC hCompDC = CreateCompatibleDC(dstDC);
HBITMAP oldbm = (HBITMAP)SelectObject(hCompDC, hbm);
BitBlt(dstDC, dstX, dstY, width, height, hCompDC, srcX, srcY, SRCCOPY);
SelectObject(hCompDC, oldbm);
DeleteObject(hCompDC);
}
inline void SetWindowTextForButton(HWND hEdit, u32 buttonCode, const char *pszButtonName)
{
if (buttonCode == 0) {
SetWindowTextA(hEdit, "Disable");
} else {
SetWindowTextA(hEdit, pszButtonName);
}
}
// Draw background image of Controls Dialog (pspmode.png) by use static control.
LRESULT CALLBACK PSPImageProc(HWND hStatic, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message) {
case WM_PAINT:
{
PAINTSTRUCT pst;
HDC hdc = BeginPaint(hStatic, &pst);
BITMAP bm;
GetObject(pCtrlDlgState->hbmPspImage, sizeof(BITMAP), &bm);
BitBlt(pCtrlDlgState->hbmPspImage, hdc, 0, 0, bm.bmWidth, bm.bmHeight, 0 , 0);
EndPaint(hStatic, &pst);
return TRUE;
}
default:
break;
}
return CallWindowProc(pCtrlDlgState->orgPSPImageProc, hStatic, message, wParam, lParam);
}
LRESULT CALLBACK ButtonsEditProc(HWND hEdit, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_RBUTTONUP:
{
UINT nCtrlID = GetDlgCtrlID(hEdit);
int deviceIdx = TabCtrl_GetCurSel(pCtrlDlgState->hCtrlTab);
if (deviceIdx != CONTROLS_KEYBOARD_INDEX && nCtrlID >= IDC_EDIT_KEY_ANALOG_UP)
return TRUE;
HMENU hSubMenu = GetSubMenu(g_hPopupMenus, 4);
POINT pos;
pos.x = LOWORD(lParam);
pos.y = HIWORD(lParam);
ClientToScreen(hEdit, &pos);
switch(TrackPopupMenuEx(GetSubMenu(g_hPopupMenus, 4), TPM_RETURNCMD, pos.x, pos.y, hEdit, NULL))
{
case ID_CONTROLS_KEY_DISABLE:
{
if (nCtrlID < IDC_EDIT_KEY_ANALOG_UP) {
pCtrlDlgState->pCtrlMap->SetDisableBind(deviceIdx, nCtrlID - CONTROLS_IDC_EDIT_BEGIN);
}
else if (deviceIdx == CONTROLS_KEYBOARD_INDEX) {
pCtrlDlgState->pCtrlMap->SetDisableBind(
CONTROLS_KEYBOARD_ANALOG_INDEX, nCtrlID - IDC_EDIT_KEY_ANALOG_UP);
}
SetWindowTextA(hEdit, "Disable");
RECT rc = getRedrawRect(hEdit);
HWND hDlg = GetParent(hEdit);
InvalidateRect(hDlg, &rc, false);
break;
}
default:
break;
}
return TRUE;
}
default :
break;
}
return CallWindowProc(pCtrlDlgState->orgEditProc, hEdit, message, wParam, lParam);
}
// Message handler for control box.
LRESULT CALLBACK Controls(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
W32Util::CenterWindow(hDlg);
{
// IDC_EDIT_xxx is need continuous value to IDC_EDIT_KEY_ANALOG_RIGHT from IDC_EDIT_KEY_MENU.
// it is total 16.
// it is need the same order as the dinput_ctrl_map(and xinput/keyboard).
if (CONTROLS_BUTTONS_COUNT != 16) {
char mes[100];
snprintf(mes, 100, "CONTROLS_BUTTONS_COUNT(%d) is need 16.", CONTROLS_BUTTONS_COUNT);
MessageBoxA(hDlg, mes, "Controls dialog init error.", MB_OK);
}
pCtrlDlgState = new ControlsDlgState();
ZeroMemory(pCtrlDlgState, sizeof(ControlsDlgState));
pCtrlDlgState->pCtrlMap = ControlMapping::CreateInstance(CONTROLS_BUTTONS_COUNT);
if (!pCtrlDlgState->pCtrlMap) {
MessageBoxA(hDlg, "Cannot Created ControlMapping instance.", "Controls dialog init error.", MB_OK);
}
pCtrlDlgState->pCtrlMap->SetTargetDevice(CONTROLS_KEYBOARD_INDEX);
pCtrlDlgState->hCtrlTab = GetDlgItem(hDlg, IDC_TAB_INPUT_DEVICE);
TCITEM tcItem;
ZeroMemory(&tcItem, sizeof(tcItem));
tcItem.mask = TCIF_TEXT;
tcItem.dwState = 0;
tcItem.pszText = "Keyboard";
tcItem.cchTextMax = (int)strlen(tcItem.pszText)+1;
tcItem.iImage = 0;
TabCtrl_InsertItem(pCtrlDlgState->hCtrlTab, TabCtrl_GetItemCount(pCtrlDlgState->hCtrlTab),&tcItem);
tcItem.pszText = "DirectInput";
tcItem.cchTextMax = (int)strlen(tcItem.pszText)+1;
TabCtrl_InsertItem(pCtrlDlgState->hCtrlTab, TabCtrl_GetItemCount(pCtrlDlgState->hCtrlTab),&tcItem);
tcItem.pszText = "XInput";
tcItem.cchTextMax = (int)strlen(tcItem.pszText)+1;
TabCtrl_InsertItem(pCtrlDlgState->hCtrlTab, TabCtrl_GetItemCount(pCtrlDlgState->hCtrlTab),&tcItem);
int tp_w = 0, tp_h = 0;
// TODO: connect to keyboard device instead
{
HBITMAP hResBM = LoadImageFromResource(hInst, MAKEINTRESOURCE(IDB_IMAGE_PSP), "IMAGE");
pCtrlDlgState->hStaticPspImage = GetDlgItem(hDlg,IDC_STATIC_IMAGE_PSP);
RECT clientRect, tabPageRect, imgRect;
GetClientRect(hDlg, &clientRect);
memcpy(&tabPageRect, &clientRect, sizeof(RECT));
TabCtrl_AdjustRect(pCtrlDlgState->hCtrlTab, FALSE, &tabPageRect);
tp_w = tabPageRect.right - tabPageRect.left;
tp_h = tabPageRect.bottom - tabPageRect.top;
MoveWindow(pCtrlDlgState->hStaticPspImage, tabPageRect.left, tabPageRect.top, tp_w, tp_h, FALSE);
HDC hDC = GetDC(pCtrlDlgState->hStaticPspImage);
HBITMAP hMemBM = CreateCompatibleBitmap(hDC, tp_w, tp_h);
HDC hResDC = CreateCompatibleDC(hDC);
HDC hMemDC = CreateCompatibleDC(hDC);
SelectObject(hResDC, hResBM);
SelectObject(hMemDC, hMemBM);
BITMAP bm;
GetObject(hResBM, sizeof(BITMAP), &bm);
SetStretchBltMode(hMemDC, HALFTONE);
float scaleX = (float)bm.bmWidth / clientRect.right;
float scaleY = (float)bm.bmHeight / clientRect.bottom;
imgRect.left = (int)(tabPageRect.left * scaleX);
imgRect.top = (int)(tabPageRect.top * scaleY);
imgRect.right= (int)(bm.bmWidth - ((clientRect.right - tabPageRect.right) * scaleX));
imgRect.bottom = (int)(bm.bmHeight - ((clientRect.bottom - tabPageRect.bottom) * scaleY));
StretchBlt(hMemDC, 0, 0, tp_w, tp_h, hResDC, imgRect.left, imgRect.top,
imgRect.right - imgRect.left, imgRect.bottom - imgRect.top, SRCCOPY);
if (pCtrlDlgState->hbmPspImage)
DeleteObject(pCtrlDlgState->hbmPspImage);
pCtrlDlgState->hbmPspImage = hMemBM;
DeleteDC(hMemDC);
DeleteDC(hResDC);
ReleaseDC(pCtrlDlgState->hStaticPspImage, hDC);
DeleteObject(hResBM);
}
pCtrlDlgState->orgEditProc = (WNDPROC)GetWindowLongPtr(
GetDlgItem(hDlg, CONTROLS_IDC_EDIT_BEGIN), GWLP_WNDPROC);
for (int i = 0; i <= CONTROLS_IDC_EDIT_END - CONTROLS_IDC_EDIT_BEGIN; i++) {
HWND hEdit = GetDlgItem(hDlg, CONTROLS_IDC_EDIT_BEGIN + i);
if (i < CONTROLS_BUTTONS_COUNT) {
u32 keyCode = pCtrlDlgState->pCtrlMap->GetBindCode(CONTROLS_KEYBOARD_INDEX, i);
SetWindowTextForButton(hEdit, keyCode, getVirtualKeyName(keyCode));
} else {
u32 analogCode = pCtrlDlgState->pCtrlMap->GetBindCode(
CONTROLS_KEYBOARD_ANALOG_INDEX, i - CONTROLS_BUTTONS_COUNT);
SetWindowTextForButton(hEdit, analogCode, getVirtualKeyName(analogCode));
}
if (pCtrlDlgState->orgEditProc != (WNDPROC)GetWindowLongPtr(hEdit, GWLP_WNDPROC)) {
MessageBoxA(hDlg,
"Can not hook to the inherited Edit control. need wndproc of original edit control.",
"Controls dialog init error.", MB_OK);
break;
}
SetWindowLongPtr(hEdit, GWLP_WNDPROC, (LONG_PTR)ButtonsEditProc);
}
ComboBox_AddString(GetDlgItem(hDlg, IDC_FORCE_INPUT_DEVICE), "None");
ComboBox_AddString(GetDlgItem(hDlg, IDC_FORCE_INPUT_DEVICE), "XInput");
ComboBox_AddString(GetDlgItem(hDlg, IDC_FORCE_INPUT_DEVICE), "DirectInput");
if ((g_Config.iForceInputDevice < 0) || (g_Config.iForceInputDevice > 1))
{
ComboBox_SetCurSel(GetDlgItem(hDlg, IDC_FORCE_INPUT_DEVICE), 0);
}
else
{
ComboBox_SetCurSel(GetDlgItem(hDlg, IDC_FORCE_INPUT_DEVICE), (g_Config.iForceInputDevice + 1));
}
pCtrlDlgState->orgPSPImageProc = (WNDPROC)GetWindowLongPtr(pCtrlDlgState->hStaticPspImage, GWLP_WNDPROC);
SetWindowLongPtr(pCtrlDlgState->hStaticPspImage, GWLP_WNDPROC, (LONG_PTR)PSPImageProc);
DWORD dwThreadID = GetWindowThreadProcessId(hDlg, NULL);
pCtrlDlgState->pKeydownHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, NULL, dwThreadID);
pCtrlDlgState->timerId = SetTimer(hDlg, TIMER_CONTROLS_BINDUPDATE, BINDUPDATE_INTERVAL_MS, 0);
}
return TRUE;
case WM_TIMER:
{
if (wParam == TIMER_CONTROLS_BINDUPDATE &&
pCtrlDlgState->pCtrlMap->GetTargetDevice() != CONTROLS_KEYBOARD_INDEX) {
HWND hEdit = GetFocus();
UINT nCtrlID = GetDlgCtrlID(hEdit);
if (nCtrlID < CONTROLS_IDC_EDIT_BEGIN || nCtrlID > IDC_EDIT_KEYRIGHT) {
break;
}
// device polling and update.
int prevButton = pCtrlDlgState->pCtrlMap->GetBindCode();
pCtrlDlgState->pCtrlMap->UpdateState();
char str[CONTROLS_BUTTONNAME_MAX];
ZeroMemory(str, CONTROLS_BUTTONNAME_MAX * sizeof(char));
int buttonCode = pCtrlDlgState->pCtrlMap->GetBindCode();
if (buttonCode == -1 || prevButton == buttonCode)
break;
switch(pCtrlDlgState->pCtrlMap->GetTargetDevice())
{
case CONTROLS_KEYBOARD_INDEX:
{
; // leave it to KeyboardProc.
}
break;
case CONTROLS_DIRECT_INPUT_INDEX:
{
if (buttonCode > 0xFF) {
int n = 1;
for (int i = buttonCode >> 8; i > 1; i >>= 1) {
n++;
}
snprintf(str, CONTROLS_BUTTONNAME_MAX, "%s",
controllist[(IDC_EDIT_KEYUP - CONTROLS_IDC_EDIT_BEGIN - 1) + n]);
} else {
snprintf(str, CONTROLS_BUTTONNAME_MAX, "%d", buttonCode + 1);
}
SetWindowTextA(hEdit, str);
RECT rc = getRedrawRect(hEdit);
InvalidateRect(hDlg, &rc, FALSE);
}
break;
case CONTROLS_XINPUT_INDEX:
{
SetWindowTextA(hEdit, getXinputButtonName(buttonCode));
RECT rc = getRedrawRect(hEdit);
InvalidateRect(hDlg, &rc, FALSE);
}
break;
}
}
}
break;
case WM_NOTIFY:
{
switch (((NMHDR *)lParam)->code)
{
case TCN_SELCHANGE:
{
int cursel = TabCtrl_GetCurSel(pCtrlDlgState->hCtrlTab);
pCtrlDlgState->pCtrlMap->SetTargetDevice(cursel);
switch (cursel)
{
case CONTROLS_KEYBOARD_INDEX:
{
for (u32 i = 0; i <= IDC_EDIT_KEYRIGHT - CONTROLS_IDC_EDIT_BEGIN; i++) {
HWND hEdit = GetDlgItem(hDlg, CONTROLS_IDC_EDIT_BEGIN + i);
u32 keyCode = pCtrlDlgState->pCtrlMap->GetBindCode(i);
SetWindowTextForButton(hEdit, keyCode, getVirtualKeyName(keyCode));
}
for (u32 i = 0; i <= CONTROLS_IDC_EDIT_END - IDC_EDIT_KEY_ANALOG_UP; i++) {
HWND hEdit = GetDlgItem(hDlg, IDC_EDIT_KEY_ANALOG_UP + i);
Edit_SetReadOnly(hEdit, FALSE);
u32 analogCode = pCtrlDlgState->pCtrlMap->GetBindCode(
CONTROLS_KEYBOARD_ANALOG_INDEX, i);
SetWindowTextForButton(hEdit, analogCode, getVirtualKeyName(analogCode));
}
InvalidateRect(hDlg, 0, 0);
}
break;
case CONTROLS_DIRECT_INPUT_INDEX:
{
for (u32 i = 0; i <= CONTROLS_IDC_EDIT_END - CONTROLS_IDC_EDIT_BEGIN; i++) {
HWND hEdit = GetDlgItem(hDlg, CONTROLS_IDC_EDIT_BEGIN + i);
int buttonCode = (int)pCtrlDlgState->pCtrlMap->GetBindCode(i);
char str[16];
if (i >= IDC_EDIT_KEYUP - CONTROLS_IDC_EDIT_BEGIN) {
if (i >= IDC_EDIT_KEY_ANALOG_UP - CONTROLS_IDC_EDIT_BEGIN) {
Edit_SetReadOnly(hEdit, TRUE);
SetWindowTextA(hEdit, controllist[i]);
} else {
int n = 1;
if (buttonCode != -1) {
for (int i = buttonCode >> 8; i > 1; i >>= 1) {
n++;
}
snprintf(str, CONTROLS_BUTTONNAME_MAX, "%s",
controllist[(IDC_EDIT_KEYUP - CONTROLS_IDC_EDIT_BEGIN - 1) + n]);
}
SetWindowTextForButton(hEdit, buttonCode + 1, str);
}
continue;
}
snprintf(str, CONTROLS_BUTTONNAME_MAX, "%d", pCtrlDlgState->pCtrlMap->GetBindCode(i) + 1);
SetWindowTextForButton(hEdit, buttonCode + 1, str);
}
InvalidateRect(hDlg, 0, 0);
}
break;
case CONTROLS_XINPUT_INDEX:
{
for (u32 i = 0; i <= CONTROLS_IDC_EDIT_END - CONTROLS_IDC_EDIT_BEGIN; i++) {
HWND hEdit = GetDlgItem(hDlg, CONTROLS_IDC_EDIT_BEGIN + i);
if (i >= IDC_EDIT_KEY_ANALOG_UP - CONTROLS_IDC_EDIT_BEGIN) {
Edit_SetReadOnly(hEdit, TRUE);
SetWindowTextA(hEdit, controllist[i]);
continue;
}
u32 button = pCtrlDlgState->pCtrlMap->GetBindCode(i);
SetWindowTextForButton(hEdit, button, getXinputButtonName(button));
}
InvalidateRect(hDlg, 0, 0);
}
break;
default:
break;
} // pCtrlDlgState->curDevice
} // TCN_SELCHANGING:
break;
default:
break;
} // ((NMHDR *)lParam)->code
} // WM_NOTIFY:
break;
case WM_PAINT:
{
return DefWindowProc(hDlg, message, wParam, lParam);
}
case WM_CTLCOLORSTATIC:
{
HDC hdc=(HDC)wParam;
HWND hCtrl = (HWND)lParam;
SetBkMode(hdc, TRANSPARENT);
int ctrlId = GetDlgCtrlID(hCtrl);
if (ctrlId >= IDC_EDIT_KEY_ANALOG_UP && ctrlId <= IDC_EDIT_KEY_ANALOG_RIGHT) {
SetTextColor(hdc, RGB(128,128,128));
RECT rc = getRedrawRect(hCtrl);
TabCtrl_AdjustRect(pCtrlDlgState->hCtrlTab, TRUE, &rc);
RECT clientrc;
GetClientRect(hCtrl, &clientrc);
TabCtrl_AdjustRect(pCtrlDlgState->hCtrlTab, TRUE, &clientrc);
BitBlt(pCtrlDlgState->hbmPspImage, hdc, 0, 0, rc.right - rc.left, rc.bottom - rc.top, rc.left, rc.top);
char str[11];
GetWindowTextA(hCtrl, str, 10);
DrawTextA(hdc, str, (int)strlen(str), &clientrc, DT_CENTER|DT_SINGLELINE);
}
return (LRESULT)GetStockObject(NULL_BRUSH);
}
case WM_CTLCOLOREDIT:
{
if ((HWND)lParam == GetDlgItem(hDlg, IDC_FORCE_INPUT_DEVICE))
return FALSE;
HDC hdc = (HDC)wParam;
SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, RGB(255, 0, 0));
HWND hEdit = (HWND)lParam;
RECT rc = getRedrawRect(hEdit);
TabCtrl_AdjustRect(pCtrlDlgState->hCtrlTab, TRUE, &rc);
RECT clientrc;
GetClientRect(hEdit, &clientrc);
TabCtrl_AdjustRect(pCtrlDlgState->hCtrlTab, TRUE, &clientrc);
BitBlt(pCtrlDlgState->hbmPspImage, hdc, 0, 0, rc.right - rc.left, rc.bottom - rc.top, rc.left, rc.top);
char str[11];
GetWindowTextA(hEdit, str, 10);
DrawTextA(hdc, str, (int)strlen(str), &clientrc, DT_CENTER|DT_SINGLELINE);
return (LRESULT)GetStockObject(NULL_BRUSH);
}
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
if (LOWORD(wParam) == IDOK) {
g_Config.iForceInputDevice = (ComboBox_GetCurSel(GetDlgItem(hDlg, IDC_FORCE_INPUT_DEVICE)) - 1);
pCtrlDlgState->pCtrlMap->BindToDevices();
saveControlsToFile();
}
UnhookWindowsHookEx(pCtrlDlgState->pKeydownHook);
KillTimer(hDlg, pCtrlDlgState->timerId);
SetWindowLongPtr(pCtrlDlgState->hStaticPspImage, GWLP_WNDPROC, (LONG_PTR)pCtrlDlgState->orgPSPImageProc);
for (u32 i = CONTROLS_IDC_EDIT_BEGIN; i <= CONTROLS_IDC_EDIT_END; i++) {
HWND hEdit = GetDlgItem(hDlg, i);
SetWindowLongPtr(hEdit, GWLP_WNDPROC, (LONG_PTR)pCtrlDlgState->orgEditProc);
}
EndDialog(hDlg, LOWORD(wParam));
if (pCtrlDlgState->hbmPspImage) {
DeleteObject(pCtrlDlgState->hbmPspImage);
pCtrlDlgState->hbmPspImage = 0;
}
if (pCtrlDlgState->pCtrlMap) {
delete pCtrlDlgState->pCtrlMap;
pCtrlDlgState->pCtrlMap = NULL;
}
if (pCtrlDlgState) {
delete pCtrlDlgState;
pCtrlDlgState = NULL;
}
return TRUE;
} else if (LOWORD(wParam) >= CONTROLS_IDC_EDIT_BEGIN &&
LOWORD(wParam) <= IDC_EDIT_KEYRIGHT &&
HIWORD(wParam) == EN_SETFOCUS) {
// send about buttonsMap-index of current focus Edit-Control to ControlMapping instance.
UINT nCtrlID = LOWORD(wParam);
if (nCtrlID < CONTROLS_IDC_EDIT_BEGIN || nCtrlID > IDC_EDIT_KEYRIGHT) {
break;
}
pCtrlDlgState->pCtrlMap->SetTargetButton(nCtrlID - CONTROLS_IDC_EDIT_BEGIN);
}
break;
}
return FALSE;
}
void Update()
{
InvalidateRect(hwndDisplay,0,0);
UpdateWindow(hwndDisplay);
SendMessage(hwndMain,WM_SIZE,0,0);
}
void Redraw()
{
InvalidateRect(hwndDisplay,0,0);
}
void _ViewNormal(HWND hWnd)
{
// put caption and border styles back
DWORD dwOldStyle = ::GetWindowLong(hWnd, GWL_STYLE);
DWORD dwNewStyle = dwOldStyle | WS_CAPTION | WS_THICKFRAME;
::SetWindowLong(hWnd, GWL_STYLE, dwNewStyle);
// put back the menu bar
::SetMenu(hWnd, menu);
// resize to normal view
// NOTE: use SWP_FRAMECHANGED to force redraw non-client
const int x = g_normalRC.left;
const int y = g_normalRC.top;
const int cx = g_normalRC.right - g_normalRC.left;
const int cy = g_normalRC.bottom - g_normalRC.top;
::SetWindowPos(hWnd, HWND_NOTOPMOST, x, y, cx, cy, SWP_FRAMECHANGED);
// reset full screen indicator
g_bFullScreen = FALSE;
CorrectCursor();
ResizeDisplay();
ShowOwnedPopups(hwndMain, TRUE);
}
void _ViewFullScreen(HWND hWnd)
{
// keep in mind normal window rectangle
::GetWindowRect(hWnd, &g_normalRC);
// remove caption and border styles
DWORD dwOldStyle = ::GetWindowLong(hWnd, GWL_STYLE);
DWORD dwNewStyle = dwOldStyle & ~(WS_CAPTION | WS_THICKFRAME);
::SetWindowLong(hWnd, GWL_STYLE, dwNewStyle);
// remove the menu bar
::SetMenu(hWnd, NULL);
// resize to full screen view
// NOTE: use SWP_FRAMECHANGED to force redraw non-client
const int x = 0;
const int y = 0;
const int cx = ::GetSystemMetrics(SM_CXSCREEN);
const int cy = ::GetSystemMetrics(SM_CYSCREEN);
::SetWindowPos(hWnd, HWND_TOPMOST, x, y, cx, cy, SWP_FRAMECHANGED);
// set full screen indicator
g_bFullScreen = TRUE;
CorrectCursor();
ResizeDisplay();
ShowOwnedPopups(hwndMain, FALSE);
}
void SetPlaying(const char *text)
{
char temp[256];
if (text == 0)
snprintf(temp, 256, "PPSSPP %s", PPSSPP_GIT_VERSION);
else
snprintf(temp, 256, "%s - PPSSPP %s", text, PPSSPP_GIT_VERSION);
temp[255] = '\0';
SetWindowText(hwndMain, temp);
}
void SaveStateActionFinished(bool result, void *userdata)
{
if (!result)
MessageBox(0, "Savestate failure. Using savestates between different PPSSPP versions is not supported.", "Sorry", MB_OK);
SetCursor(LoadCursor(0, IDC_ARROW));
}
HINSTANCE GetHInstance()
{
return hInst;
}
}