Add Control Config (Win platform)

This commit is contained in:
infvaL 2018-10-21 20:51:11 +03:00
parent f2949ec382
commit 783c002a64
3 changed files with 385 additions and 157 deletions

View File

@ -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,144 +292,194 @@ 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);
if (wmId >= IDM_GHOSTING && wmId <= IDM_GHOSTING + SV_GHOSTING_MAX) {
currGhosting = wmId - IDM_GHOSTING;
UpdateGhosting();
break;
}
else if (wmId >= IDM_PALETTE && wmId <= IDM_PALETTE + SV_COLOR_SCHEME_COUNT - 1) {
currPalette = wmId - IDM_PALETTE;
UpdatePalette();
break;
}
switch (wmId)
{
case IDM_OPEN:
{
execute = FALSE; // Stop emulation while opening new rom
TCHAR szFileName[MAX_PATH] = _T("");
OPENFILENAME ofn;
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hWnd;
ofn.lpstrFilter = _T("Supervision files (.sv, .ws, .bin)\0*.sv;*.ws;*.bin\0\0");
ofn.nFilterIndex = 1;
ofn.lpstrFile = szFileName;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrDefExt = _T("sv");
ofn.Flags = OFN_NOCHANGEDIR;
if (!GetOpenFileName(&ofn)) {
if (buffer)
execute = TRUE;
return 0;
}
if (LoadROM(szFileName) == 0) {
supervision_load(&buffer, (uint32)bufferSize);
UpdateGhosting();
UpdatePalette();
execute = TRUE;
}
}
break;
case IDM_SAVE:
if (buffer) {
execute = FALSE;
Sleep(1000 / UPDATE_RATE * 4); // Wait for the end of execution
supervision_save_state(romName, 0);
execute = TRUE;
}
break;
case IDM_LOAD:
if (buffer) {
execute = FALSE;
Sleep(1000 / UPDATE_RATE * 4); // Wait for the end of execution
supervision_load_state(romName, 0);
execute = TRUE;
}
break;
case IDM_WEBSITE:
ShellExecute(NULL, _T("open"), _T("https://github.com/infval/potator"), NULL, NULL, SW_SHOWNORMAL);
break;
case IDM_ABOUT:
MessageBox(NULL, _T("Potator 1.0 (fork)"), szClassName, MB_ICONEXCLAMATION | MB_OK);
break;
case IDM_FULLSCREEN:
ToggleFullscreen();
break;
case IDM_SIZE1:
case IDM_SIZE2:
case IDM_SIZE3:
case IDM_SIZE4:
case IDM_SIZE5:
case IDM_SIZE6:
windowScale = wmId - IDM_SIZE1 + 1;
UpdateWindowSize();
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
{
int wmId = LOWORD(wParam);
if (wmId >= IDM_GHOSTING && wmId <= IDM_GHOSTING + SV_GHOSTING_MAX) {
currGhosting = wmId - IDM_GHOSTING;
UpdateGhosting();
break;
}
else if (wmId >= IDM_PALETTE && wmId <= IDM_PALETTE + SV_COLOR_SCHEME_COUNT - 1) {
currPalette = wmId - IDM_PALETTE;
UpdatePalette();
break;
}
switch (wmId) {
case IDM_OPEN:
{
execute = FALSE; // Stop emulation while opening new rom
TCHAR szFileName[MAX_PATH] = _T("");
OPENFILENAME ofn;
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hWnd;
ofn.lpstrFilter = _T("Supervision files (.sv, .ws, .bin)\0*.sv;*.ws;*.bin\0\0");
ofn.nFilterIndex = 1;
ofn.lpstrFile = szFileName;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrDefExt = _T("sv");
ofn.Flags = OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if (!GetOpenFileName(&ofn)) {
if (buffer)
execute = TRUE;
return 0;
}
if (LoadROM(szFileName) == 0) {
LoadBuffer();
execute = TRUE;
}
}
break;
case IDM_SAVE:
if (buffer) {
StopEmulation();
supervision_save_state(romName, 0);
ResumeEmulation();
}
break;
case IDM_LOAD:
if (buffer) {
StopEmulation();
supervision_load_state(romName, 0);
ResumeEmulation();
}
break;
case IDM_WEBSITE:
ShellExecute(NULL, _T("open"), _T("https://github.com/infval/potator"), NULL, NULL, SW_SHOWNORMAL);
break;
case IDM_ABOUT:
MessageBox(NULL, _T("Potator 1.0 (fork)"), szClassName, MB_ICONEXCLAMATION | MB_OK);
break;
case IDM_FULLSCREEN:
ToggleFullscreen();
break;
case IDM_SIZE1:
case IDM_SIZE2:
case IDM_SIZE3:
case IDM_SIZE4:
case IDM_SIZE5:
case IDM_SIZE6:
windowScale = wmId - IDM_SIZE1 + 1;
UpdateWindowSize();
break;
case IDM_CONTROL_CONFIG:
CreateControlConfigWindow(hWnd);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
}
break;
case WM_DROPFILES:
{
execute = FALSE;
Sleep(1000 / UPDATE_RATE * 4); // Wait for the end of execution
HDROP hDrop = (HDROP)wParam;
TCHAR szFileName[MAX_PATH] = _T("");
DragQueryFile(hDrop, 0, szFileName, MAX_PATH);
DragFinish(hDrop);
{
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;
}
if (LoadROM(szFileName) == 0) {
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);
}

View File

@ -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

View File

@ -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