#include "SDL.h" #include "GpMain.h" #include "GpAudioDriverFactory.h" #include "GpDisplayDriverFactory.h" #include "GpGlobalConfig.h" #include "GpFiber_Win32.h" #include "GpFiber_SDL.h" #include "GpFileSystem_Win32.h" #include "GpLogDriver_Win32.h" #include "GpFontHandlerFactory.h" #include "GpInputDriverFactory.h" #include "GpAppInterface.h" #include "GpSystemServices_Win32.h" #include "GpVOSEvent.h" #include "IGpVOSEventQueue.h" #include "HostFileSystem.h" #include "HostThreadEvent.h" #include "GpWindows.h" #include "resource.h" #include #include #include GpWindowsGlobals g_gpWindowsGlobals; extern "C" __declspec(dllimport) IGpAudioDriver *GpDriver_CreateAudioDriver_XAudio2(const GpAudioDriverProperties &properties); extern "C" __declspec(dllimport) IGpInputDriver *GpDriver_CreateInputDriver_XInput(const GpInputDriverProperties &properties); extern "C" __declspec(dllimport) IGpFontHandler *GpDriver_CreateFontHandler_FreeType2(const GpFontHandlerProperties &properties); IGpDisplayDriver *GpDriver_CreateDisplayDriver_SDL_GL2(const GpDisplayDriverProperties &properties); static void PostMouseEvent(IGpVOSEventQueue *eventQueue, GpMouseEventType_t eventType, GpMouseButton_t button, int32_t x, int32_t y, float pixelScaleX, float pixelScaleY) { if (GpVOSEvent *evt = eventQueue->QueueEvent()) { evt->m_eventType = GpVOSEventTypes::kMouseInput; GpMouseInputEvent &mEvent = evt->m_event.m_mouseInputEvent; mEvent.m_button = button; mEvent.m_x = x; mEvent.m_y = y; mEvent.m_eventType = eventType; if (pixelScaleX != 1.0f) mEvent.m_x = static_cast(static_cast(x) / pixelScaleX); if (pixelScaleY != 1.0f) mEvent.m_y = static_cast(static_cast(y) / pixelScaleX); } } static bool IdentifyVKey(const WPARAM &wparam, const LPARAM &lparam, GpKeyIDSubset_t &outSubset, GpKeyboardInputEvent::KeyUnion &outKey) { switch (wparam) { case VK_ESCAPE: outSubset = GpKeyIDSubsets::kSpecial; outKey.m_specialKey = GpKeySpecials::kEscape; break; case VK_PRINT: outSubset = GpKeyIDSubsets::kSpecial; outKey.m_specialKey = GpKeySpecials::kPrintScreen; break; case VK_SCROLL: outSubset = GpKeyIDSubsets::kSpecial; outKey.m_specialKey = GpKeySpecials::kScrollLock; break; case VK_PAUSE: outSubset = GpKeyIDSubsets::kSpecial; outKey.m_specialKey = GpKeySpecials::kPause; break; case VK_INSERT: outSubset = GpKeyIDSubsets::kSpecial; outKey.m_specialKey = GpKeySpecials::kInsert; break; case VK_HOME: outSubset = GpKeyIDSubsets::kSpecial; outKey.m_specialKey = GpKeySpecials::kHome; break; case VK_PRIOR: outSubset = GpKeyIDSubsets::kSpecial; outKey.m_specialKey = GpKeySpecials::kPageUp; break; case VK_NEXT: outSubset = GpKeyIDSubsets::kSpecial; outKey.m_specialKey = GpKeySpecials::kPageDown; break; case VK_DELETE: outSubset = GpKeyIDSubsets::kSpecial; outKey.m_specialKey = GpKeySpecials::kDelete; break; case VK_TAB: outSubset = GpKeyIDSubsets::kSpecial; outKey.m_specialKey = GpKeySpecials::kTab; break; case VK_END: outSubset = GpKeyIDSubsets::kSpecial; outKey.m_specialKey = GpKeySpecials::kEnd; break; case VK_BACK: outSubset = GpKeyIDSubsets::kSpecial; outKey.m_specialKey = GpKeySpecials::kBackspace; break; case VK_CAPITAL: outSubset = GpKeyIDSubsets::kSpecial; outKey.m_specialKey = GpKeySpecials::kCapsLock; break; case VK_RETURN: outSubset = GpKeyIDSubsets::kSpecial; outKey.m_specialKey = GpKeySpecials::kEnter; break; case VK_SHIFT: { UINT vkey = MapVirtualKeyW((lparam >> 16) & 0xff, MAPVK_VSC_TO_VK_EX); if (vkey == VK_LSHIFT || vkey == VK_SHIFT) { outSubset = GpKeyIDSubsets::kSpecial; outKey.m_specialKey = GpKeySpecials::kLeftShift; } else if (vkey == VK_RSHIFT) { outSubset = GpKeyIDSubsets::kSpecial; outKey.m_specialKey = GpKeySpecials::kRightShift; } else return false; } break; case VK_RSHIFT: outSubset = GpKeyIDSubsets::kSpecial; outKey.m_specialKey = GpKeySpecials::kRightShift; break; case VK_CONTROL: outSubset = GpKeyIDSubsets::kSpecial; if (lparam & 0x01000000) outKey.m_specialKey = GpKeySpecials::kRightCtrl; else outKey.m_specialKey = GpKeySpecials::kLeftCtrl; break; case VK_MENU: outSubset = GpKeyIDSubsets::kSpecial; if (lparam & 0x01000000) outKey.m_specialKey = GpKeySpecials::kRightAlt; else outKey.m_specialKey = GpKeySpecials::kLeftAlt; break; case VK_NUMLOCK: outSubset = GpKeyIDSubsets::kSpecial; outKey.m_specialKey = GpKeySpecials::kNumLock; break; case VK_NUMPAD0: case VK_NUMPAD1: case VK_NUMPAD2: case VK_NUMPAD3: case VK_NUMPAD4: case VK_NUMPAD5: case VK_NUMPAD6: case VK_NUMPAD7: case VK_NUMPAD8: case VK_NUMPAD9: outSubset = GpKeyIDSubsets::kNumPadNumber; outKey.m_numPadNumber = static_cast(wparam - VK_NUMPAD0); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': outSubset = GpKeyIDSubsets::kASCII; outKey.m_asciiChar = static_cast(wparam); break; case VK_F1: case VK_F2: case VK_F3: case VK_F4: case VK_F5: case VK_F6: case VK_F7: case VK_F8: case VK_F9: case VK_F10: case VK_F11: case VK_F12: case VK_F13: case VK_F14: case VK_F15: case VK_F16: case VK_F17: case VK_F18: case VK_F19: case VK_F20: case VK_F21: case VK_F22: case VK_F23: case VK_F24: outSubset = GpKeyIDSubsets::kFKey; outKey.m_fKey = static_cast(wparam - VK_F1 + 1); break; case VK_OEM_COMMA: outSubset = GpKeyIDSubsets::kASCII; outKey.m_asciiChar = ','; break; case VK_OEM_MINUS: outSubset = GpKeyIDSubsets::kASCII; outKey.m_asciiChar = '-'; break; case VK_OEM_PERIOD: outSubset = GpKeyIDSubsets::kASCII; outKey.m_asciiChar = '.'; break; case VK_OEM_PLUS: outSubset = GpKeyIDSubsets::kASCII; outKey.m_asciiChar = '+'; break; case VK_UP: outSubset = GpKeyIDSubsets::kSpecial; outKey.m_specialKey = GpKeySpecials::kUpArrow; break; case VK_DOWN: outSubset = GpKeyIDSubsets::kSpecial; outKey.m_specialKey = GpKeySpecials::kDownArrow; break; case VK_LEFT: outSubset = GpKeyIDSubsets::kSpecial; outKey.m_specialKey = GpKeySpecials::kLeftArrow; break; case VK_RIGHT: outSubset = GpKeyIDSubsets::kSpecial; outKey.m_specialKey = GpKeySpecials::kRightArrow; break; default: { if (wparam >= VK_OEM_1 && wparam <= VK_OEM_102) { UINT charCode = MapVirtualKeyW(static_cast(wparam), MAPVK_VK_TO_CHAR); if (charCode == 0) return false; if (charCode < 128) { outSubset = GpKeyIDSubsets::kASCII; outKey.m_asciiChar = static_cast(charCode); break; } else { outSubset = GpKeyIDSubsets::kUnicode; outKey.m_unicodeChar = charCode;; break; } } } return false; } return true; } static void PostKeyboardEvent(IGpVOSEventQueue *eventQueue, GpKeyboardInputEventType_t eventType, GpKeyIDSubset_t subset, const GpKeyboardInputEvent::KeyUnion &key, uint32_t repeatCount) { if (GpVOSEvent *evt = eventQueue->QueueEvent()) { evt->m_eventType = GpVOSEventTypes::kKeyboardInput; GpKeyboardInputEvent &mEvent = evt->m_event.m_keyboardInputEvent; mEvent.m_key = key; mEvent.m_eventType = eventType; mEvent.m_keyIDSubset = subset; mEvent.m_repeatCount = repeatCount; } } static void TranslateWindowsMessage(const MSG *msg, IGpVOSEventQueue *eventQueue, float pixelScaleX, float pixelScaleY) { WPARAM wParam = msg->wParam; LPARAM lParam = msg->lParam; switch (msg->message) { case WM_LBUTTONDOWN: PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kLeft, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY); break; case WM_LBUTTONUP: PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kLeft, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY); break; case WM_MBUTTONDOWN: PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kMiddle, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY); break; case WM_MBUTTONUP: PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kMiddle, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY); break; case WM_RBUTTONDOWN: PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kRight, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY); break; case WM_RBUTTONUP: PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kRight, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY); break; case WM_XBUTTONDOWN: if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kX1, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY); else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON2) PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kX2, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY); break; case WM_XBUTTONUP: if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kX1, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY); else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON2) PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kX2, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY); break; case WM_MOUSEMOVE: PostMouseEvent(eventQueue, GpMouseEventTypes::kMove, GpMouseButtons::kNone, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY); break; case WM_MOUSELEAVE: PostMouseEvent(eventQueue, GpMouseEventTypes::kLeave, GpMouseButtons::kNone, 0, 0, pixelScaleX, pixelScaleY); break; case WM_KEYDOWN: case WM_SYSKEYDOWN: { GpKeyIDSubset_t subset; GpKeyboardInputEvent::KeyUnion key; bool isRepeat = ((lParam & 0x40000000) != 0); const GpKeyboardInputEventType_t keyEventType = isRepeat ? GpKeyboardInputEventTypes::kAuto : GpKeyboardInputEventTypes::kDown; if (IdentifyVKey(wParam, lParam, subset, key)) PostKeyboardEvent(eventQueue, keyEventType, subset, key, static_cast(lParam & 0xffff)); (void)TranslateMessage(msg); } break; case WM_KEYUP: case WM_SYSKEYUP: { GpKeyIDSubset_t subset; GpKeyboardInputEvent::KeyUnion key; if (IdentifyVKey(wParam, lParam, subset, key)) PostKeyboardEvent(eventQueue, GpKeyboardInputEventTypes::kUp, subset, key, (lParam & 0xffff)); } break; case WM_CHAR: case WM_UNICHAR: { bool isRepeat = ((lParam & 0x4000000) != 0); const GpKeyboardInputEventType_t keyEventType = isRepeat ? GpKeyboardInputEventTypes::kAutoChar : GpKeyboardInputEventTypes::kDownChar; GpKeyboardInputEvent::KeyUnion key; GpKeyIDSubset_t subset = GpKeyIDSubsets::kASCII; if (wParam <= 128) key.m_asciiChar = static_cast(wParam); else { subset = GpKeyIDSubsets::kUnicode; key.m_unicodeChar = static_cast(wParam); } PostKeyboardEvent(eventQueue, keyEventType, subset, key, (lParam & 0xffff)); } break; case WM_QUIT: { if (GpVOSEvent *evt = eventQueue->QueueEvent()) evt->m_eventType = GpVOSEventTypes::kQuit; } break; default: break; } } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { if (SDL_Init(SDL_INIT_VIDEO) < 0) return -1; LPWSTR cmdLine = GetCommandLineW(); int nArgs; LPWSTR *cmdLineArgs = CommandLineToArgvW(cmdLine, &nArgs); for (int i = 1; i < nArgs; i++) { if (!wcscmp(cmdLineArgs[i], L"-diagnostics")) GpLogDriver_Win32::Init(); } IGpLogDriver *logger = GpLogDriver_Win32::GetInstance(); GpAppInterface_Get()->PL_HostFileSystem_SetInstance(GpFileSystem_Win32::GetInstance()); GpAppInterface_Get()->PL_HostSystemServices_SetInstance(GpSystemServices_Win32::GetInstance()); GpAppInterface_Get()->PL_HostLogDriver_SetInstance(GpLogDriver_Win32::GetInstance()); g_gpWindowsGlobals.m_hInstance = hInstance; g_gpWindowsGlobals.m_hPrevInstance = hPrevInstance; g_gpWindowsGlobals.m_cmdLine = cmdLine; g_gpWindowsGlobals.m_cmdLineArgc = nArgs; g_gpWindowsGlobals.m_cmdLineArgv = cmdLineArgs; g_gpWindowsGlobals.m_nCmdShow = nCmdShow; g_gpWindowsGlobals.m_baseDir = GpFileSystem_Win32::GetInstance()->GetBasePath(); g_gpWindowsGlobals.m_hwnd = nullptr; //g_gpWindowsGlobals.m_hIcon = LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_ICON1)); //g_gpWindowsGlobals.m_hIconSm = LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_ICON2)); g_gpWindowsGlobals.m_translateWindowsMessageFunc = TranslateWindowsMessage; g_gpGlobalConfig.m_displayDriverType = EGpDisplayDriverType_SDL_GL2; g_gpGlobalConfig.m_audioDriverType = EGpAudioDriverType_XAudio2; g_gpGlobalConfig.m_fontHandlerType = EGpFontHandlerType_FreeType2; EGpInputDriverType inputDrivers[] = { EGpInputDriverType_XInput }; g_gpGlobalConfig.m_inputDriverTypes = inputDrivers; g_gpGlobalConfig.m_numInputDrivers = sizeof(inputDrivers) / sizeof(inputDrivers[0]); g_gpGlobalConfig.m_osGlobals = &g_gpWindowsGlobals; g_gpGlobalConfig.m_logger = logger; GpDisplayDriverFactory::RegisterDisplayDriverFactory(EGpDisplayDriverType_SDL_GL2, GpDriver_CreateDisplayDriver_SDL_GL2); GpAudioDriverFactory::RegisterAudioDriverFactory(EGpAudioDriverType_XAudio2, GpDriver_CreateAudioDriver_XAudio2); GpInputDriverFactory::RegisterInputDriverFactory(EGpInputDriverType_XInput, GpDriver_CreateInputDriver_XInput); GpFontHandlerFactory::RegisterFontHandlerFactory(EGpFontHandlerType_FreeType2, GpDriver_CreateFontHandler_FreeType2); if (logger) logger->Printf(IGpLogDriver::Category_Information, "SDL environment configured, starting up"); int returnCode = GpMain::Run(); if (logger) logger->Printf(IGpLogDriver::Category_Information, "SDL environment exited with code %i, cleaning up", returnCode); LocalFree(cmdLineArgs); return returnCode; }