27 #include "precompiled.h"
49 #pragma comment(lib, "user32.lib")
50 #pragma comment(lib, "gdi32.lib")
67 static HWND
g_hWnd = (HWND)INVALID_HANDLE_VALUE;
71 static HDC
g_hDC = (HDC)INVALID_HANDLE_VALUE;
85 bool Change(HDC hDC,
float gamma_r,
float gamma_g,
float gamma_b)
134 for(
u16 i = 0; i < 256; i++)
135 ramp[i] =
u16(i << 8);
139 for(
int i = 0; i < 256; i++)
141 const double val = pow(i/255.0, (
double)gamma);
142 const double clamped = std::max(0.0, std::min(val, 1.0-DBL_EPSILON));
146 ENSURE(ramp[255] == 0xFFFF);
154 BOOL ok = SetDeviceGammaRamp(
g_hDC, ramps);
160 ok = SetDeviceGammaRamp(
g_hDC, ramps);
164 debug_printf(L
"SetDeviceGammaRamp failed twice. Oh well.\n");
192 DWORD windowStyle = fullscreen? WS_POPUP : WS_POPUPWINDOW|WS_CAPTION|WS_MINIMIZEBOX;
193 windowStyle |= WS_VISIBLE;
194 windowStyle |= WS_CLIPCHILDREN|WS_CLIPSIBLINGS;
199 windowStyle |= WS_SIZEBOX|WS_MAXIMIZEBOX;
205 const DWORD previousWindowState = GetWindowLongW(previousWindow, GWL_STYLE);
206 windowStyle |= (previousWindowState & WS_MAXIMIZE);
222 if(AdjustWindowRectEx(&r, windowStyle, FALSE, 0))
239 const HINSTANCE hInst = GetModuleHandle(0);
243 memset(&wc, 0,
sizeof(wc));
247 wc.lpszClassName = L
"WSDL{55752F43-0241-492C-8648-C7243397FCE4}";
248 wc.hInstance = hInst;
249 ATOM class_atom = RegisterClassW(&wc);
258 HWND hWnd = CreateWindowExW(WS_EX_APPWINDOW, (LPCWSTR)(uintptr_t)class_atom, L
"wsdl", windowStyle, 0, 0, w, h, 0, 0, hInst, 0);
279 static HGLRC
hGLRC = (HGLRC)INVALID_HANDLE_VALUE;
291 depthBufferBits = value;
295 stencilBufferBits = value;
299 vsyncEnabled = value;
319 if(w > cur_w || h > cur_h)
323 if(fullscreen && (w != cur_w || h != cur_h))
332 const DWORD dwFlags = PFD_SUPPORT_OPENGL|PFD_DRAW_TO_WINDOW|PFD_DOUBLEBUFFER;
333 BYTE cColourBits = (BYTE)bpp;
340 const BYTE cAccumBits = 0;
341 const BYTE cDepthBits = (BYTE)depthBufferBits;
342 const BYTE cStencilBits = (BYTE)stencilBufferBits;
343 const BYTE cAuxBuffers = 0;
345 PIXELFORMATDESCRIPTOR pfd =
347 sizeof(PIXELFORMATDESCRIPTOR),
351 cColourBits, 0, 0, 0, 0, 0, 0,
353 cAccumBits, 0, 0, 0, 0,
364 const int pf = ChoosePixelFormat(hDC, &pfd);
379 memset(&dm, 0,
sizeof(dm));
380 dm.dmSize =
sizeof(
dm);
381 WARN_IF_FALSE(EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &dm));
382 const int cur_w = (int)dm.dmPelsWidth, cur_h = (
int)dm.dmPelsHeight;
385 dm.dmBitsPerPel = bpp;
386 dm.dmFields = DM_BITSPERPEL;
390 dm.dmPelsWidth = (
DWORD)w;
391 dm.dmPelsHeight = (
DWORD)h;
392 dm.dmFields |= DM_PELSWIDTH|DM_PELSHEIGHT;
418 UINT swp_flags = SWP_FRAMECHANGED|SWP_NOZORDER|SWP_NOACTIVATE;
420 swp_flags |= SWP_NOMOVE;
428 ShowWindow(
g_hWnd, SW_RESTORE);
429 status = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
433 status = ChangeDisplaySettings(0, 0);
436 ENSURE(status == DISP_CHANGE_SUCCESSFUL);
443 pwglSwapIntervalEXT(vsyncEnabled);
462 LONG status = ChangeDisplaySettings(0, 0);
463 ENSURE(status == DISP_CHANGE_SUCCESSFUL);
470 hGLRC = (HGLRC)INVALID_HANDLE_VALUE;
473 g_hWnd = (HWND)INVALID_HANDLE_VALUE;
474 g_hDC = (HDC)INVALID_HANDLE_VALUE;
493 for(WmiInstances::iterator it = instances.begin(); it != instances.end(); ++it)
495 if((*it)[L
"Availability"].intVal != 8)
519 typedef std::queue<SDL_Event>
Queue;
531 ev = g_queue.front();
558 for(
size_t i = 0; i <
ARRAY_SIZE(g_SDLKeyForVK); i++)
559 g_SDLKeyForVK[i] = SDLK_UNKNOWN;
561 g_SDLKeyForVK[VK_BACK] = SDLK_BACKSPACE;
562 g_SDLKeyForVK[VK_TAB] = SDLK_TAB;
563 g_SDLKeyForVK[VK_CLEAR] = SDLK_CLEAR;
564 g_SDLKeyForVK[VK_RETURN] = SDLK_RETURN;
565 g_SDLKeyForVK[VK_PAUSE] = SDLK_PAUSE;
566 g_SDLKeyForVK[VK_ESCAPE] = SDLK_ESCAPE;
567 g_SDLKeyForVK[VK_SPACE] = SDLK_SPACE;
568 g_SDLKeyForVK[VK_OEM_7] = SDLK_QUOTE;
569 g_SDLKeyForVK[VK_OEM_COMMA] = SDLK_COMMA;
570 g_SDLKeyForVK[VK_OEM_MINUS] = SDLK_MINUS;
571 g_SDLKeyForVK[VK_OEM_PERIOD] = SDLK_PERIOD;
572 g_SDLKeyForVK[VK_OEM_2] = SDLK_SLASH;
573 g_SDLKeyForVK[VK_OEM_1] = SDLK_SEMICOLON;
574 g_SDLKeyForVK[VK_OEM_PLUS] = SDLK_EQUALS;
575 g_SDLKeyForVK[VK_OEM_4] = SDLK_LEFTBRACKET;
576 g_SDLKeyForVK[VK_OEM_5] = SDLK_BACKSLASH;
577 g_SDLKeyForVK[VK_OEM_6] = SDLK_RIGHTBRACKET;
578 g_SDLKeyForVK[VK_OEM_3] = SDLK_BACKQUOTE;
579 g_SDLKeyForVK[VK_OEM_8] = SDLK_BACKQUOTE;
582 const int VK_0 =
'0';
583 for(
int i = 0; i < 10; i++)
584 g_SDLKeyForVK[VK_0+i] = (SDLKey)(SDLK_0+i);
585 const int VK_A =
'A';
586 for(
int i = 0; i < 26; i++)
587 g_SDLKeyForVK[VK_A+i] = (SDLKey)(SDLK_a+i);
589 g_SDLKeyForVK[VK_DELETE] = SDLK_DELETE;
591 for(
int i = 0; i < 10; i++)
592 g_SDLKeyForVK[VK_NUMPAD0+i] = (SDLKey)(SDLK_KP0+i);
594 g_SDLKeyForVK[VK_DECIMAL] = SDLK_KP_PERIOD;
595 g_SDLKeyForVK[VK_DIVIDE] = SDLK_KP_DIVIDE;
596 g_SDLKeyForVK[VK_MULTIPLY] = SDLK_KP_MULTIPLY;
597 g_SDLKeyForVK[VK_SUBTRACT] = SDLK_KP_MINUS;
598 g_SDLKeyForVK[VK_ADD] = SDLK_KP_PLUS;
600 g_SDLKeyForVK[VK_UP] = SDLK_UP;
601 g_SDLKeyForVK[VK_DOWN] = SDLK_DOWN;
602 g_SDLKeyForVK[VK_RIGHT] = SDLK_RIGHT;
603 g_SDLKeyForVK[VK_LEFT] = SDLK_LEFT;
604 g_SDLKeyForVK[VK_INSERT] = SDLK_INSERT;
605 g_SDLKeyForVK[VK_HOME] = SDLK_HOME;
606 g_SDLKeyForVK[VK_END] = SDLK_END;
607 g_SDLKeyForVK[VK_PRIOR] = SDLK_PAGEUP;
608 g_SDLKeyForVK[VK_NEXT] = SDLK_PAGEDOWN;
610 for(
int i = 0; i < 12; i++)
611 g_SDLKeyForVK[VK_F1+i] = (SDLKey)(SDLK_F1+i);
613 g_SDLKeyForVK[VK_NUMLOCK] = SDLK_NUMLOCK;
614 g_SDLKeyForVK[VK_CAPITAL] = SDLK_CAPSLOCK;
615 g_SDLKeyForVK[VK_SCROLL] = SDLK_SCROLLOCK;
616 g_SDLKeyForVK[VK_RSHIFT] = SDLK_RSHIFT;
617 g_SDLKeyForVK[VK_LSHIFT] = SDLK_LSHIFT;
618 g_SDLKeyForVK[VK_SHIFT] = SDLK_LSHIFT;
619 g_SDLKeyForVK[VK_RCONTROL] = SDLK_RCTRL;
620 g_SDLKeyForVK[VK_LCONTROL] = SDLK_LCTRL;
621 g_SDLKeyForVK[VK_CONTROL] = SDLK_LCTRL;
622 g_SDLKeyForVK[VK_RMENU] = SDLK_RALT;
623 g_SDLKeyForVK[VK_LMENU] = SDLK_LALT;
624 g_SDLKeyForVK[VK_MENU] = SDLK_LALT;
625 g_SDLKeyForVK[VK_RWIN] = SDLK_RSUPER;
626 g_SDLKeyForVK[VK_LWIN] = SDLK_LSUPER;
628 g_SDLKeyForVK[VK_HELP] = SDLK_HELP;
630 g_SDLKeyForVK[VK_PRINT] = SDLK_PRINT;
632 g_SDLKeyForVK[VK_SNAPSHOT] = SDLK_PRINT;
633 g_SDLKeyForVK[VK_CANCEL] = SDLK_BREAK;
634 g_SDLKeyForVK[VK_APPS] = SDLK_MENU;
640 if(!(0 <= vk && vk < 256))
645 return g_SDLKeyForVK[vk];
672 if(sdlk != SDLK_UNKNOWN)
673 keys[sdlk] = (
Uint8)fDown;
682 const UINT scancode = flags;
686 int output_count = ToUnicode(vk, scancode, key_states, wchars,
ARRAY_SIZE(wchars), 0);
690 for(
int i = 0; i < output_count; i++)
694 else if(output_count == -1)
698 else if(output_count == 0)
711 *num_keys = SDLK_LAST;
785 app_state =
Uint8(app_state | changed_app_state);
787 app_state =
Uint8(app_state & ~changed_app_state);
790 if((old_app_state & changed_app_state) != (app_state & changed_app_state))
798 Uint8 changed_app_state;
801 if(state != WA_INACTIVE && !fMinimized)
812 ShowWindow(
g_hWnd, SW_RESTORE);
813 const LONG ret = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
814 ENSURE(ret == DISP_CHANGE_SUCCESSFUL);
833 const LONG ret = ChangeDisplaySettings(0, 0);
834 ENSURE(ret == DISP_CHANGE_SUCCESSFUL);
875 ENSURE(
unsigned(x|y) <= USHRT_MAX);
887 ENSURE(
unsigned(x|y) <= USHRT_MAX);
904 if(mouse_x == x && mouse_y == y)
915 screen_pt.x = (
LONG)client_x;
916 screen_pt.y = (
LONG)client_y;
927 screen_pt.x = (
LONG)screen_x;
928 screen_pt.y = (
LONG)screen_y;
937 client_pt = screen_pt;
938 const int ret = MapWindowPoints(HWND_DESKTOP,
g_hWnd, &client_pt, 1);
939 ENSURE(ret != 0 || GetLastError() == 0);
944 if(!PtInRect(&client_rect, client_pt))
948 if(WindowFromPoint(screen_pt) !=
g_hWnd)
971 if(!GetCursorPos(&screen_pt))
1003 case WM_RBUTTONDOWN:
1011 case WM_MBUTTONDOWN:
1019 case WM_XBUTTONDOWN:
1031 static int outstanding_press_events;
1035 if(++outstanding_press_events > 0)
1036 (void)SetCapture(
g_hWnd);
1041 if(--outstanding_press_events <= 0)
1044 outstanding_press_events = 0;
1060 if (uMsg == WM_XBUTTONDOWN || uMsg == WM_XBUTTONUP)
1097 ENSURE(x >= 0 && y >= 0);
1100 const int client_x = x, client_y = y;
1113 if(cursor_visible != toggle)
1115 (void)ShowCursor(toggle);
1116 cursor_visible = toggle;
1119 return cursor_visible;
1135 POINT upperLeft = { clientRect.
left, clientRect.
top };
1137 POINT lowerRight = { clientRect.
right, clientRect.
bottom };
1139 const RECT screenRect = { upperLeft.x, upperLeft.y, lowerRight.x, lowerRight.y };
1158 static int lastClientWidth, lastClientHeight;
1159 if(lastClientWidth == clientWidth && lastClientHeight == clientHeight)
1161 lastClientWidth = clientWidth;
1162 lastClientHeight = clientHeight;
1173 if(clientWidth == 0 && clientHeight == 0)
1224 g_hDC = (HDC)INVALID_HANDLE_VALUE;
1225 g_hWnd = (HWND)INVALID_HANDLE_VALUE;
1233 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
1271 return DefWindowProcW(hWnd, uMsg, wParam, lParam);
1287 HANDLE_MSG(hWnd, WM_DESTROY,
OnDestroy);
1294 HANDLE_MSG(hWnd, WM_SYSKEYUP ,
OnKey);
1295 HANDLE_MSG(hWnd, WM_KEYUP ,
OnKey);
1296 HANDLE_MSG(hWnd, WM_SYSKEYDOWN,
OnKey);
1297 HANDLE_MSG(hWnd, WM_KEYDOWN ,
OnKey);
1301 HANDLE_MSG(hWnd, WM_SIZE,
OnSize);
1304 case WM_LBUTTONDOWN:
1306 case WM_RBUTTONDOWN:
1308 case WM_MBUTTONDOWN:
1310 case WM_XBUTTONDOWN:
1312 return OnMouseButton(hWnd, uMsg, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), (
UINT)wParam);
1320 return DefWindowProcW(hWnd, uMsg, wParam, lParam);
1335 while(PeekMessageW(&msg, 0, 0, 0, PM_REMOVE))
1337 (void)DispatchMessageW(&msg);
1369 return (
u16)(((x & 0xff) << 8) | (x >> 8));
1378 ((x << 8) & 0x00ff0000) |
1379 ((x >> 8) & 0x0000ff00);
1386 const u32 lo = (
u32)(x & 0xFFFFFFFF);
1387 const u32 hi = (
u32)(x >> 32);
1416 HANDLE h = CreateSemaphore(0, cnt, std::numeric_limits<LONG>::max(), 0);
1429 return ReleaseSemaphore(h, 1, 0);
1435 return WaitForSingleObject(h, INFINITE);
1453 return GetTickCount();
1532 (void)_wfreopen_s(&f,
OsString(pathname).c_str(), L
"wt", stdout);
1533 if(GetLastError() == ERROR_ALREADY_EXISTS)
1544 #if CONFIG_ENABLE_CHECKS
1547 setvbuf(stdout, 0, _IONBF, 0);
1569 #endif // #if CONFIG2_WSDL
int SDL_PollEvent(SDL_Event *ev)
static unsigned mouse_buttons
static HANDLE HANDLE_from_sem(SDL_sem *s)
u16 SDL_Swap16(const u16 x)
static LRESULT OnMouseButton(HWND hWnd, UINT uMsg, int client_x, int client_y, UINT flags)
static SDLKey SDLKeyFromVK(int vk)
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
int SDL_JoystickNumAxes(SDL_Joystick *joystick)
int SDL_ShowCursor(int toggle)
Uint8 SDL_GetMouseState(int *x, int *y)
int SDL_JoystickEventState(int state)
static void QueueMouseEvent(int x, int y)
some WinAPI functions SetLastError(0) on success, which is bad because it can hide previous errors...
void SDL_WarpMouse(int x, int y)
static ModuleInitState initState
static Uint8 keys[SDLK_LAST]
void SDL_Delay(Uint32 ms)
SDL_GrabMode SDL_WM_GrabInput(SDL_GrabMode mode)
bool wutil_IsValidHandle(H h)
static void mouse_UpdatePosition(int x, int y)
SDL_VideoInfo * SDL_GetVideoInfo()
static bool DequeueEvent(SDL_Event &ev)
static SDL_sem * sem_from_HANDLE(HANDLE h)
void * SDL_GL_GetProcAddress(const char *name)
u16 u16_from_double(double in)
convert double to u16; verifies number is in range.
bool Change(HDC hDC, float gamma_r, float gamma_g, float gamma_b)
static void Compute(float gamma, u16 *ramp)
WINGDIAPI BOOL WINAPI wglDeleteContext(HGLRC)
void SDL_GL_SwapBuffers()
int SDL_GL_SetAttribute(SDL_GLattr attr, int value)
std::vector< WmiInstance > WmiInstances
SDL_MouseMotionEvent motion
static void QueueEvent(const SDL_Event &ev)
static void active_ChangeState(SdlActivationType type, Uint8 changed_app_state)
static Status wsdl_Init()
void SDL_DestroySemaphore(SDL_sem *sem)
static void QueueActiveEvent(SdlActivationType type, size_t changed_app_state)
static LRESULT OnPaint(HWND hWnd)
#define ENSURE(expr)
ensure the expression <expr> evaluates to non-zero.
void SDL_WM_SetCaption(const char *title, const char *icon)
#define UNUSED2(param)
mark a function local variable or parameter as unused and avoid the corresponding compiler warning...
intptr_t ModuleInitState
initialization state of a module (class, source file, etc.) must be initialized to zero (e...
static LRESULT OnMouseWheel(HWND hWnd, int screen_x, int screen_y, int zDelta, UINT fwKeys)
static void wnd_UpdateWindowDimensions(DWORD windowStyle, int &w, int &h)
WINGDIAPI HGLRC WINAPI wglCreateContext(HDC)
static int stencilBufferBits
SDL_MouseButtonEvent button
static int depthBufferBits
Status wmi_GetClassInstances(const wchar_t *className, WmiInstances &instances)
get all instances of the requested class.
static GammaRamp gammaRamp
static void QueueQuitEvent()
u64 SDL_Swap64(const u64 x)
#define UNREACHABLE
"unreachable code" helpers
Uint8 * SDL_GetKeyState(int *num_keys)
Sint16 SDL_JoystickGetAxis(SDL_Joystick *joystick, int axis)
static HWND wnd_CreateWindow(int w, int h)
static bool mouse_GetCoords(int screen_x, int screen_y, int &x, int &y)
i64 Status
Error handling system.
WINIT_REGISTER_EARLY_SHUTDOWN(wsdl_Shutdown)
SDL_Joystick * SDL_JoystickOpen(int device_index)
SDL_Surface * SDL_GetVideoSurface()
WINGDIAPI PROC WINAPI wglGetProcAddress(LPCSTR)
#define DEBUG_WARN_ERR(status)
display the error dialog with text corresponding to the given error code.
static void QueueKeyEvent(Uint8 type, SDLKey sdlk, WCHAR unicode_char)
static LRESULT OnKey(HWND hWnd, UINT vk, BOOL fDown, int cRepeat, UINT flags)
int SDL_Init(Uint32 flags)
int SDL_EnableUNICODE(int enable)
SDL_sem * SDL_CreateSemaphore(int cnt)
Status ModuleShutdown(volatile ModuleInitState *initState, void(*shutdown)())
calls a user-defined shutdown function if initState is "initialized".
WINIT_REGISTER_LATE_INIT(wsdl_Init)
const char * SDL_JoystickName(int device_index)
std::queue< SDL_Event > Queue
bool ogl_HaveExtension(const char *ext)
check if an extension is supported by the OpenGL implementation.
static LRESULT OnDestroy(HWND hWnd)
static bool video_NeedsChange(int w, int h, int cur_w, int cur_h, bool fullscreen)
u32 SDL_Swap32(const u32 x)
Path ChangeExtension(Path extension) const
static void video_Shutdown()
OsPath sys_ExecutablePathname()
#define WARN_IF_FALSE(expression)
void ogl_Init()
initialization: import extension function pointers and do feature detect.
static LRESULT OnActivate(HWND hWnd, UINT state, HWND hWndActDeact, BOOL fMinimized)
static Status wsdl_Shutdown()
static DefWindowProcDisposition OnSysCommand(WPARAM wParam)
int SDL_PushEvent(SDL_Event *ev)
int SDL_InitSubSystem(Uint32 flags)
static BOOL OnEraseBkgnd(HWND hWnd, HDC hDC)
static void QueueButtonEvent(int button, int state, int x, int y)
#define NODEFAULT
convenient specialization of UNREACHABLE for switch statements whose default can never be reached...
int SDL_SetGamma(float r, float g, float b)
static void video_SetPixelFormat(HDC hDC, int bpp)
static bool ResizeEventEnabled(int clientWidth, int clientHeight)
int SDL_SemPost(SDL_sem *sem)
SDL_Surface * SDL_SetVideoMode(int w, int h, int bpp, Uint32 flags)
static void OnSize(HWND hWnd, UINT state, int clientWidth, int clientHeight)
static POINT mouse_ScreenFromClient(int client_x, int client_y)
static void mouse_Update()
Status ModuleInit(volatile ModuleInitState *initState, Status(*init)())
calls a user-defined init function if initState is zero.
WINGDIAPI BOOL WINAPI wglMakeCurrent(HDC, HGLRC)
int SDL_SemWait(SDL_sem *sem)
static LRESULT CALLBACK OnMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
static SDLKey g_SDLKeyForVK[256]
static void RedirectStdout()
static void key_ResetAll()
void debug_printf(const wchar_t *fmt,...)
write a formatted string to the debug channel, subject to filtering (see below).
static std::string OsString(const OsPath &path)
static RECT ClientRect(HWND hWnd)
static DWORD wnd_ChooseWindowStyle(bool fullscreen, HWND previousWindow=(HWND) INVALID_HANDLE_VALUE)