From e48e330db7656ea99c8c32ffb578e4ae45ed76c1 Mon Sep 17 00:00:00 2001 From: historic_bruno Date: Fri, 20 Feb 2015 05:52:18 +0000 Subject: [PATCH] Sets SDL2 as default and only build option on Windows. Removes remnants of WSDL. Refs #2041 This was SVN commit r16357. --- build/premake/extern_libs4.lua | 13 +- build/workspaces/update-workspaces.bat | 2 +- source/lib/config2.h | 16 +- source/lib/external_libraries/libsdl.h | 9 +- source/lib/sysdep/gfx.cpp | 3 +- source/lib/sysdep/os/win/wsdl.cpp | 1589 ------------------------ source/lib/sysdep/os/win/wsdl.h | 343 ----- 7 files changed, 6 insertions(+), 1969 deletions(-) delete mode 100644 source/lib/sysdep/os/win/wsdl.cpp delete mode 100644 source/lib/sysdep/os/win/wsdl.h diff --git a/build/premake/extern_libs4.lua b/build/premake/extern_libs4.lua index 45e30c57cc..326e933f52 100644 --- a/build/premake/extern_libs4.lua +++ b/build/premake/extern_libs4.lua @@ -580,12 +580,7 @@ extern_lib_defs = { sdl = { compile_settings = function() if os.is("windows") then - if _OPTIONS["sdl2"] then - includedirs { libraries_dir .. "sdl2/include/SDL" } - defines { "CONFIG2_WSDL=0" } - else - includedirs { libraries_dir .. "sdl/include/SDL" } - end + includedirs { libraries_dir .. "sdl2/include/SDL" } elseif not _OPTIONS["android"] then -- Support SDL*_CONFIG for overriding the default PATH-based sdl*-config if _OPTIONS["sdl2"] then @@ -605,11 +600,7 @@ extern_lib_defs = { end, link_settings = function() if os.is("windows") then - if _OPTIONS["sdl2"] then - add_default_lib_paths("sdl2") - else - add_default_lib_paths("sdl") - end + add_default_lib_paths("sdl2") elseif not _OPTIONS["android"] then if _OPTIONS["sdl2"] then sdl_config_path = os.getenv("SDL2_CONFIG") diff --git a/build/workspaces/update-workspaces.bat b/build/workspaces/update-workspaces.bat index c612a99e9f..1969f3d57a 100644 --- a/build/workspaces/update-workspaces.bat +++ b/build/workspaces/update-workspaces.bat @@ -3,5 +3,5 @@ rem ** Create Visual Studio Workspaces on Windows ** cd ..\premake rem ** Support for Visual Studio versions <2013 has been dropped (check #2669). -if not exist ..\workspaces\vc2013\SKIP_PREMAKE_HERE premake4\bin\release\premake4 --outpath="../workspaces/vc2013" --collada --use-shared-glooxwrapper --sdl2 %* vs2013 +if not exist ..\workspaces\vc2013\SKIP_PREMAKE_HERE premake4\bin\release\premake4 --outpath="../workspaces/vc2013" --collada --use-shared-glooxwrapper %* vs2013 cd ..\workspaces diff --git a/source/lib/config2.h b/source/lib/config2.h index 7dbee5ac73..4a135cf213 100644 --- a/source/lib/config2.h +++ b/source/lib/config2.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013 Wildfire Games +/* Copyright (c) 2015 Wildfire Games * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -56,20 +56,6 @@ #define CONFIG2_CACHE_READ_ONLY 1 #endif -// enable the wsdl emulator in Windows builds. -// -// NOTE: the official SDL distribution has two problems on Windows: -// - it specifies "/defaultlib:msvcrt.lib". this is troublesome because -// multiple heaps are active; errors result when allocated blocks are -// (for reasons unknown) passed to a different heap to be freed. -// one workaround is to add "/nodefaultlib:msvcrt.lib" to the linker -// command line in debug configurations. -// - it doesn't support color hardware mouse cursors and clashes with -// cursor.cpp's efforts by resetting the mouse cursor after movement. -#ifndef CONFIG2_WSDL -# define CONFIG2_WSDL 1 -#endif - #ifndef CONFIG2_FILE_ENABLE_AIO // work around a bug introduced in Linux 2.6.38 // (http://www.wildfiregames.com/forum/index.php?showtopic=14561&view=findpost&p=217710) diff --git a/source/lib/external_libraries/libsdl.h b/source/lib/external_libraries/libsdl.h index 71070cf363..b8677093ca 100644 --- a/source/lib/external_libraries/libsdl.h +++ b/source/lib/external_libraries/libsdl.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014 Wildfire Games +/* Copyright (c) 2015 Wildfire Games * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -28,11 +28,6 @@ #define INCLUDED_SDL #include "lib/external_libraries/libsdl_fwd.h" -#include "lib/config2.h" // CONFIG2_WSDL - -#if OS_WIN && CONFIG2_WSDL -# include "lib/sysdep/os/win/wsdl.h" -#else # include "SDL.h" # include "SDL_thread.h" @@ -53,8 +48,6 @@ # endif # endif -#endif - // complete definition of our forward-declared SDL_Event (see sdl_fwd.h) struct SDL_Event_ { diff --git a/source/lib/sysdep/gfx.cpp b/source/lib/sysdep/gfx.cpp index 6a8ee9b7f4..57ba511913 100644 --- a/source/lib/sysdep/gfx.cpp +++ b/source/lib/sysdep/gfx.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2013 Wildfire Games +/* Copyright (c) 2015 Wildfire Games * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -27,7 +27,6 @@ #include "precompiled.h" #include "lib/sysdep/gfx.h" -#define WSDL_NO_KEYSYM #include "lib/external_libraries/libsdl.h" #include "lib/ogl.h" diff --git a/source/lib/sysdep/os/win/wsdl.cpp b/source/lib/sysdep/os/win/wsdl.cpp deleted file mode 100644 index ac9e49d7dd..0000000000 --- a/source/lib/sysdep/os/win/wsdl.cpp +++ /dev/null @@ -1,1589 +0,0 @@ -/* Copyright (c) 2012 Wildfire Games - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * emulate SDL on Windows. - */ - -#include "precompiled.h" -#include "lib/external_libraries/libsdl.h" - -#if CONFIG2_WSDL - -#include -#include -#include -#include - -#include "lib/sysdep/os/win/win.h" -#include // _beginthreadex -#include // message crackers - -#include "lib/module_init.h" -#include "lib/posix/posix_pthread.h" -#include "lib/sysdep/sysdep.h" -#include "lib/sysdep/os/win/wutil.h" -#include "lib/sysdep/os/win/winit.h" -#include "lib/sysdep/os/win/wmi.h" // for SDL_GetVideoInfo - -#if MSC_VERSION -#pragma comment(lib, "user32.lib") -#pragma comment(lib, "gdi32.lib") -#endif - -#include "lib/ogl.h" // needed to pull in the delay-loaded opengl32.dll - - -WINIT_REGISTER_LATE_INIT(wsdl_Init); -WINIT_REGISTER_EARLY_SHUTDOWN(wsdl_Shutdown); - -// in fullscreen mode, i.e. not windowed. -// video mode will be restored when app is deactivated. -static bool fullscreen; - -// the app is shutting down. -// if set, ignore further Windows messages for clean shutdown. -static bool is_quitting; - -static HWND g_hWnd = (HWND)INVALID_HANDLE_VALUE; - -// usable at any time (required by SDL_SetGamma); this is made -// mostly safe via CS_OWNDC. -static HDC g_hDC = (HDC)INVALID_HANDLE_VALUE; - - -//---------------------------------------------------------------------------- -// gamma - -class GammaRamp -{ -public: - GammaRamp() - : m_hasChanged(false) - { - } - - bool Change(HDC hDC, float gamma_r, float gamma_g, float gamma_b) - { - // get current ramp (once) so we can later restore it. - if(!m_hasChanged) - { - ENSURE(wutil_IsValidHandle(hDC)); - if(!GetDeviceGammaRamp(hDC, m_original)) - return false; - } - - Compute(gamma_r, m_changed+0*256); - Compute(gamma_g, m_changed+1*256); - Compute(gamma_b, m_changed+2*256); - if(!Upload(m_changed)) - return false; - - m_hasChanged = true; - return true; - } - - void Latch() - { - if(m_hasChanged) - { - if(!Upload(m_changed)) - m_hasChanged = false; - } - - } - - void RestoreOriginal() - { - if(m_hasChanged) - { - if(!Upload(m_original)) - m_hasChanged = false; - } - } - -private: - static void Compute(float gamma, u16* ramp) - { - // assume identity if invalid - if(gamma <= 0.0f) - gamma = 1.0f; - - // identity: special-case to make sure we get exact values - if(gamma == 1.0f) - { - for(u16 i = 0; i < 256; i++) - ramp[i] = u16(i << 8); - return; - } - - for(int i = 0; i < 256; i++) - { - const double val = pow(i/255.0, (double)gamma); - const double clamped = std::max(0.0, std::min(val, 1.0-DBL_EPSILON)); - ramp[i] = u16_from_double(clamped); - } - ENSURE(ramp[0] == 0); - ENSURE(ramp[255] == 0xFFFF); - } - - bool Upload(u16* ramps) - { - WinScopedPreserveLastError s; - SetLastError(0); - ENSURE(wutil_IsValidHandle(g_hDC)); - BOOL ok = SetDeviceGammaRamp(g_hDC, ramps); - // on multi-monitor NVidia systems, the first call after a reboot - // fails, but subsequent ones succeed. - // see http://icculus.org/pipermail/quake3-bugzilla/2009-October/001316.html - if(ok == FALSE) - { - ok = SetDeviceGammaRamp(g_hDC, ramps); - // at least one 32-bit XP system STILL fails here, - // so don't raise an error dialog. - if(!ok) - debug_printf("SetDeviceGammaRamp failed twice. Oh well.\n"); - } - return (ok == TRUE); - } - - bool m_hasChanged; - - // values are 8.8 fixed point - u16 m_original[3*256]; - u16 m_changed[3*256]; -}; - -static GammaRamp gammaRamp; - - -// note: any component gamma = 0 is assumed to be identity. -int SDL_SetGamma(float r, float g, float b) -{ - return gammaRamp.Change(g_hDC, r, g, b)? 0 : -1; -} - - -//---------------------------------------------------------------------------- -// window -//---------------------------------------------------------------------------- - -static DWORD wnd_ChooseWindowStyle(bool fullscreen, HWND previousWindow = (HWND)INVALID_HANDLE_VALUE) -{ - DWORD windowStyle = fullscreen? WS_POPUP : WS_POPUPWINDOW|WS_CAPTION|WS_MINIMIZEBOX; - windowStyle |= WS_VISIBLE; - windowStyle |= WS_CLIPCHILDREN|WS_CLIPSIBLINGS; // MSDN SetPixelFormat says this is required - - if(!fullscreen) // windowed - { - // support resizing - windowStyle |= WS_SIZEBOX|WS_MAXIMIZEBOX; - - // remember the previous maximized state - // (else subsequent attempts to maximize will fail) - if(wutil_IsValidHandle(previousWindow)) - { - const DWORD previousWindowState = GetWindowLongW(previousWindow, GWL_STYLE); - windowStyle |= (previousWindowState & WS_MAXIMIZE); - } - } - - return windowStyle; -} - - -// @param w,h value-return (in: desired, out: actual pixel count) -static void wnd_UpdateWindowDimensions(DWORD windowStyle, int& w, int& h) -{ - // Calculate the size of the outer window, so that the client area has - // the desired dimensions. - RECT r; - r.left = r.top = 0; - r.right = w; r.bottom = h; - if(AdjustWindowRectEx(&r, windowStyle, FALSE, 0)) - { - w = r.right - r.left; - h = r.bottom - r.top; - } -} - - -static LRESULT CALLBACK OnMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - -static HWND wnd_CreateWindow(int w, int h) -{ - // (create new window every time (instead of once at startup), because - // pixel format isn't supposed to be changed more than once) - - // app instance. - // returned by GetModuleHandle and used in keyboard hook and window creation. - const HINSTANCE hInst = GetModuleHandle(0); - - // register window class - WNDCLASSW wc; - memset(&wc, 0, sizeof(wc)); - // no CS_VREDRAW and CS_HREDRAW - avoids redrawing when resized. - wc.style = CS_OWNDC; // (see g_hDC definition) - wc.lpfnWndProc = OnMessage; - wc.lpszClassName = L"WSDL{55752F43-0241-492C-8648-C7243397FCE4}"; - wc.hInstance = hInst; - ATOM class_atom = RegisterClassW(&wc); - // ignore failure, which is probably caused by not unregistering the class - // (does not happen automatically when called from a DLL). just re-use - // the existing class, which is safe because our class name is unique. - - const DWORD windowStyle = wnd_ChooseWindowStyle(fullscreen); - wnd_UpdateWindowDimensions(windowStyle, w, h); - - // note: you can override the hard-coded window name via SDL_WM_SetCaption. - HWND hWnd = CreateWindowExW(WS_EX_APPWINDOW, (LPCWSTR)(uintptr_t)class_atom, L"wsdl", windowStyle, 0, 0, w, h, 0, 0, hInst, 0); - if(!wutil_IsValidHandle(hWnd)) - DEBUG_WARN_ERR(ERR::FAIL); - return hWnd; -} - - -static RECT ClientRect(HWND hWnd) -{ - RECT rect; - ENSURE(wutil_IsValidHandle(hWnd)); - WARN_IF_FALSE(GetClientRect(hWnd, &rect)); - return rect; -} - - -//---------------------------------------------------------------------------- -// video -//---------------------------------------------------------------------------- - -static DEVMODE dm; // current video mode -static HGLRC hGLRC = (HGLRC)INVALID_HANDLE_VALUE; - -// set via SDL_GL_SetAttribute: -static int depthBufferBits = 24; -static int stencilBufferBits = 0; -static int vsyncEnabled = 1; - -int SDL_GL_SetAttribute(SDL_GLattr attr, int value) -{ - switch(attr) - { - case SDL_GL_DEPTH_SIZE: - depthBufferBits = value; - break; - - case SDL_GL_STENCIL_SIZE: - stencilBufferBits = value; - break; - - case SDL_GL_SWAP_CONTROL: - vsyncEnabled = value; - break; - - case SDL_GL_DOUBLEBUFFER: - // (always enabled) - break; - } - - return 0; -} - - -// check if resolution needs to be changed -static bool video_NeedsChange(int w, int h, int cur_w, int cur_h, bool fullscreen) -{ - // invalid: keep current settings - if(w <= 0 || h <= 0) - return false; - - // higher resolution mode needed - if(w > cur_w || h > cur_h) - return true; - - // fullscreen requested and not exact same mode set - if(fullscreen && (w != cur_w || h != cur_h)) - return true; - - return false; -} - - -static void video_SetPixelFormat(HDC hDC, int bpp) -{ - const DWORD dwFlags = PFD_SUPPORT_OPENGL|PFD_DRAW_TO_WINDOW|PFD_DOUBLEBUFFER; - BYTE cColourBits = (BYTE)bpp; - BYTE cAlphaBits = 0; - if(bpp == 32) - { - cColourBits = 24; - cAlphaBits = 8; - } - const BYTE cAccumBits = 0; - const BYTE cDepthBits = (BYTE)depthBufferBits; - const BYTE cStencilBits = (BYTE)stencilBufferBits; - const BYTE cAuxBuffers = 0; - - PIXELFORMATDESCRIPTOR pfd = - { - sizeof(PIXELFORMATDESCRIPTOR), - 1, // version - dwFlags, - PFD_TYPE_RGBA, - cColourBits, 0, 0, 0, 0, 0, 0, // c*Bits, c*Shift are unused - cAlphaBits, 0, // cAlphaShift is unused - cAccumBits, 0, 0, 0, 0, // cAccum*Bits are unused - cDepthBits, - cStencilBits, - cAuxBuffers, - PFD_MAIN_PLANE, - 0, 0, 0, 0 // bReserved, dw*Mask are unused - }; - - // note: the GDI pixel format functions require opengl32.dll to be loaded. - // a deadlock on the next line is probably due to VLD's LdrLoadDll hook. - - const int pf = ChoosePixelFormat(hDC, &pfd); - ENSURE(pf >= 1); - WARN_IF_FALSE(SetPixelFormat(hDC, pf, &pfd)); -} - - -// set video mode width x height : bpp (or leave unchanged if already adequate). -// w = h = bpp = 0 => no change. -SDL_Surface* SDL_SetVideoMode(int w, int h, int bpp, Uint32 flags) -{ - WinScopedPreserveLastError s; // OpenGL and GDI - - fullscreen = (flags & SDL_FULLSCREEN) != 0; - - // get current mode settings - memset(&dm, 0, sizeof(dm)); - dm.dmSize = sizeof(dm); - WARN_IF_FALSE(EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &dm)); - const int cur_w = (int)dm.dmPelsWidth, cur_h = (int)dm.dmPelsHeight; - - // independent of resolution; app must always get bpp it wants - dm.dmBitsPerPel = bpp; - dm.dmFields = DM_BITSPERPEL; - - if(video_NeedsChange(w,h, cur_w,cur_h, fullscreen)) - { - dm.dmPelsWidth = (DWORD)w; - dm.dmPelsHeight = (DWORD)h; - dm.dmFields |= DM_PELSWIDTH|DM_PELSHEIGHT; - } - // the (possibly changed) mode will be (re)set at next WM_ACTIVATE - - if(!wutil_IsValidHandle(g_hWnd)) - { - g_hWnd = wnd_CreateWindow(w, h); - if(!wutil_IsValidHandle(g_hWnd)) - return 0; - - g_hDC = GetDC(g_hWnd); - - video_SetPixelFormat(g_hDC, bpp); - - hGLRC = wglCreateContext(g_hDC); - if(!hGLRC) - return 0; - - if(!wglMakeCurrent(g_hDC, hGLRC)) - return 0; - } - else // update the existing window - { - const DWORD windowStyle = wnd_ChooseWindowStyle(fullscreen, g_hWnd); - wnd_UpdateWindowDimensions(windowStyle, w, h); - - UINT swp_flags = SWP_FRAMECHANGED|SWP_NOZORDER|SWP_NOACTIVATE; - if(!fullscreen) // windowed: preserve the top-left corner - swp_flags |= SWP_NOMOVE; - - WARN_IF_FALSE(SetWindowLongW(g_hWnd, GWL_STYLE, windowStyle)); - WARN_IF_FALSE(SetWindowPos(g_hWnd, 0, 0, 0, w, h, swp_flags)); - - LONG status; - if(fullscreen) - { - ShowWindow(g_hWnd, SW_RESTORE); - status = ChangeDisplaySettings(&dm, CDS_FULLSCREEN); - } - else - { - status = ChangeDisplaySettings(0, 0); - // don't ShowWindow with SW_MINIMIZE (we just want to update) - } - if (status != DISP_CHANGE_SUCCESSFUL) - { - wchar_t buf[100]; - swprintf_s(buf, ARRAY_SIZE(buf), L"ChangeDisplaySettings failed with status=%d", status); - DEBUG_DISPLAY_ERROR(buf); - } - } - - // (required for ogl_HaveExtension, but callers should also invoke - // ogl_Init in case the real SDL is being used.) - ogl_Init(); - if(ogl_HaveExtension("WGL_EXT_swap_control") && pwglSwapIntervalEXT) - pwglSwapIntervalEXT(vsyncEnabled); - - const RECT rect = ClientRect(g_hWnd); // updated window size - - static SDL_PixelFormat format; - format.BitsPerPixel = bpp; - - static SDL_Surface screen; - screen.w = rect.right; - screen.h = rect.bottom; - screen.format = &format; - return &screen; -} - - -static void video_Shutdown() -{ - if(fullscreen) - { - LONG status = ChangeDisplaySettings(0, 0); - if (status != DISP_CHANGE_SUCCESSFUL) - { - wchar_t buf[100]; - swprintf_s(buf, ARRAY_SIZE(buf), L"ChangeDisplaySettings failed with status=%d", status); - DEBUG_DISPLAY_ERROR(buf); - } - } - - if(wutil_IsValidHandle(hGLRC)) - { - WARN_IF_FALSE(wglMakeCurrent(0, 0)); - WARN_IF_FALSE(wglDeleteContext(hGLRC)); - hGLRC = (HGLRC)INVALID_HANDLE_VALUE; - } - - g_hWnd = (HWND)INVALID_HANDLE_VALUE; - g_hDC = (HDC)INVALID_HANDLE_VALUE; -} - - -void SDL_GL_SwapBuffers() -{ - WARN_IF_FALSE(SwapBuffers(g_hDC)); -} - - -SDL_VideoInfo* SDL_GetVideoInfo() -{ - static SDL_VideoInfo video_info; - - if(video_info.video_mem == 0) - { - WmiInstances instances; - if(wmi_GetClassInstances(L"Win32_VideoController", instances) == INFO::OK) - { - for(WmiInstances::iterator it = instances.begin(); it != instances.end(); ++it) - { - if((*it)[L"Availability"].intVal != 8) // not offline - { - video_info.video_mem = std::max(video_info.video_mem, (*it)[L"AdapterRAM"].lVal / KiB); - break; - } - } - } - } - - return &video_info; -} - - -SDL_Surface* SDL_GetVideoSurface() -{ - return 0; -} - - -//---------------------------------------------------------------------------- -// event queue - -// note: we only use winit to redirect stdout; this queue won't be used -// before _cinit. -typedef std::queue Queue; -static Queue g_queue; - -static void QueueEvent(const SDL_Event& ev) -{ - g_queue.push(ev); -} - -static bool DequeueEvent(SDL_Event& ev) -{ - if(g_queue.empty()) - return false; - ev = g_queue.front(); - g_queue.pop(); - return true; -} - - -//---------------------------------------------------------------------------- -// keyboard - -// note: keysym.unicode is only returned for SDL_KEYDOWN, and is otherwise 0. -static void QueueKeyEvent(Uint8 type, SDLKey sdlk, WCHAR unicode_char) -{ - SDL_Event ev; - ev.type = type; - ev.key.keysym.sym = sdlk; - ev.key.keysym.unicode = (Uint16)unicode_char; - QueueEvent(ev); -} - - -static Uint8 keys[SDLK_LAST]; - -static SDLKey g_SDLKeyForVK[256]; // g_SDLKeyForVK[vk] == SDLK - -static void key_Init() -{ - // Map the VK keysyms - for(size_t i = 0; i < ARRAY_SIZE(g_SDLKeyForVK); i++) - g_SDLKeyForVK[i] = SDLK_UNKNOWN; - - g_SDLKeyForVK[VK_BACK] = SDLK_BACKSPACE; - g_SDLKeyForVK[VK_TAB] = SDLK_TAB; - g_SDLKeyForVK[VK_CLEAR] = SDLK_CLEAR; - g_SDLKeyForVK[VK_RETURN] = SDLK_RETURN; - g_SDLKeyForVK[VK_PAUSE] = SDLK_PAUSE; - g_SDLKeyForVK[VK_ESCAPE] = SDLK_ESCAPE; - g_SDLKeyForVK[VK_SPACE] = SDLK_SPACE; - g_SDLKeyForVK[VK_OEM_7] = SDLK_QUOTE; - g_SDLKeyForVK[VK_OEM_COMMA] = SDLK_COMMA; - g_SDLKeyForVK[VK_OEM_MINUS] = SDLK_MINUS; - g_SDLKeyForVK[VK_OEM_PERIOD] = SDLK_PERIOD; - g_SDLKeyForVK[VK_OEM_2] = SDLK_SLASH; - g_SDLKeyForVK[VK_OEM_1] = SDLK_SEMICOLON; - g_SDLKeyForVK[VK_OEM_PLUS] = SDLK_EQUALS; - g_SDLKeyForVK[VK_OEM_4] = SDLK_LEFTBRACKET; - g_SDLKeyForVK[VK_OEM_5] = SDLK_BACKSLASH; - g_SDLKeyForVK[VK_OEM_6] = SDLK_RIGHTBRACKET; - g_SDLKeyForVK[VK_OEM_3] = SDLK_BACKQUOTE; - g_SDLKeyForVK[VK_OEM_8] = SDLK_BACKQUOTE; - - // winuser.h guarantees A..Z and 0..9 match their ASCII values: - const int VK_0 = '0'; - for(int i = 0; i < 10; i++) - g_SDLKeyForVK[VK_0+i] = (SDLKey)(SDLK_0+i); - const int VK_A = 'A'; - for(int i = 0; i < 26; i++) - g_SDLKeyForVK[VK_A+i] = (SDLKey)(SDLK_a+i); - - g_SDLKeyForVK[VK_DELETE] = SDLK_DELETE; - - for(int i = 0; i < 10; i++) - g_SDLKeyForVK[VK_NUMPAD0+i] = (SDLKey)(SDLK_KP0+i); - - g_SDLKeyForVK[VK_DECIMAL] = SDLK_KP_PERIOD; - g_SDLKeyForVK[VK_DIVIDE] = SDLK_KP_DIVIDE; - g_SDLKeyForVK[VK_MULTIPLY] = SDLK_KP_MULTIPLY; - g_SDLKeyForVK[VK_SUBTRACT] = SDLK_KP_MINUS; - g_SDLKeyForVK[VK_ADD] = SDLK_KP_PLUS; - - g_SDLKeyForVK[VK_UP] = SDLK_UP; - g_SDLKeyForVK[VK_DOWN] = SDLK_DOWN; - g_SDLKeyForVK[VK_RIGHT] = SDLK_RIGHT; - g_SDLKeyForVK[VK_LEFT] = SDLK_LEFT; - g_SDLKeyForVK[VK_INSERT] = SDLK_INSERT; - g_SDLKeyForVK[VK_HOME] = SDLK_HOME; - g_SDLKeyForVK[VK_END] = SDLK_END; - g_SDLKeyForVK[VK_PRIOR] = SDLK_PAGEUP; - g_SDLKeyForVK[VK_NEXT] = SDLK_PAGEDOWN; - - for(int i = 0; i < 12; i++) - g_SDLKeyForVK[VK_F1+i] = (SDLKey)(SDLK_F1+i); - - g_SDLKeyForVK[VK_NUMLOCK] = SDLK_NUMLOCK; - g_SDLKeyForVK[VK_CAPITAL] = SDLK_CAPSLOCK; - g_SDLKeyForVK[VK_SCROLL] = SDLK_SCROLLOCK; - g_SDLKeyForVK[VK_RSHIFT] = SDLK_RSHIFT; - g_SDLKeyForVK[VK_LSHIFT] = SDLK_LSHIFT; - g_SDLKeyForVK[VK_SHIFT] = SDLK_LSHIFT; // XXX: Not quite - g_SDLKeyForVK[VK_RCONTROL] = SDLK_RCTRL; - g_SDLKeyForVK[VK_LCONTROL] = SDLK_LCTRL; - g_SDLKeyForVK[VK_CONTROL] = SDLK_LCTRL; // XXX: Not quite - g_SDLKeyForVK[VK_RMENU] = SDLK_RALT; - g_SDLKeyForVK[VK_LMENU] = SDLK_LALT; - g_SDLKeyForVK[VK_MENU] = SDLK_LALT; // XXX: Not quite - g_SDLKeyForVK[VK_RWIN] = SDLK_RSUPER; - g_SDLKeyForVK[VK_LWIN] = SDLK_LSUPER; - - g_SDLKeyForVK[VK_HELP] = SDLK_HELP; -#ifdef VK_PRINT - g_SDLKeyForVK[VK_PRINT] = SDLK_PRINT; -#endif - g_SDLKeyForVK[VK_SNAPSHOT] = SDLK_PRINT; - g_SDLKeyForVK[VK_CANCEL] = SDLK_BREAK; - g_SDLKeyForVK[VK_APPS] = SDLK_MENU; -} - - -static inline SDLKey SDLKeyFromVK(int vk) -{ - if(!(0 <= vk && vk < 256)) - { - DEBUG_WARN_ERR(ERR::LOGIC); // invalid vk - return SDLK_UNKNOWN; - } - return g_SDLKeyForVK[vk]; -} - - -static void key_ResetAll() -{ - SDL_Event spoofed_up_event; - spoofed_up_event.type = SDL_KEYUP; - spoofed_up_event.key.keysym.unicode = 0; - - for(size_t i = 0; i < ARRAY_SIZE(keys); i++) - { - if(keys[i]) - { - spoofed_up_event.key.keysym.sym = (SDLKey)i; - QueueEvent(spoofed_up_event); - } - } -} - - -static LRESULT OnKey(HWND UNUSED(hWnd), UINT vk, BOOL fDown, int UNUSED(cRepeat), UINT flags) -{ - // TODO Mappings for left/right modifier keys - // TODO Modifier statekeeping - - const SDLKey sdlk = SDLKeyFromVK(vk); - if(sdlk != SDLK_UNKNOWN) - keys[sdlk] = (Uint8)fDown; - - if(!fDown) - QueueKeyEvent(SDL_KEYUP, sdlk, 0); - else - { - // note: flags is HIWORD(lParam) from WM_KEYDOWN, which includes - // scancode. ToUnicode also uses its bit 15 to determine if the - // key is currently pressed. - const UINT scancode = flags; - u8 key_states[256]; - WARN_IF_FALSE(GetKeyboardState(key_states)); - WCHAR wchars[8]; - int output_count = ToUnicode(vk, scancode, key_states, wchars, ARRAY_SIZE(wchars), 0); - // translation succeeded; queue each produced character - if(output_count > 0) - { - for(int i = 0; i < output_count; i++) - QueueKeyEvent(SDL_KEYDOWN, sdlk, wchars[i]); - } - // dead-char; do nothing - else if(output_count == -1) - { - } - // translation failed; just generate a regular (non-unicode) event - else if(output_count == 0) - QueueKeyEvent(SDL_KEYDOWN, sdlk, 0); - else - UNREACHABLE; - } - - return 0; -} - - -Uint8* SDL_GetKeyState(int* num_keys) -{ - if(num_keys) - *num_keys = SDLK_LAST; - return keys; -} - - -// always on (we don't care about the extra overhead) -int SDL_EnableUNICODE(int UNUSED(enable)) -{ - return 1; -} - - -//---------------------------------------------------------------------------- -// joystick - -int SDL_NumJoysticks() -{ - return 0; -} - -int SDL_JoystickEventState(int UNUSED(state)) -{ - return 0; -} - -const char* SDL_JoystickName(int UNUSED(device_index)) -{ - return NULL; -} - -SDL_Joystick* SDL_JoystickOpen(int UNUSED(device_index)) -{ - return NULL; -} - -int SDL_JoystickNumAxes(SDL_Joystick* UNUSED(joystick)) -{ - return 0; -} - -Sint16 SDL_JoystickGetAxis(SDL_Joystick* UNUSED(joystick), int UNUSED(axis)) -{ - return 0; -} - - -//---------------------------------------------------------------------------- -// app activation - -enum SdlActivationType { LOSE = 0, GAIN = 1 }; - -static inline void QueueActiveEvent(SdlActivationType type, size_t changed_app_state) -{ - // SDL says this event is not generated when the window is created, - // but skipping the first event may confuse things. - - SDL_Event ev; - ev.type = SDL_ACTIVEEVENT; - ev.active.state = (u8)changed_app_state; - ev.active.gain = (u8)((type == GAIN)? 1 : 0); - QueueEvent(ev); -} - - -// SDL_APP* bitflags indicating whether we are active. -// note: responsibility for yielding lies with SDL apps - -// they control the main loop. -static Uint8 app_state; - -static void active_ChangeState(SdlActivationType type, Uint8 changed_app_state) -{ - Uint8 old_app_state = app_state; - - if(type == GAIN) - app_state = Uint8(app_state | changed_app_state); - else - app_state = Uint8(app_state & ~changed_app_state); - - // generate an event - but only if the given state flags actually changed. - if((old_app_state & changed_app_state) != (app_state & changed_app_state)) - QueueActiveEvent(type, changed_app_state); -} - - -static LRESULT OnActivate(HWND hWnd, UINT state, HWND UNUSED(hWndActDeact), BOOL fMinimized) -{ - SdlActivationType type; - Uint8 changed_app_state; - - // went active and not minimized - if(state != WA_INACTIVE && !fMinimized) - { - type = GAIN; - changed_app_state = SDL_APPINPUTFOCUS|SDL_APPACTIVE; - - // grab keyboard focus (we previously had DefWindowProc do this). - SetFocus(hWnd); - - gammaRamp.Latch(); - if(fullscreen) - { - ShowWindow(g_hWnd, SW_RESTORE); - const LONG ret = ChangeDisplaySettings(&dm, CDS_FULLSCREEN); - if (ret != DISP_CHANGE_SUCCESSFUL) - { - wchar_t buf[100]; - swprintf_s(buf, ARRAY_SIZE(buf), L"ChangeDisplaySettings failed with ret=%d", ret); - DEBUG_DISPLAY_ERROR(buf); - } - } - - // re-assert mouse grab state - SDL_WM_GrabInput(SDL_WM_GrabInput(SDL_GRAB_QUERY)); - } - // deactivated (Alt+Tab out) or minimized - else - { - type = LOSE; - changed_app_state = SDL_APPINPUTFOCUS; - if(fMinimized) - changed_app_state |= SDL_APPACTIVE; - - key_ResetAll(); - - gammaRamp.RestoreOriginal(); - if(fullscreen) - { - const LONG ret = ChangeDisplaySettings(0, 0); - if (ret != DISP_CHANGE_SUCCESSFUL) - { - wchar_t buf[100]; - swprintf_s(buf, ARRAY_SIZE(buf), L"ChangeDisplaySettings failed with ret=%d", ret); - DEBUG_DISPLAY_ERROR(buf); - } - WARN_IF_FALSE(ShowWindow(g_hWnd, SW_MINIMIZE)); - } - } - - active_ChangeState(type, changed_app_state); - return 0; -} - - -Uint8 SDL_GetAppState() -{ - return app_state; -} - - -static void QueueQuitEvent() -{ - SDL_Event ev; - ev.type = SDL_QUIT; - QueueEvent(ev); -} - - -//---------------------------------------------------------------------------- -// mouse - -// background: there are several types of coordinates. -// - screen coords are relative to the primary desktop and may therefore be -// negative on multi-monitor systems (e.g. if secondary monitor is left of -// primary). they are prefixed with screen_*. -// - "client" coords are simply relative to the parent window's origin and -// can also be negative (e.g. in the window's NC area). -// these are prefixed with client_*. -// - "idealized" coords are what the app sees. these range from 0 to -// windowDimensions-1. they are returned by mouse_GetCoords and have no prefix. - -static void QueueMouseEvent(int x, int y) -{ - SDL_Event ev; - ev.type = SDL_MOUSEMOTION; - ENSURE(unsigned(x|y) <= USHRT_MAX); - ev.motion.x = (Uint16)x; - ev.motion.y = (Uint16)y; - QueueEvent(ev); -} - -static void QueueButtonEvent(int button, int state, int x, int y) -{ - SDL_Event ev; - ev.type = Uint8((state == SDL_PRESSED)? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP); - ev.button.button = (u8)button; - ev.button.state = (u8)state; - ENSURE(unsigned(x|y) <= USHRT_MAX); - ev.button.x = (Uint16)x; - ev.button.y = (Uint16)y; - QueueEvent(ev); -} - - -static int mouse_x, mouse_y; - -// generate a mouse move message and update our notion of the mouse position. -// x, y are client pixel coordinates. -// notes: -// - does not actually move the OS cursor; -// - called from mouse_Update and SDL_WarpMouse. -static void mouse_UpdatePosition(int x, int y) -{ - // nothing to do if it hasn't changed since last time - if(mouse_x == x && mouse_y == y) - return; - - mouse_x = x; - mouse_y = y; - QueueMouseEvent(x, y); -} - -static POINT mouse_ScreenFromClient(int client_x, int client_y) -{ - POINT screen_pt; - screen_pt.x = (LONG)client_x; - screen_pt.y = (LONG)client_y; - WARN_IF_FALSE(ClientToScreen(g_hWnd, &screen_pt)); - return screen_pt; -} - -// get idealized client coordinates or return false if outside our window. -static bool mouse_GetCoords(int screen_x, int screen_y, int& x, int& y) -{ - ENSURE(wutil_IsValidHandle(g_hWnd)); - - POINT screen_pt; - screen_pt.x = (LONG)screen_x; - screen_pt.y = (LONG)screen_y; - - POINT client_pt; - { - // note: MapWindowPoints has a really stupid interface, returning 0 - // on failure or if no shift was needed (i.e. window is fullscreen). - // we must use GetLastError to detect error conditions. - WinScopedPreserveLastError s; - SetLastError(0); - client_pt = screen_pt; // translated below - const int ret = MapWindowPoints(HWND_DESKTOP, g_hWnd, &client_pt, 1); - ENSURE(ret != 0 || GetLastError() == 0); - } - - { - const RECT client_rect = ClientRect(g_hWnd); - if(!PtInRect(&client_rect, client_pt)) - return false; - } - - if(WindowFromPoint(screen_pt) != g_hWnd) - return false; - - x = client_pt.x; - y = client_pt.y; - ENSURE(x >= 0 && y >= 0); - return true; -} - - -static void mouse_Update() -{ - // window not created yet or already shut down. no sense reporting - // mouse position, and bail now to avoid ScreenToClient failing. - if(!wutil_IsValidHandle(g_hWnd)) - return; - - // don't use DirectInput, because we want to respect the user's mouse - // sensitivity settings. Windows messages are prone to lag, - // so query current position directly. - // note: GetCursorPos fails if the desktop is switched (e.g. after - // pressing Ctrl+Alt+Del), which can be ignored. - POINT screen_pt; - if(!GetCursorPos(&screen_pt)) - return; - int x, y; - if(mouse_GetCoords(screen_pt.x, screen_pt.y, x, y)) - { - active_ChangeState(GAIN, SDL_APPMOUSEFOCUS); - mouse_UpdatePosition(x, y); - } - // moved outside of window - else - active_ChangeState(LOSE, SDL_APPMOUSEFOCUS); -} - - -static unsigned mouse_buttons; - -// (we define a new function signature since the windowsx.h message crackers -// don't provide for passing uMsg) -static LRESULT OnMouseButton(HWND UNUSED(hWnd), UINT uMsg, int client_x, int client_y, UINT flags) -{ - int button; - int state; - switch(uMsg) - { - case WM_LBUTTONDOWN: - button = SDL_BUTTON_LEFT; - state = SDL_PRESSED; - break; - case WM_LBUTTONUP: - button = SDL_BUTTON_LEFT; - state = SDL_RELEASED; - break; - case WM_RBUTTONDOWN: - button = SDL_BUTTON_RIGHT; - state = SDL_PRESSED; - break; - case WM_RBUTTONUP: - button = SDL_BUTTON_RIGHT; - state = SDL_RELEASED; - break; - case WM_MBUTTONDOWN: - button = SDL_BUTTON_MIDDLE; - state = SDL_PRESSED; - break; - case WM_MBUTTONUP: - button = SDL_BUTTON_MIDDLE; - state = SDL_RELEASED; - break; - case WM_XBUTTONDOWN: - button = SDL_BUTTON_X1 + GET_XBUTTON_WPARAM(flags) - 1; - state = SDL_PRESSED; - break; - case WM_XBUTTONUP: - button = SDL_BUTTON_X1 + GET_XBUTTON_WPARAM(flags) - 1; - state = SDL_RELEASED; - break; - NODEFAULT; - } - - // mouse capture - static int outstanding_press_events; - if(state == SDL_PRESSED) - { - // grab mouse to ensure we get up events - if(++outstanding_press_events > 0) - (void)SetCapture(g_hWnd); // (returns previous window) - } - else - { - // release after all up events received - if(--outstanding_press_events <= 0) - { - WARN_IF_FALSE(ReleaseCapture()); - outstanding_press_events = 0; - } - } - - // update button bitfield - if(state == SDL_PRESSED) - mouse_buttons |= SDL_BUTTON(button); - else - mouse_buttons &= ~SDL_BUTTON(button); - - const POINT screen_pt = mouse_ScreenFromClient(client_x, client_y); - int x, y; - if(mouse_GetCoords(screen_pt.x, screen_pt.y, x, y)) - QueueButtonEvent(button, state, x, y); - - // Per MSDN, return TRUE for XBUTTON events - if (uMsg == WM_XBUTTONDOWN || uMsg == WM_XBUTTONUP) - return TRUE; - - return 0; -} - - -// (note: this message is sent even if the cursor is outside our window) -static LRESULT OnMouseWheel(HWND UNUSED(hWnd), int screen_x, int screen_y, int zDelta, UINT UNUSED(fwKeys)) -{ - int x, y; - if(mouse_GetCoords(screen_x, screen_y, x, y)) - { - int button = (zDelta < 0)? SDL_BUTTON_WHEELDOWN : SDL_BUTTON_WHEELUP; - // SDL says this sends a down message followed by up. - QueueButtonEvent(button, SDL_PRESSED, x, y); - QueueButtonEvent(button, SDL_RELEASED, x, y); - } - - return 0; // handled -} - - -Uint8 SDL_GetMouseState(int* x, int* y) -{ - if(x) - *x = (int)mouse_x; - if(y) - *y = (int)mouse_y; - return (Uint8)mouse_buttons; -} - - -void SDL_WarpMouse(int x, int y) -{ - // SDL interface provides for int, but the values should be - // idealized client coords (>= 0) - ENSURE(x >= 0 && y >= 0); - mouse_UpdatePosition(x, y); - - const int client_x = x, client_y = y; - const POINT screen_pt = mouse_ScreenFromClient(client_x, client_y); - WARN_IF_FALSE(SetCursorPos(screen_pt.x, screen_pt.y)); -} - - -int SDL_ShowCursor(int toggle) -{ - static int cursor_visible = SDL_ENABLE; - if(toggle != SDL_QUERY) - { - // only call Windows ShowCursor if changing the visibility - - // it maintains a counter. - if(cursor_visible != toggle) - { - (void)ShowCursor(toggle); // (returns display counter) - cursor_visible = toggle; - } - } - return cursor_visible; -} - - -SDL_GrabMode SDL_WM_GrabInput(SDL_GrabMode mode) -{ - static SDL_GrabMode prevMode; - if(mode == SDL_GRAB_QUERY) - return prevMode; - prevMode = mode; - - if(mode == SDL_GRAB_OFF) - WARN_IF_FALSE(ClipCursor(0)); - else - { - const RECT clientRect = ClientRect(g_hWnd); - POINT upperLeft = { clientRect.left, clientRect.top }; - WARN_IF_FALSE(ClientToScreen(g_hWnd, &upperLeft)); - POINT lowerRight = { clientRect.right, clientRect.bottom }; - WARN_IF_FALSE(ClientToScreen(g_hWnd, &lowerRight)); - const RECT screenRect = { upperLeft.x, upperLeft.y, lowerRight.x, lowerRight.y }; - WARN_IF_FALSE(ClipCursor(&screenRect)); - } - - return mode; -} - - -//---------------------------------------------------------------------------- -// video resizing/expose - -static bool ResizeEventEnabled(int clientWidth, int clientHeight) -{ - // when the app receives a resize event, it must call SDL_SetVideoMode. - // avoid that if the size hasn't actually changed. this also - // prevents infinite recursion, since SDL_SetVideoMode might - // trigger resize events. note that this logic is safer than a - // skipResize flag, because that would remain set if SDL_SetVideoMode - // doesn't trigger a resize, and we would miss an actual resize. - static int lastClientWidth, lastClientHeight; - if(lastClientWidth == clientWidth && lastClientHeight == clientHeight) - return false; - lastClientWidth = clientWidth; - lastClientHeight = clientHeight; - - // if fullscreen, interaction with other topmost windows causes - // minimization and a spurious resize. however, the app only - // expects resizing events if !fullscreen. - if(fullscreen) - return false; - - // this happens during minimization, which results in an - // app-active event anyway, and the app might have - // trouble with size=0. - if(clientWidth == 0 && clientHeight == 0) - return false; - - return true; -} - -// note: this is called continuously during resizing. since SDL doesn't -// discard any SDL_VIDEORESIZE events, the application must deal with -// the flood (and only call SDL_SetVideoMode once a frame or similar). -// note: SDL uses WM_WINDOWPOSCHANGING, which requires calling -// GetClientRect and suffers from false alarms. -static void OnSize(HWND UNUSED(hWnd), UINT UNUSED(state), int clientWidth, int clientHeight) -{ - if(!ResizeEventEnabled(clientWidth, clientHeight)) - return; - - SDL_Event ev; - ev.type = SDL_VIDEORESIZE; - ev.resize.w = clientWidth; - ev.resize.h = clientHeight; - QueueEvent(ev); -} - - -static BOOL OnEraseBkgnd(HWND UNUSED(hWnd), HDC UNUSED(hDC)) -{ - SDL_Event ev; - ev.type = SDL_VIDEOEXPOSE; - QueueEvent(ev); - - // prevent GDI from erasing the background by claiming we did so. - // PAINTSTRUCT.fErase will later be FALSE. - return TRUE; -} - - -//---------------------------------------------------------------------------- - -static LRESULT OnPaint(HWND hWnd) -{ - // BeginPaint/EndPaint is unnecessary (see http://opengl.czweb.org/ch04/082-084.html) - // however, we at least need to validate the window to prevent - // continuous WM_PAINT messages. - WARN_IF_FALSE(ValidateRect(hWnd, 0)); - return 0; -} - -static LRESULT OnDestroy(HWND hWnd) -{ - ENSURE(hWnd == g_hWnd); - WARN_IF_FALSE(ReleaseDC(g_hWnd, g_hDC)); - g_hDC = (HDC)INVALID_HANDLE_VALUE; - g_hWnd = (HWND)INVALID_HANDLE_VALUE; - QueueQuitEvent(); - -#ifdef _DEBUG - // see http://www.adrianmccarthy.com/blog/?p=51 - // with WM_QUIT in the message queue, MessageBox will immediately - // return IDABORT. to ensure any subsequent CRT error reports are - // at least somewhat visible, we redirect them to debug output. - _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); -#endif - - PostQuitMessage(0); - return 0; -} - - -enum DefWindowProcDisposition -{ - kSkipDefWindowProc, - kRunDefWindowProc -}; - -static DefWindowProcDisposition OnSysCommand(WPARAM wParam) -{ - switch(wParam) - { - case SC_SCREENSAVE: - // disable screen-saver in fullscreen mode (other applications - // may interfere with us, and we have set the system-wide gamma) - if(fullscreen) - return kSkipDefWindowProc; - break; - - // Alt+F4 or system menu double-click / exit - case SC_CLOSE: - QueueQuitEvent(); - break; - } - - return kRunDefWindowProc; -} - - -static LRESULT CALLBACK OnMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - if(is_quitting) - return DefWindowProcW(hWnd, uMsg, wParam, lParam); - - switch(uMsg) - { - case WM_PAINT: - return OnPaint(hWnd); - - HANDLE_MSG(hWnd, WM_ERASEBKGND, OnEraseBkgnd); - - // prevent selecting menu in fullscreen mode - case WM_NCHITTEST: - if(fullscreen) - return HTCLIENT; - break; - - HANDLE_MSG(hWnd, WM_ACTIVATE, OnActivate); - HANDLE_MSG(hWnd, WM_DESTROY, OnDestroy); - - case WM_SYSCOMMAND: - if(OnSysCommand(wParam) == kSkipDefWindowProc) - return 0; - break; - - HANDLE_MSG(hWnd, WM_SYSKEYUP , OnKey); - HANDLE_MSG(hWnd, WM_KEYUP , OnKey); - HANDLE_MSG(hWnd, WM_SYSKEYDOWN, OnKey); - HANDLE_MSG(hWnd, WM_KEYDOWN , OnKey); - - HANDLE_MSG(hWnd, WM_MOUSEWHEEL, OnMouseWheel); - - HANDLE_MSG(hWnd, WM_SIZE, OnSize); - - // (can't use message crackers: they do not provide for passing uMsg) - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - case WM_RBUTTONDOWN: - case WM_RBUTTONUP: - case WM_MBUTTONDOWN: - case WM_MBUTTONUP: - case WM_XBUTTONDOWN: - case WM_XBUTTONUP: - return OnMouseButton(hWnd, uMsg, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), (UINT)wParam); - - default: - // (DefWindowProc must be called outside the switch because some - // messages are only conditionally 'grabbed', e.g. NCHITTEST) - break; - } - - return DefWindowProcW(hWnd, uMsg, wParam, lParam); -} - - -void SDL_PumpEvents() -{ - // rationale: we would like to reduce CPU usage automatically if - // possible. blocking here until a message arrives would accomplish - // that, but might potentially freeze the app too long. - // instead, they should check active state and call SDL_Delay etc. - // if our window is minimized. - - mouse_Update(); // polled - - MSG msg; - while(PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) - { - (void)DispatchMessageW(&msg); // (returns window procedure's return value) - } -} - - - -int SDL_PollEvent(SDL_Event* ev) -{ - SDL_PumpEvents(); - - if(DequeueEvent(*ev)) - return 1; - - return 0; -} - - -int SDL_PushEvent(SDL_Event* ev) -{ - QueueEvent(*ev); - return 0; -} - - -//----------------------------------------------------------------------------- -// byte swapping - -// implement only if the header hasn't mapped SDL_Swap* to intrinsics - -#ifndef SDL_Swap16 -u16 SDL_Swap16(const u16 x) -{ - return (u16)(((x & 0xff) << 8) | (x >> 8)); -} -#endif - -#ifndef SDL_Swap32 -u32 SDL_Swap32(const u32 x) -{ - return (x << 24) | - (x >> 24) | - ((x << 8) & 0x00ff0000) | - ((x >> 8) & 0x0000ff00); -} -#endif - -#ifndef SDL_Swap64 -u64 SDL_Swap64(const u64 x) -{ - const u32 lo = (u32)(x & 0xFFFFFFFF); - const u32 hi = (u32)(x >> 32); - u64 ret = SDL_Swap32(lo); - ret <<= 32; - // careful: must shift var of type u64, not u32 - ret |= SDL_Swap32(hi); - return ret; -} -#endif - - -//----------------------------------------------------------------------------- -// multithread support - -// semaphores -// note: implementing these in terms of pthread sem_t doesn't help; -// this wrapper is very close to the Win32 routines. - -static HANDLE HANDLE_from_sem(SDL_sem* s) -{ - return (HANDLE)s; -} - -static SDL_sem* sem_from_HANDLE(HANDLE h) -{ - return (SDL_sem*)h; -} - -SDL_sem* SDL_CreateSemaphore(int cnt) -{ - HANDLE h = CreateSemaphore(0, cnt, std::numeric_limits::max(), 0); - return sem_from_HANDLE(h); -} - -void SDL_DestroySemaphore(SDL_sem* sem) -{ - HANDLE h = HANDLE_from_sem(sem); - WARN_IF_FALSE(CloseHandle(h)); -} - -int SDL_SemPost(SDL_sem* sem) -{ - HANDLE h = HANDLE_from_sem(sem); - return ReleaseSemaphore(h, 1, 0); -} - -int SDL_SemWait(SDL_sem* sem) -{ - HANDLE h = HANDLE_from_sem(sem); - return WaitForSingleObject(h, INFINITE); -} - - -//----------------------------------------------------------------------------- -// misc API - -void SDL_WM_SetCaption(const char* title, const char* icon) -{ - WARN_IF_FALSE(SetWindowTextA(g_hWnd, title)); - - // real SDL ignores this parameter, so we will follow suit. - UNUSED2(icon); -} - - -u32 SDL_GetTicks() -{ - return GetTickCount(); -} - - -void SDL_Delay(Uint32 ms) -{ - Sleep(ms); -} - - -void* SDL_GL_GetProcAddress(const char* name) -{ - return wglGetProcAddress(name); -} - - -//----------------------------------------------------------------------------- -// init/shutdown - -// defend against calling SDL_Quit twice (GameSetup does this to work -// around ATI driver breakage) -static ModuleInitState initState; - -static Status Init() -{ - key_Init(); - return INFO::OK; -} - -static void Shutdown() -{ - is_quitting = true; - - if(wutil_IsValidHandle(g_hDC)) - gammaRamp.RestoreOriginal(); - - if(wutil_IsValidHandle(g_hWnd)) - WARN_IF_FALSE(DestroyWindow(g_hWnd)); - - video_Shutdown(); -} - -int SDL_Init(Uint32 UNUSED(flags)) -{ - return (ModuleInit(&initState, Init) < 0)? -1 : 0; -} - -int SDL_InitSubSystem(Uint32 UNUSED(flags)) -{ - return 0; -} - -void SDL_Quit() -{ - ModuleShutdown(&initState, Shutdown); -} - - -static void RedirectStdout() -{ - // this process is apparently attached to a console, and users might be - // surprised to find that we redirected the output to a file, so don't. - if(wutil_IsValidHandle(GetStdHandle(STD_OUTPUT_HANDLE))) - return; - - WinScopedPreserveLastError s; // ChangeExtension - - // this code may be included in multiple executables sharing the same - // directory, so include the executable's name in the filename. use its - // full path since the current directory is unreliable. - const OsPath pathname = sys_ExecutablePathname().ChangeExtension(L"_stdout.txt"); - - // ignore BoundsChecker warnings here. subsystem is set to "Windows" - // to prevent the OS from opening a console on startup (ugly). - // that means stdout isn't associated with a lowio handle; _close is - // called with fd = -1. oh well, there's nothing we can do. - FILE* f = 0; - // ignore return value - it might indicate 'file already exists' even - // if f is valid, which is what actually counts. - (void)_wfreopen_s(&f, OsString(pathname).c_str(), L"wt", stdout); - if(GetLastError() == ERROR_ALREADY_EXISTS) - SetLastError(0); - // executable directory (probably Program Files) is read-only for - // non-Administrators. we can't pick another directory because - // ah_log_dir might not be valid until the app's init has run, - // nor should we pollute the (root) wutil_AppdataPath directory. - // since stdout usually isn't critical and is seen if launching the - // app from a console, just skip the redirection in this case. - if(f == 0) - return; - -#if CONFIG_ENABLE_CHECKS - // disable buffering, so that no writes are lost even if the program - // crashes. only enabled in full debug mode because this is really slow! - setvbuf(stdout, 0, _IONBF, 0); - #endif -} - -static Status wsdl_Init() -{ - // note: SDL does this in its WinMain hook. doing so in SDL_Init would be - // too late (we might miss some output), so we use winit. - // (this is possible because _cinit has already been called) - RedirectStdout(); - - return INFO::OK; -} - -static Status wsdl_Shutdown() -{ - // was redirected to stdout.txt; closing avoids a BoundsChecker warning. - fclose(stdout); - - return INFO::OK; -} - -#endif // #if CONFIG2_WSDL diff --git a/source/lib/sysdep/os/win/wsdl.h b/source/lib/sysdep/os/win/wsdl.h deleted file mode 100644 index 43a7de59f1..0000000000 --- a/source/lib/sysdep/os/win/wsdl.h +++ /dev/null @@ -1,343 +0,0 @@ -/* Copyright (c) 2012 Wildfire Games - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * emulate SDL on Windows. - */ - -#ifndef INCLUDED_WSDL -#define INCLUDED_WSDL - -#include "lib/lib_api.h" -#include "lib/byte_order.h" -#ifndef WSDL_NO_KEYSYM -# include "SDL_keysym.h" -#endif - -typedef u8 Uint8; -typedef u16 Uint16; -typedef i16 Sint16; -typedef u32 Uint32; - - -// SDL_Init flags -#define SDL_INIT_VIDEO 0 -#define SDL_INIT_AUDIO 0 -#define SDL_INIT_TIMER 0 -#define SDL_INIT_JOYSTICK 0 -#define SDL_INIT_NOPARACHUTE 0 - -LIB_API int SDL_Init(Uint32 flags); -LIB_API int SDL_InitSubSystem(Uint32 flags); - -LIB_API void SDL_Quit(); - - -// -// video -// - -typedef enum -{ - SDL_GL_DEPTH_SIZE, - SDL_GL_STENCIL_SIZE, - SDL_GL_DOUBLEBUFFER, // ignored - always double buffered - SDL_GL_SWAP_CONTROL -} -SDL_GLattr; - -LIB_API int SDL_GL_SetAttribute(SDL_GLattr attr, int value); - -// SDL_SetVideoMode() flags -#define SDL_OPENGL 0 -#define SDL_FULLSCREEN 1 -#define SDL_RESIZABLE 2 - -struct SDL_PixelFormat -{ - Uint8 BitsPerPixel; -}; - -struct SDL_Surface -{ - SDL_PixelFormat* format; - int w, h; -}; - -LIB_API SDL_Surface* SDL_SetVideoMode(int w, int h, int bpp, Uint32 flags); - -LIB_API SDL_Surface* SDL_GetVideoSurface(); - -typedef struct -{ - Uint32 video_mem; // total amount of video memory (in K) -} -SDL_VideoInfo; - -LIB_API SDL_VideoInfo* SDL_GetVideoInfo(); - -LIB_API void* SDL_GL_GetProcAddress(const char*); - -LIB_API void SDL_GL_SwapBuffers(); - -LIB_API int SDL_SetGamma(float r, float g, float b); - - -// -// semaphores -// - -typedef void SDL_sem; -LIB_API SDL_sem* SDL_CreateSemaphore(int cnt); -LIB_API void SDL_DestroySemaphore(SDL_sem*); -LIB_API int SDL_SemPost(SDL_sem*); -LIB_API int SDL_SemWait(SDL_sem* sem); - - -// -// time -// - -LIB_API u32 SDL_GetTicks(); -LIB_API void SDL_Delay(u32 ms); - - -// -// mouse -// - -LIB_API void SDL_WarpMouse(int, int); - -enum ShowCursorToggle -{ - SDL_DISABLE = 0, - SDL_ENABLE = 1, - SDL_QUERY = 2 -}; -LIB_API int SDL_ShowCursor(int toggle); - -LIB_API Uint8 SDL_GetMouseState(int* x, int* y); - - -// -// keyboard -// - -// from real SDL, but they're ignored anyway -#define SDL_DEFAULT_REPEAT_DELAY 500 -#define SDL_DEFAULT_REPEAT_INTERVAL 30 -#define SDL_EnableKeyRepeat(delay, interval) - -LIB_API Uint8* SDL_GetKeyState(int* num_keys); - - -// -// joystick -// - -typedef void* SDL_Joystick; -int SDL_NumJoysticks(); -int SDL_JoystickEventState(int state); -const char* SDL_JoystickName(int device_index); -SDL_Joystick* SDL_JoystickOpen(int device_index); -int SDL_JoystickNumAxes(SDL_Joystick* joystick); -Sint16 SDL_JoystickGetAxis(SDL_Joystick* joystick, int axis); - - -// -// byte swapping -// - -#define SDL_LIL_ENDIAN 1234 -#define SDL_BIG_ENDIAN 4321 - -#define SDL_BYTEORDER SDL_LIL_ENDIAN - -#define SDL_Swap16 swap16 -#define SDL_Swap32 swap32 -#define SDL_Swap64 swap64 - - -//----------------------------------------------------------------------------- -// events -//----------------------------------------------------------------------------- - -#ifndef WSDL_NO_KEYSYM - -typedef struct -{ - SDLKey sym; - u16 unicode; -} -SDL_keysym; - -typedef struct -{ - Uint8 type; - SDL_keysym keysym; -} -SDL_KeyboardEvent; - -#endif // #ifndef WSDL_NO_KEYSYM - -typedef struct -{ - Uint8 type; - u16 x, y; -} -SDL_MouseMotionEvent; - -typedef struct -{ - Uint8 type; -} -SDL_QuitEvent; - -typedef struct -{ - Uint8 type; -} -SDL_ExposeEvent; - -enum SDL_MouseButtonEvent_button -{ - // to remain compatible with regular SDL, these values must not change! - SDL_BUTTON_LEFT = 1, - SDL_BUTTON_MIDDLE = 2, - SDL_BUTTON_RIGHT = 3, - SDL_BUTTON_WHEELUP = 4, - SDL_BUTTON_WHEELDOWN = 5, - SDL_BUTTON_X1 = 6, - SDL_BUTTON_X2 = 7 -}; - -#define SDL_BUTTON(b) (1u << (b-1)) -#define SDL_BUTTON_LMASK SDL_BUTTON(SDL_BUTTON_LEFT) -#define SDL_BUTTON_MMASK SDL_BUTTON(SDL_BUTTON_MIDDLE) -#define SDL_BUTTON_RMASK SDL_BUTTON(SDL_BUTTON_RIGHT) -#define SDL_BUTTON_X1MASK SDL_BUTTON(SDL_BUTTON_X1) -#define SDL_BUTTON_X2MASK SDL_BUTTON(SDL_BUTTON_X2) - -enum SDL_MouseButtonEvent_state -{ - SDL_RELEASED = 0, - SDL_PRESSED = 1 -}; - -typedef struct -{ - Uint8 type; - u8 button; - u8 state; - u16 x, y; -} -SDL_MouseButtonEvent; - -enum SDL_ActiveEvent_state -{ - SDL_APPACTIVE = 1, - SDL_APPMOUSEFOCUS = 2, - SDL_APPINPUTFOCUS = 4 -}; - -typedef struct -{ - Uint8 type; - u8 gain; - u8 state; -} -SDL_ActiveEvent; - -typedef struct -{ - Uint8 type; - int w; - int h; -} -SDL_ResizeEvent; - -typedef struct -{ - Uint8 type; - int code; - void* data1; -} -SDL_UserEvent; - -enum SDL_Event_type -{ - SDL_KEYDOWN, - SDL_KEYUP, - SDL_MOUSEMOTION, - SDL_MOUSEBUTTONDOWN, - SDL_MOUSEBUTTONUP, - SDL_ACTIVEEVENT, - SDL_QUIT, - SDL_VIDEOEXPOSE, - SDL_VIDEORESIZE, - SDL_USEREVENT -}; - -typedef union -{ - Uint8 type; - SDL_ActiveEvent active; -#ifndef WSDL_NO_KEYSYM - SDL_KeyboardEvent key; -#endif - SDL_MouseMotionEvent motion; - SDL_MouseButtonEvent button; - SDL_ResizeEvent resize; - SDL_ExposeEvent expose; - SDL_QuitEvent quit; - SDL_UserEvent user; -} -SDL_Event; - -LIB_API int SDL_EnableUNICODE(int enable); -LIB_API int SDL_WaitEvent(SDL_Event*); -LIB_API int SDL_PollEvent(SDL_Event* ev); -LIB_API int SDL_PushEvent(SDL_Event* ev); - - -// -// misc -// - -enum SDL_GrabMode -{ - SDL_GRAB_QUERY, - SDL_GRAB_OFF, - SDL_GRAB_ON -}; -LIB_API SDL_GrabMode SDL_WM_GrabInput(SDL_GrabMode mode); - -#define SDL_GetError() "" - -LIB_API void SDL_WM_SetCaption(const char *title, const char *icon); - -LIB_API Uint8 SDL_GetAppState(); - -// Pretend that we always implement the latest version of SDL 1.2 (but not 1.3) -#define SDL_VERSION_ATLEAST(X, Y, Z) ((X) == 1 && (Y) <= 2) - -#endif // #ifndef INCLUDED_WSDL