mirror of
https://github.com/libretro/potator.git
synced 2024-11-27 10:40:31 +00:00
Add Control Config (Win platform)
This commit is contained in:
parent
f2949ec382
commit
783c002a64
@ -1,8 +1,14 @@
|
||||
#pragma comment(linker,"\"/manifestdependency:type='win32' \
|
||||
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
|
||||
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
||||
|
||||
#include <windows.h>
|
||||
//#include <commctrl.h>
|
||||
//#pragma comment(lib, "Comctl32.lib")
|
||||
#include <stdlib.h>
|
||||
#include <tchar.h>
|
||||
|
||||
// PathFindFileName()
|
||||
#include <shlwapi.h>
|
||||
#pragma comment(lib, "Shlwapi.lib")
|
||||
|
||||
@ -17,11 +23,14 @@
|
||||
#include "../../common/supervision.h"
|
||||
#include "../../common/sound.h"
|
||||
|
||||
#define SCREEN_W 160
|
||||
#define SCREEN_H 160
|
||||
|
||||
#ifdef TERRIBLE_AUDIO_IMPLEMENTATION
|
||||
WAVEHDR whdr;
|
||||
HWAVEOUT hWaveOut;
|
||||
// 44100 / 60 * 2 (channels) * 2 (16-bit) - 20
|
||||
#define BUFFER_SIZE 2920
|
||||
// 44100 / 60 * 2 (channels) * 2 (16-bit)
|
||||
#define BUFFER_SIZE 2940
|
||||
int8 audioBuffer[BUFFER_SIZE];
|
||||
#endif
|
||||
|
||||
@ -32,8 +41,8 @@ LPCTSTR szClassName = _T("Potator");
|
||||
#define WINDOW_STYLE (WS_SYSMENU | WS_MINIMIZEBOX | WS_CAPTION | WS_VISIBLE)
|
||||
#define WINDOW_EX_STYLE (WS_EX_CLIENTEDGE)
|
||||
|
||||
HWND hWindow;
|
||||
HMENU hMenu;
|
||||
HWND hWnd;
|
||||
HDC hDC;
|
||||
|
||||
DWORD threadID;
|
||||
@ -43,12 +52,33 @@ char romName[MAX_PATH];
|
||||
uint8 *buffer;
|
||||
uint32 bufferSize = 0;
|
||||
uint8 windowScale = 2;
|
||||
uint16 screenBuffer[160 * 160];
|
||||
uint16 screenBuffer[SCREEN_W * SCREEN_H];
|
||||
|
||||
int keysMapping[] = {
|
||||
VK_RIGHT
|
||||
, VK_LEFT
|
||||
, VK_DOWN
|
||||
, VK_UP
|
||||
, 'X'
|
||||
, 'C'
|
||||
, 'Z'
|
||||
, VK_SPACE
|
||||
};
|
||||
LPCTSTR keysNames[] = {
|
||||
_T("Right")
|
||||
, _T("Left")
|
||||
, _T("Down")
|
||||
, _T("Up")
|
||||
, _T("B")
|
||||
, _T("A")
|
||||
, _T("Select")
|
||||
, _T("Start")
|
||||
};
|
||||
|
||||
#define UPDATE_RATE 60
|
||||
|
||||
uint64 startCounter;
|
||||
uint64 freq;
|
||||
|
||||
void InitCounter(void)
|
||||
{
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
|
||||
@ -77,7 +107,7 @@ BOOL NeedUpdate(void)
|
||||
// FIXME: IPC (lock Load ROM before exit 'while (execute)')
|
||||
DWORD WINAPI run(LPVOID lpParameter)
|
||||
{
|
||||
BITMAPV4HEADER bmi;
|
||||
BITMAPV4HEADER bmi = { 0 };
|
||||
TCHAR txt[64];
|
||||
uint64 curticks = 0;
|
||||
uint64 fpsticks = 0;
|
||||
@ -89,8 +119,6 @@ DWORD WINAPI run(LPVOID lpParameter)
|
||||
hTimer = CreateWaitableTimer(NULL, FALSE, NULL);
|
||||
SetWaitableTimer(hTimer, &dueTime, 1000 / UPDATE_RATE, NULL, NULL, TRUE);
|
||||
|
||||
//CreateBitmapIndirect(&bmi);
|
||||
memset(&bmi, 0, sizeof(bmi));
|
||||
bmi.bV4Size = sizeof(bmi);
|
||||
bmi.bV4Planes = 1;
|
||||
bmi.bV4BitCount = 16;
|
||||
@ -98,22 +126,18 @@ DWORD WINAPI run(LPVOID lpParameter)
|
||||
bmi.bV4RedMask = 0x001F;
|
||||
bmi.bV4GreenMask = 0x03E0;
|
||||
bmi.bV4BlueMask = 0x7C00;
|
||||
bmi.bV4Width = 160;
|
||||
bmi.bV4Height = -160;
|
||||
bmi.bV4Width = SCREEN_W;
|
||||
bmi.bV4Height = -SCREEN_H;
|
||||
|
||||
while (!finished) {
|
||||
InitCounter();
|
||||
while (execute) {
|
||||
uint8 controls_state = 0;
|
||||
|
||||
if (GetAsyncKeyState(VK_RIGHT) & 0x8000) controls_state |= 0x01;
|
||||
if (GetAsyncKeyState(VK_LEFT ) & 0x8000) controls_state |= 0x02;
|
||||
if (GetAsyncKeyState(VK_DOWN ) & 0x8000) controls_state |= 0x04;
|
||||
if (GetAsyncKeyState(VK_UP ) & 0x8000) controls_state |= 0x08;
|
||||
if (GetAsyncKeyState('X' ) & 0x8000) controls_state |= 0x10;
|
||||
if (GetAsyncKeyState('C' ) & 0x8000) controls_state |= 0x20;
|
||||
if (GetAsyncKeyState('Z' ) & 0x8000) controls_state |= 0x40;
|
||||
if (GetAsyncKeyState(VK_SPACE) & 0x8000) controls_state |= 0x80;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (GetAsyncKeyState(keysMapping[i]) & 0x8000)
|
||||
controls_state |= 1 << i;
|
||||
}
|
||||
|
||||
controls_state_write(0, controls_state);
|
||||
|
||||
@ -140,23 +164,22 @@ DWORD WINAPI run(LPVOID lpParameter)
|
||||
fpsticks = curticks; // Initial value
|
||||
if (curticks >= fpsticks) {
|
||||
_stprintf(txt, _T("%s (FPS: %d)"), szClassName, fpsframecount);
|
||||
SetWindowText(hWnd, txt);
|
||||
SetWindowText(hWindow, txt);
|
||||
fpsframecount = 0;
|
||||
fpsticks += freq;
|
||||
}
|
||||
|
||||
RECT r;
|
||||
GetClientRect(hWnd, &r);
|
||||
LONG w = r.right - r.left;
|
||||
LONG h = r.bottom - r.top;
|
||||
GetClientRect(hWindow, &r);
|
||||
LONG x = 0, w = r.right - r.left;
|
||||
LONG y = 0, h = r.bottom - r.top;
|
||||
if (w != h) {
|
||||
// Center
|
||||
LONG size = h / 160 * 160;
|
||||
StretchDIBits(hDC, (w - size) / 2, (h - size) / 2, size, size, 0, 0, 160, 160, screenBuffer, (BITMAPINFO*)&bmi, DIB_RGB_COLORS, SRCCOPY);
|
||||
}
|
||||
else {
|
||||
StretchDIBits(hDC, 0, 0, w, h, 0, 0, 160, 160, screenBuffer, (BITMAPINFO*)&bmi, DIB_RGB_COLORS, SRCCOPY);
|
||||
LONG size = h / SCREEN_H * SCREEN_H;
|
||||
x = (w - size) / 2; w = size;
|
||||
y = (h - size) / 2; h = size;
|
||||
}
|
||||
StretchDIBits(hDC, x, y, w, h, 0, 0, SCREEN_W, SCREEN_H, screenBuffer, (BITMAPINFO*)&bmi, DIB_RGB_COLORS, SRCCOPY);
|
||||
}
|
||||
|
||||
WaitForSingleObject(hTimer, INFINITE);
|
||||
@ -200,15 +223,34 @@ int LoadROM(LPCTSTR fileName)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void UpdateGhosting(void);
|
||||
void UpdatePalette(void);
|
||||
|
||||
void LoadBuffer(void)
|
||||
{
|
||||
supervision_load(&buffer, bufferSize);
|
||||
UpdateGhosting();
|
||||
UpdatePalette();
|
||||
}
|
||||
|
||||
void StopEmulation(void)
|
||||
{
|
||||
execute = FALSE;
|
||||
Sleep(1000 / UPDATE_RATE * 4); // Wait for the end of execution
|
||||
}
|
||||
|
||||
void ResumeEmulation(void)
|
||||
{
|
||||
execute = TRUE;
|
||||
}
|
||||
|
||||
void UpdateWindowSize(void)
|
||||
{
|
||||
CheckMenuRadioItem(hMenu, IDM_SIZE1, IDM_SIZE6, IDM_SIZE1 + windowScale - 1, MF_BYCOMMAND);
|
||||
|
||||
RECT r = { 0 };
|
||||
r.right = 160 * windowScale;
|
||||
r.bottom = 160 * windowScale;
|
||||
RECT r;
|
||||
SetRect(&r, 0, 0, SCREEN_W * windowScale, SCREEN_H * windowScale);
|
||||
AdjustWindowRectEx(&r, WINDOW_STYLE, TRUE, WINDOW_EX_STYLE);
|
||||
SetWindowPos(hWnd, NULL, 0, 0, r.right - r.left, r.bottom - r.top, SWP_NOMOVE | SWP_NOZORDER | SWP_SHOWWINDOW);
|
||||
SetWindowPos(hWindow, NULL, 0, 0, r.right - r.left, r.bottom - r.top, SWP_NOMOVE | SWP_NOZORDER | SWP_SHOWWINDOW);
|
||||
}
|
||||
|
||||
int currGhosting = 0;
|
||||
@ -241,7 +283,7 @@ void InitMenu(void)
|
||||
AppendMenu(hMenuGhosting, MF_STRING, IDM_GHOSTING + i, buf);
|
||||
}
|
||||
HMENU hMenuOptions = GetSubMenu(hMenu, 1);
|
||||
AppendMenu(hMenuOptions, MF_POPUP, (UINT_PTR)hMenuGhosting, _T("Ghosting"));
|
||||
InsertMenu(hMenuOptions, 2, MF_POPUP | MF_BYPOSITION, (UINT_PTR)hMenuGhosting, _T("Ghosting"));
|
||||
UpdateGhosting();
|
||||
|
||||
HMENU hMenuPalette = CreateMenu();
|
||||
@ -250,37 +292,60 @@ void InitMenu(void)
|
||||
_stprintf(buf, _T("%d"), i);
|
||||
AppendMenu(hMenuPalette, MF_STRING, IDM_PALETTE + i, buf);
|
||||
}
|
||||
AppendMenu(hMenuOptions, MF_POPUP, (UINT_PTR)hMenuPalette, _T("Palette"));
|
||||
InsertMenu(hMenuOptions, 3, MF_POPUP | MF_BYPOSITION, (UINT_PTR)hMenuPalette, _T("Palette"));
|
||||
UpdatePalette();
|
||||
}
|
||||
|
||||
BOOL showCursorFullscreen = FALSE;
|
||||
|
||||
BOOL IsFullscreen(void)
|
||||
{
|
||||
return GetWindowLongPtr(hWindow, GWL_STYLE) & WS_POPUP;
|
||||
}
|
||||
|
||||
void ToggleFullscreen(void)
|
||||
{
|
||||
static RECT lastPos = { 0 };
|
||||
if (GetWindowLongPtr(hWnd, GWL_STYLE) & WS_POPUP) {
|
||||
SetWindowLongPtr(hWnd, GWL_STYLE, WINDOW_STYLE);
|
||||
SetWindowLongPtr(hWnd, GWL_EXSTYLE, WINDOW_EX_STYLE);
|
||||
SetWindowPos(hWnd, NULL, lastPos.left, lastPos.top, 0, 0, SWP_FRAMECHANGED);
|
||||
UpdateWindowSize();
|
||||
SetMenu(hWnd, hMenu);
|
||||
static WINDOWPLACEMENT wp;
|
||||
if (IsFullscreen()) {
|
||||
SetWindowLongPtr(hWindow, GWL_STYLE, WINDOW_STYLE);
|
||||
SetWindowLongPtr(hWindow, GWL_EXSTYLE, WINDOW_EX_STYLE);
|
||||
SetWindowPlacement(hWindow, &wp);
|
||||
SetWindowPos(hWindow, NULL, 0, 0, 0, 0,
|
||||
SWP_FRAMECHANGED | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE);
|
||||
SetMenu(hWindow, hMenu);
|
||||
if (!showCursorFullscreen)
|
||||
ShowCursor(TRUE);
|
||||
}
|
||||
else {
|
||||
showCursorFullscreen = FALSE;
|
||||
wp.length = sizeof(wp);
|
||||
GetWindowPlacement(hWindow, &wp);
|
||||
SetWindowLongPtr(hWindow, GWL_STYLE, WS_VISIBLE | WS_POPUP);
|
||||
SetWindowLongPtr(hWindow, GWL_EXSTYLE, 0);
|
||||
int w = GetSystemMetrics(SM_CXSCREEN);
|
||||
int h = GetSystemMetrics(SM_CYSCREEN);
|
||||
GetWindowRect(hWnd, &lastPos);
|
||||
SetWindowLongPtr(hWnd, GWL_STYLE, WS_VISIBLE | WS_POPUP);
|
||||
SetWindowLongPtr(hWnd, GWL_EXSTYLE, 0);
|
||||
SetWindowPos(hWnd, HWND_TOP, 0, 0, w, h, SWP_FRAMECHANGED);
|
||||
SetMenu(hWnd, NULL);
|
||||
// SWP_NOOWNERZORDER - prevent showing child windows on top
|
||||
SetWindowPos(hWindow, HWND_TOP, 0, 0, w, h, SWP_FRAMECHANGED | SWP_NOOWNERZORDER);
|
||||
SetMenu(hWindow, NULL);
|
||||
ShowCursor(FALSE);
|
||||
RECT r = { 0, 0, w, h };
|
||||
FillRect(hDC, &r, (HBRUSH)GetStockObject(BLACK_BRUSH));
|
||||
}
|
||||
InvalidateRect(hWindow, NULL, TRUE);
|
||||
}
|
||||
|
||||
void RegisterControlConfigClass(HWND);
|
||||
void CreateControlConfigWindow(HWND);
|
||||
|
||||
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (msg)
|
||||
{
|
||||
static HFONT hFont;
|
||||
switch (msg) {
|
||||
case WM_CREATE:
|
||||
hFont = CreateFont(0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
|
||||
ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, _T("Arial"));
|
||||
RegisterControlConfigClass(hWnd);
|
||||
break;
|
||||
case WM_COMMAND:
|
||||
{
|
||||
int wmId = LOWORD(wParam);
|
||||
@ -294,8 +359,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
UpdatePalette();
|
||||
break;
|
||||
}
|
||||
switch (wmId)
|
||||
{
|
||||
switch (wmId) {
|
||||
case IDM_OPEN:
|
||||
{
|
||||
execute = FALSE; // Stop emulation while opening new rom
|
||||
@ -309,7 +373,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
ofn.lpstrFile = szFileName;
|
||||
ofn.nMaxFile = MAX_PATH;
|
||||
ofn.lpstrDefExt = _T("sv");
|
||||
ofn.Flags = OFN_NOCHANGEDIR;
|
||||
ofn.Flags = OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
|
||||
|
||||
if (!GetOpenFileName(&ofn)) {
|
||||
if (buffer)
|
||||
@ -318,27 +382,23 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
}
|
||||
|
||||
if (LoadROM(szFileName) == 0) {
|
||||
supervision_load(&buffer, (uint32)bufferSize);
|
||||
UpdateGhosting();
|
||||
UpdatePalette();
|
||||
LoadBuffer();
|
||||
execute = TRUE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IDM_SAVE:
|
||||
if (buffer) {
|
||||
execute = FALSE;
|
||||
Sleep(1000 / UPDATE_RATE * 4); // Wait for the end of execution
|
||||
StopEmulation();
|
||||
supervision_save_state(romName, 0);
|
||||
execute = TRUE;
|
||||
ResumeEmulation();
|
||||
}
|
||||
break;
|
||||
case IDM_LOAD:
|
||||
if (buffer) {
|
||||
execute = FALSE;
|
||||
Sleep(1000 / UPDATE_RATE * 4); // Wait for the end of execution
|
||||
StopEmulation();
|
||||
supervision_load_state(romName, 0);
|
||||
execute = TRUE;
|
||||
ResumeEmulation();
|
||||
}
|
||||
break;
|
||||
case IDM_WEBSITE:
|
||||
@ -359,6 +419,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
windowScale = wmId - IDM_SIZE1 + 1;
|
||||
UpdateWindowSize();
|
||||
break;
|
||||
case IDM_CONTROL_CONFIG:
|
||||
CreateControlConfigWindow(hWnd);
|
||||
break;
|
||||
case IDM_EXIT:
|
||||
DestroyWindow(hWnd);
|
||||
break;
|
||||
@ -369,25 +432,54 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
break;
|
||||
case WM_DROPFILES:
|
||||
{
|
||||
execute = FALSE;
|
||||
Sleep(1000 / UPDATE_RATE * 4); // Wait for the end of execution
|
||||
StopEmulation();
|
||||
HDROP hDrop = (HDROP)wParam;
|
||||
TCHAR szFileName[MAX_PATH] = _T("");
|
||||
DragQueryFile(hDrop, 0, szFileName, MAX_PATH);
|
||||
DragFinish(hDrop);
|
||||
|
||||
if (LoadROM(szFileName) == 0) {
|
||||
supervision_load(&buffer, (uint32)bufferSize);
|
||||
UpdateGhosting();
|
||||
UpdatePalette();
|
||||
execute = TRUE;
|
||||
LoadBuffer();
|
||||
ResumeEmulation();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WM_LBUTTONDBLCLK:
|
||||
ToggleFullscreen();
|
||||
break;
|
||||
case WM_SYSCOMMAND:
|
||||
// Alt or F10 show menu
|
||||
if (wParam == SC_KEYMENU && IsFullscreen()) {
|
||||
showCursorFullscreen = !showCursorFullscreen;
|
||||
ShowCursor(showCursorFullscreen);
|
||||
SetMenu(hWindow, showCursorFullscreen ? hMenu : NULL);
|
||||
return DefWindowProc(hWnd, msg, wParam, lParam); // If break;, menu doesn't get focus
|
||||
}
|
||||
return DefWindowProc(hWnd, msg, wParam, lParam);
|
||||
case WM_PAINT:
|
||||
{
|
||||
if (!buffer && !IsFullscreen()) {
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc = BeginPaint(hWnd, &ps);
|
||||
SelectObject(hdc, hFont);
|
||||
TEXTMETRIC tm;
|
||||
GetTextMetrics(hdc, &tm);
|
||||
SetTextColor(hdc, RGB(255, 255, 255));
|
||||
SetBkColor(hdc, RGB(0, 0, 0));
|
||||
#define X(s) _T(s), _countof(s)
|
||||
TextOut(hdc, 8, 8 , X("Open ROM:"));
|
||||
TextOut(hdc, 8, 8 + tm.tmHeight * 1, X("Drag & Drop"));
|
||||
TextOut(hdc, 8, 8 + tm.tmHeight * 3, X("Toggle Fullscreen:"));
|
||||
TextOut(hdc, 8, 8 + tm.tmHeight * 4, X("Double-Click or Alt+Enter"));
|
||||
TextOut(hdc, 8, 8 + tm.tmHeight * 6, X("Toggle Menu in Fullscreen:"));
|
||||
TextOut(hdc, 8, 8 + tm.tmHeight * 7, X("Press Alt or F10"));
|
||||
#undef X
|
||||
EndPaint(hWnd, &ps);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WM_CLOSE:
|
||||
DeleteObject(hFont);
|
||||
DestroyWindow(hWnd);
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
@ -399,9 +491,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
||||
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
|
||||
{
|
||||
//InitCommonControlsEx
|
||||
//INITCOMMONCONTROLSEX ccs = { 0 };
|
||||
//ccs.dwSize = sizeof(ccs);
|
||||
//ccs.dwICC = ICC_STANDARD_CLASSES;
|
||||
//InitCommonControlsEx(&ccs);
|
||||
|
||||
supervision_init();
|
||||
|
||||
@ -424,23 +519,23 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
hWnd = CreateWindowEx(WINDOW_EX_STYLE, szClassName, szClassName, WINDOW_STYLE,
|
||||
hWindow = CreateWindowEx(WINDOW_EX_STYLE, szClassName, szClassName, WINDOW_STYLE,
|
||||
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
|
||||
if (!hWnd) {
|
||||
if (!hWindow) {
|
||||
MessageBox(NULL, _T("Window creation failed!"), szClassName, MB_ICONEXCLAMATION | MB_OK);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DragAcceptFiles(hWnd, TRUE);
|
||||
DragAcceptFiles(hWindow, TRUE);
|
||||
|
||||
hDC = GetDC(hWnd);
|
||||
hMenu = GetMenu(hWnd);
|
||||
hDC = GetDC(hWindow);
|
||||
hMenu = GetMenu(hWindow);
|
||||
UpdateWindowSize();
|
||||
|
||||
InitMenu();
|
||||
|
||||
ShowWindow(hWnd, nCmdShow);
|
||||
UpdateWindow(hWnd);
|
||||
ShowWindow(hWindow, nCmdShow);
|
||||
UpdateWindow(hWindow);
|
||||
|
||||
#ifdef TERRIBLE_AUDIO_IMPLEMENTATION
|
||||
whdr.lpData = (LPSTR)audioBuffer;
|
||||
@ -475,9 +570,138 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseDC(hWnd, hDC);
|
||||
ReleaseDC(hWindow, hDC);
|
||||
|
||||
UnregisterClass(wcex.lpszClassName, hInstance);
|
||||
|
||||
return (int)msg.wParam;
|
||||
}
|
||||
|
||||
// Control Config
|
||||
|
||||
WPARAM MapLeftRightKeys(WPARAM vk, LPARAM lParam);
|
||||
void VirtualKeyCodeToString(UINT virtualKey, LPTSTR szName, int size);
|
||||
|
||||
HWND hButton;
|
||||
int buttonId;
|
||||
|
||||
LRESULT CALLBACK GetMsgProc(int code, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (code < 0) {
|
||||
return CallNextHookEx(NULL, code, wParam, lParam);
|
||||
}
|
||||
MSG msg = *((MSG*)lParam);
|
||||
if (msg.message == WM_KEYDOWN) {
|
||||
if (hButton) {
|
||||
TCHAR buf[32] = { 0 };
|
||||
GetKeyNameText(msg.lParam, buf, _countof(buf));
|
||||
SetWindowText(hButton, buf);
|
||||
EnableWindow(hButton, TRUE);
|
||||
hButton = NULL;
|
||||
keysMapping[buttonId - 1] = (int)MapLeftRightKeys(msg.wParam, msg.lParam);
|
||||
}
|
||||
}
|
||||
return CallNextHookEx(NULL, code, wParam, lParam);
|
||||
}
|
||||
|
||||
HWND hControlConfigWindow;
|
||||
|
||||
LRESULT CALLBACK ControlConfigProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
static HHOOK hHook;
|
||||
static HFONT hFont;
|
||||
switch (msg) {
|
||||
case WM_CREATE:
|
||||
hButton = NULL;
|
||||
buttonId = 0;
|
||||
hFont = CreateFont(0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
|
||||
ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, _T("Arial"));
|
||||
for (int i = 0; i < 8; i++) {
|
||||
HWND h = CreateWindow(_T("static"), keysNames[i], WS_VISIBLE | WS_CHILD,
|
||||
11, 11 + i * 30, 80, 25, hwnd, (HMENU)((UINT_PTR)i + 1 + 8), NULL, NULL);
|
||||
SendMessage(h, WM_SETFONT, (WPARAM)hFont, TRUE);
|
||||
TCHAR name[32];
|
||||
VirtualKeyCodeToString(keysMapping[i], name, _countof(name));
|
||||
h = CreateWindow(_T("button"), name, WS_VISIBLE | WS_CHILD,
|
||||
80, 8 + i * 30, 120, 25, hwnd, (HMENU)((UINT_PTR)i + 1), NULL, NULL);
|
||||
SendMessage(h, WM_SETFONT, (WPARAM)hFont, TRUE);
|
||||
}
|
||||
hHook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, GetModuleHandle(NULL), GetCurrentThreadId());
|
||||
break;
|
||||
case WM_COMMAND:
|
||||
{
|
||||
int wmId = LOWORD(wParam);
|
||||
if (wmId >= 1 && wmId <= 8) {
|
||||
if (hButton) break;
|
||||
hButton = (HWND)lParam;
|
||||
buttonId = wmId;
|
||||
EnableWindow(hButton, FALSE);
|
||||
SetWindowText(hButton, _T("Press Key"));
|
||||
SetFocus(hwnd);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WM_CLOSE:
|
||||
hControlConfigWindow = NULL;
|
||||
DeleteObject(hFont);
|
||||
UnhookWindowsHookEx(hHook);
|
||||
DestroyWindow(hwnd);
|
||||
break;
|
||||
}
|
||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
void RegisterControlConfigClass(HWND hwnd)
|
||||
{
|
||||
WNDCLASSEX wc = { 0 };
|
||||
wc.cbSize = sizeof(WNDCLASSEX);
|
||||
wc.hInstance = GetModuleHandle(NULL);
|
||||
wc.lpszClassName = _T("ControlConfigClass");
|
||||
wc.lpfnWndProc = ControlConfigProc;
|
||||
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
|
||||
RegisterClassEx(&wc);
|
||||
}
|
||||
|
||||
void CreateControlConfigWindow(HWND hwnd)
|
||||
{
|
||||
if (hControlConfigWindow)
|
||||
return;
|
||||
RECT r;
|
||||
GetWindowRect(hWindow, &r);
|
||||
hControlConfigWindow = CreateWindowEx(WS_EX_DLGMODALFRAME, _T("ControlConfigClass"), _T("Control Config"),
|
||||
WS_VISIBLE | WS_SYSMENU | WS_CAPTION, r.left + 64, r.top + 64, 228, 290,
|
||||
hwnd, NULL, GetModuleHandle(NULL), NULL);
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/15977613
|
||||
WPARAM MapLeftRightKeys(WPARAM virtualKey, LPARAM lParam)
|
||||
{
|
||||
UINT scancode = (lParam & 0x00ff0000) >> 16;
|
||||
int extended = (lParam & 0x01000000) != 0;
|
||||
switch (virtualKey) {
|
||||
case VK_SHIFT:
|
||||
return MapVirtualKey(scancode, MAPVK_VSC_TO_VK_EX);
|
||||
case VK_CONTROL:
|
||||
return extended ? VK_RCONTROL : VK_LCONTROL;
|
||||
case VK_MENU:
|
||||
return extended ? VK_RMENU : VK_LMENU;
|
||||
}
|
||||
return virtualKey;
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/38107083
|
||||
void VirtualKeyCodeToString(UINT virtualKey, LPTSTR szName, int size)
|
||||
{
|
||||
UINT scanCode = MapVirtualKey(virtualKey, MAPVK_VK_TO_VSC);
|
||||
switch (virtualKey) {
|
||||
case VK_LEFT: case VK_UP: case VK_RIGHT: case VK_DOWN:
|
||||
case VK_RCONTROL: case VK_RMENU:
|
||||
case VK_LWIN: case VK_RWIN: case VK_APPS:
|
||||
case VK_INSERT: case VK_DELETE:
|
||||
case VK_HOME: case VK_END:
|
||||
case VK_PRIOR: case VK_NEXT:
|
||||
case VK_NUMLOCK: case VK_DIVIDE:
|
||||
scanCode |= KF_EXTENDED;
|
||||
}
|
||||
GetKeyNameText(scanCode << 16, szName, size);
|
||||
}
|
||||
|
@ -17,8 +17,9 @@
|
||||
#define IDM_SIZE6 112
|
||||
|
||||
#define IDM_FULLSCREEN 113
|
||||
#define IDM_CONTROL_CONFIG 114
|
||||
|
||||
#define IDM_GHOSTING 114
|
||||
#define IDM_GHOSTING 115
|
||||
#define IDM_PALETTE (IDM_GHOSTING + SV_GHOSTING_MAX + 1)
|
||||
|
||||
#endif
|
||||
|
@ -6,7 +6,7 @@ MENU_PRINCIPAL MENU
|
||||
BEGIN
|
||||
POPUP "&File"
|
||||
BEGIN
|
||||
MENUITEM "&Open\tCtrl+O",IDM_OPEN
|
||||
MENUITEM "&Open ROM...\tCtrl+O",IDM_OPEN
|
||||
MENUITEM "&Load State\t2", IDM_LOAD
|
||||
MENUITEM "&Save State\t1", IDM_SAVE
|
||||
MENUITEM SEPARATOR
|
||||
@ -24,6 +24,7 @@ BEGIN
|
||||
MENUITEM "&5x",IDM_SIZE5
|
||||
MENUITEM "&6x",IDM_SIZE6
|
||||
END
|
||||
MENUITEM "&Control Config...\tCtrl+I",IDM_CONTROL_CONFIG
|
||||
END
|
||||
POPUP "&Help"
|
||||
BEGIN
|
||||
@ -35,8 +36,10 @@ END
|
||||
|
||||
IDR_MAIN_ACCEL ACCELERATORS DISCARDABLE
|
||||
BEGIN
|
||||
"O", IDM_OPEN, VIRTKEY, CONTROL, NOINVERT
|
||||
"O", IDM_OPEN, VIRTKEY, CONTROL
|
||||
"2", IDM_LOAD, VIRTKEY
|
||||
"1", IDM_SAVE, VIRTKEY
|
||||
VK_F11, IDM_FULLSCREEN, VIRTKEY
|
||||
VK_RETURN, IDM_FULLSCREEN, VIRTKEY, ALT
|
||||
"I", IDM_CONTROL_CONFIG, VIRTKEY, CONTROL
|
||||
END
|
||||
|
Loading…
Reference in New Issue
Block a user