WindowImplWin32.cpp
00001 00002 // 00003 // SFML - Simple and Fast Multimedia Library 00004 // Copyright (C) 2007-2009 Laurent Gomila ([email protected]) 00005 // 00006 // This software is provided 'as-is', without any express or implied warranty. 00007 // In no event will the authors be held liable for any damages arising from the use of this software. 00008 // 00009 // Permission is granted to anyone to use this software for any purpose, 00010 // including commercial applications, and to alter it and redistribute it freely, 00011 // subject to the following restrictions: 00012 // 00013 // 1. The origin of this software must not be misrepresented; 00014 // you must not claim that you wrote the original software. 00015 // If you use this software in a product, an acknowledgment 00016 // in the product documentation would be appreciated but is not required. 00017 // 00018 // 2. Altered source versions must be plainly marked as such, 00019 // and must not be misrepresented as being the original software. 00020 // 00021 // 3. This notice may not be removed or altered from any source distribution. 00022 // 00024 00026 // Headers 00028 #define _WIN32_WINDOWS 0x0501 00029 #define _WIN32_WINNT 0x0501 00030 #include <SFML/Window/Win32/WindowImplWin32.hpp> 00031 #include <SFML/Window/WindowSettings.hpp> 00032 #include <SFML/Window/WindowStyle.hpp> 00033 #include <GL/gl.h> 00034 #include <SFML/Window/glext/wglext.h> 00035 #include <SFML/Window/glext/glext.h> 00036 #include <iostream> 00037 #include <vector> 00038 00039 // MinGW lacks the definition of some Win32 constants 00040 #ifndef XBUTTON1 00041 #define XBUTTON1 0x0001 00042 #endif 00043 #ifndef XBUTTON2 00044 #define XBUTTON2 0x0002 00045 #endif 00046 #ifndef MAPVK_VK_TO_VSC 00047 #define MAPVK_VK_TO_VSC (0) 00048 #endif 00049 00050 00051 namespace sf 00052 { 00053 namespace priv 00054 { 00056 // Static member data 00058 unsigned int WindowImplWin32::ourWindowCount = 0; 00059 const char* WindowImplWin32::ourClassNameA = "SFML_Window"; 00060 const wchar_t* WindowImplWin32::ourClassNameW = L"SFML_Window"; 00061 WindowImplWin32* WindowImplWin32::ourFullscreenWindow = NULL; 00062 00063 00068 WindowImplWin32::WindowImplWin32() : 00069 myHandle (NULL), 00070 myCallback (0), 00071 myCursor (NULL), 00072 myIcon (NULL), 00073 myKeyRepeatEnabled(true), 00074 myIsCursorIn (false) 00075 { 00076 // Register the window class at first call 00077 if (ourWindowCount == 0) 00078 RegisterWindowClass(); 00079 00080 // Use small dimensions 00081 myWidth = 1; 00082 myHeight = 1; 00083 00084 // Create a dummy window (disabled and hidden) 00085 if (HasUnicodeSupport()) 00086 { 00087 myHandle = CreateWindowW(ourClassNameW, L"", WS_POPUP | WS_DISABLED, 0, 0, myWidth, myHeight, NULL, NULL, GetModuleHandle(NULL), NULL); 00088 } 00089 else 00090 { 00091 myHandle = CreateWindowA(ourClassNameA, "", WS_POPUP | WS_DISABLED, 0, 0, myWidth, myHeight, NULL, NULL, GetModuleHandle(NULL), NULL); 00092 } 00093 ShowWindow(myHandle, SW_HIDE); 00094 00095 // Create the rendering context 00096 if (myHandle) 00097 { 00098 WindowSettings Params(0, 0, 0); 00099 CreateContext(VideoMode(myWidth, myHeight, 32), Params); 00100 00101 // Don't activate by default 00102 SetActive(false); 00103 } 00104 } 00105 00106 00110 WindowImplWin32::WindowImplWin32(WindowHandle Handle, WindowSettings& Params) : 00111 myHandle (NULL), 00112 myCallback (0), 00113 myCursor (NULL), 00114 myIcon (NULL), 00115 myKeyRepeatEnabled(true), 00116 myIsCursorIn (false) 00117 { 00118 // Save window handle 00119 myHandle = static_cast<HWND>(Handle); 00120 00121 if (myHandle) 00122 { 00123 // Get window client size 00124 RECT Rect; 00125 GetClientRect(myHandle, &Rect); 00126 myWidth = Rect.right - Rect.left; 00127 myHeight = Rect.bottom - Rect.top; 00128 00129 // Create the rendering context 00130 VideoMode Mode(myWidth, myHeight, VideoMode::GetDesktopMode().BitsPerPixel); 00131 CreateContext(Mode, Params); 00132 00133 // We change the event procedure of the control (it is important to save the old one) 00134 SetWindowLongPtr(myHandle, GWLP_USERDATA, reinterpret_cast<long>(this)); 00135 myCallback = SetWindowLongPtr(myHandle, GWLP_WNDPROC, reinterpret_cast<long>(&WindowImplWin32::GlobalOnEvent)); 00136 } 00137 } 00138 00139 00143 WindowImplWin32::WindowImplWin32(VideoMode Mode, const std::string& Title, unsigned long WindowStyle, WindowSettings& Params) : 00144 myHandle (NULL), 00145 myCallback (0), 00146 myCursor (NULL), 00147 myIcon (NULL), 00148 myKeyRepeatEnabled(true), 00149 myIsCursorIn (false) 00150 { 00151 // Register the window class at first call 00152 if (ourWindowCount == 0) 00153 RegisterWindowClass(); 00154 00155 // Compute position and size 00156 HDC ScreenDC = GetDC(NULL); 00157 int Left = (GetDeviceCaps(ScreenDC, HORZRES) - Mode.Width) / 2; 00158 int Top = (GetDeviceCaps(ScreenDC, VERTRES) - Mode.Height) / 2; 00159 int Width = myWidth = Mode.Width; 00160 int Height = myHeight = Mode.Height; 00161 ReleaseDC(NULL, ScreenDC); 00162 00163 // Choose the window style according to the Style parameter 00164 DWORD Win32Style = WS_VISIBLE; 00165 if (WindowStyle == Style::None) 00166 { 00167 Win32Style |= WS_POPUP; 00168 } 00169 else 00170 { 00171 if (WindowStyle & Style::Titlebar) Win32Style |= WS_CAPTION | WS_MINIMIZEBOX; 00172 if (WindowStyle & Style::Resize) Win32Style |= WS_THICKFRAME | WS_MAXIMIZEBOX; 00173 if (WindowStyle & Style::Close) Win32Style |= WS_SYSMENU; 00174 } 00175 00176 // In windowed mode, adjust width and height so that window will have the requested client area 00177 bool Fullscreen = (WindowStyle & Style::Fullscreen) != 0; 00178 if (!Fullscreen) 00179 { 00180 RECT Rect = {0, 0, Width, Height}; 00181 AdjustWindowRect(&Rect, Win32Style, false); 00182 Width = Rect.right - Rect.left; 00183 Height = Rect.bottom - Rect.top; 00184 } 00185 00186 // Create the window 00187 if (HasUnicodeSupport()) 00188 { 00189 wchar_t WTitle[256]; 00190 int NbChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, Title.c_str(), static_cast<int>(Title.size()), WTitle, sizeof(WTitle) / sizeof(*WTitle)); 00191 WTitle[NbChars] = L'\0'; 00192 myHandle = CreateWindowW(ourClassNameW, WTitle, Win32Style, Left, Top, Width, Height, NULL, NULL, GetModuleHandle(NULL), this); 00193 } 00194 else 00195 { 00196 myHandle = CreateWindowA(ourClassNameA, Title.c_str(), Win32Style, Left, Top, Width, Height, NULL, NULL, GetModuleHandle(NULL), this); 00197 } 00198 00199 // Switch to fullscreen if requested 00200 if (Fullscreen) 00201 SwitchToFullscreen(Mode); 00202 00203 // Create the rendering context 00204 if (myHandle) 00205 CreateContext(Mode, Params); 00206 00207 // Increment window count 00208 ourWindowCount++; 00209 00210 // Get the actual size of the window, which can be smaller even after the call to AdjustWindowRect 00211 // This happens when the window is bigger than the desktop 00212 RECT ActualRect; 00213 GetClientRect(myHandle, &ActualRect); 00214 myWidth = ActualRect.right - ActualRect.left; 00215 myHeight = ActualRect.bottom - ActualRect.top; 00216 } 00217 00218 00222 WindowImplWin32::~WindowImplWin32() 00223 { 00224 // Destroy the custom icon, if any 00225 if (myIcon) 00226 DestroyIcon(myIcon); 00227 00228 if (!myCallback) 00229 { 00230 // Destroy the window 00231 if (myHandle) 00232 DestroyWindow(myHandle); 00233 00234 // Decrement the window count 00235 ourWindowCount--; 00236 00237 // Unregister window class if we were the last window 00238 if (ourWindowCount == 0) 00239 { 00240 if (HasUnicodeSupport()) 00241 { 00242 UnregisterClassW(ourClassNameW, GetModuleHandle(NULL)); 00243 } 00244 else 00245 { 00246 UnregisterClassA(ourClassNameA, GetModuleHandle(NULL)); 00247 } 00248 } 00249 } 00250 else 00251 { 00252 // The window is external : remove the hook on its message callback 00253 SetWindowLongPtr(myHandle, GWLP_WNDPROC, myCallback); 00254 } 00255 } 00256 00257 00261 bool WindowImplWin32::IsContextActive() 00262 { 00263 return wglGetCurrentContext() != NULL; 00264 } 00265 00266 00270 void WindowImplWin32::ProcessEvents() 00271 { 00272 // We update the window only if we own it 00273 if (!myCallback) 00274 { 00275 MSG Message; 00276 while (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE)) 00277 { 00278 TranslateMessage(&Message); 00279 DispatchMessage(&Message); 00280 } 00281 } 00282 } 00283 00284 00288 void WindowImplWin32::Display() 00289 { 00290 if (myDeviceContext && myGLContext) 00291 SwapBuffers(myDeviceContext); 00292 } 00293 00294 00298 void WindowImplWin32::SetActive(bool Active) const 00299 { 00300 if (Active) 00301 { 00302 if (myDeviceContext && myGLContext && (wglGetCurrentContext() != myGLContext)) 00303 wglMakeCurrent(myDeviceContext, myGLContext); 00304 } 00305 else 00306 { 00307 if (wglGetCurrentContext() == myGLContext) 00308 wglMakeCurrent(NULL, NULL); 00309 } 00310 } 00311 00312 00316 void WindowImplWin32::UseVerticalSync(bool Enabled) 00317 { 00318 PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = reinterpret_cast<PFNWGLSWAPINTERVALEXTPROC>(wglGetProcAddress("wglSwapIntervalEXT")); 00319 if (wglSwapIntervalEXT) 00320 wglSwapIntervalEXT(Enabled ? 1 : 0); 00321 } 00322 00323 00327 void WindowImplWin32::ShowMouseCursor(bool Show) 00328 { 00329 if (Show) 00330 myCursor = LoadCursor(NULL, IDC_ARROW); 00331 else 00332 myCursor = NULL; 00333 00334 SetCursor(myCursor); 00335 } 00336 00337 00341 void WindowImplWin32::SetCursorPosition(unsigned int Left, unsigned int Top) 00342 { 00343 POINT Pos = {Left, Top}; 00344 ClientToScreen(myHandle, &Pos); 00345 SetCursorPos(Pos.x, Pos.y); 00346 } 00347 00348 00352 void WindowImplWin32::SetPosition(int Left, int Top) 00353 { 00354 SetWindowPos(myHandle, NULL, Left, Top, 0, 0, SWP_NOSIZE | SWP_NOZORDER); 00355 } 00356 00357 00361 void WindowImplWin32::SetSize(unsigned int Width, unsigned int Height) 00362 { 00363 // SetWindowPos wants the total size of the window (including title bar and borders), 00364 // so we have to compute it 00365 RECT Rect = {0, 0, Width, Height}; 00366 AdjustWindowRect(&Rect, GetWindowLong(myHandle, GWL_STYLE), false); 00367 Width = Rect.right - Rect.left; 00368 Height = Rect.bottom - Rect.top; 00369 00370 SetWindowPos(myHandle, NULL, 0, 0, Width, Height, SWP_NOMOVE | SWP_NOZORDER); 00371 } 00372 00373 00377 void WindowImplWin32::Show(bool State) 00378 { 00379 ShowWindow(myHandle, State ? SW_SHOW : SW_HIDE); 00380 } 00381 00382 00386 void WindowImplWin32::EnableKeyRepeat(bool Enabled) 00387 { 00388 myKeyRepeatEnabled = Enabled; 00389 } 00390 00391 00395 void WindowImplWin32::SetIcon(unsigned int Width, unsigned int Height, const Uint8* Pixels) 00396 { 00397 // First destroy the previous one 00398 if (myIcon) 00399 DestroyIcon(myIcon); 00400 00401 // Windows wants BGRA pixels : swap red and blue channels 00402 std::vector<Uint8> IconPixels(Width * Height * 4); 00403 for (std::size_t i = 0; i < IconPixels.size() / 4; ++i) 00404 { 00405 IconPixels[i * 4 + 0] = Pixels[i * 4 + 2]; 00406 IconPixels[i * 4 + 1] = Pixels[i * 4 + 1]; 00407 IconPixels[i * 4 + 2] = Pixels[i * 4 + 0]; 00408 IconPixels[i * 4 + 3] = Pixels[i * 4 + 3]; 00409 } 00410 00411 // Create the icon from the pixels array 00412 myIcon = CreateIcon(GetModuleHandle(NULL), Width, Height, 1, 32, NULL, &IconPixels[0]); 00413 00414 // Set it as both big and small icon of the window 00415 if (myIcon) 00416 { 00417 SendMessage(myHandle, WM_SETICON, ICON_BIG, (LPARAM)myIcon); 00418 SendMessage(myHandle, WM_SETICON, ICON_SMALL, (LPARAM)myIcon); 00419 } 00420 else 00421 { 00422 std::cerr << "Failed to set the window's icon" << std::endl; 00423 } 00424 } 00425 00426 00430 void WindowImplWin32::RegisterWindowClass() 00431 { 00432 if (HasUnicodeSupport()) 00433 { 00434 WNDCLASSW WindowClass; 00435 WindowClass.style = 0; 00436 WindowClass.lpfnWndProc = &WindowImplWin32::GlobalOnEvent; 00437 WindowClass.cbClsExtra = 0; 00438 WindowClass.cbWndExtra = 0; 00439 WindowClass.hInstance = GetModuleHandle(NULL); 00440 WindowClass.hIcon = NULL; 00441 WindowClass.hCursor = 0; 00442 WindowClass.hbrBackground = 0; 00443 WindowClass.lpszMenuName = NULL; 00444 WindowClass.lpszClassName = ourClassNameW; 00445 RegisterClassW(&WindowClass); 00446 } 00447 else 00448 { 00449 WNDCLASSA WindowClass; 00450 WindowClass.style = 0; 00451 WindowClass.lpfnWndProc = &WindowImplWin32::GlobalOnEvent; 00452 WindowClass.cbClsExtra = 0; 00453 WindowClass.cbWndExtra = 0; 00454 WindowClass.hInstance = GetModuleHandle(NULL); 00455 WindowClass.hIcon = NULL; 00456 WindowClass.hCursor = 0; 00457 WindowClass.hbrBackground = 0; 00458 WindowClass.lpszMenuName = NULL; 00459 WindowClass.lpszClassName = ourClassNameA; 00460 RegisterClassA(&WindowClass); 00461 } 00462 } 00463 00464 00468 void WindowImplWin32::SwitchToFullscreen(const VideoMode& Mode) 00469 { 00470 DEVMODE DevMode; 00471 DevMode.dmSize = sizeof(DEVMODE); 00472 DevMode.dmPelsWidth = Mode.Width; 00473 DevMode.dmPelsHeight = Mode.Height; 00474 DevMode.dmBitsPerPel = Mode.BitsPerPixel; 00475 DevMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL; 00476 00477 // Apply fullscreen mode 00478 if (ChangeDisplaySettings(&DevMode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) 00479 { 00480 std::cerr << "Failed to change display mode for fullscreen" << std::endl; 00481 return; 00482 } 00483 00484 // Make the window flags compatible with fullscreen mode 00485 SetWindowLong(myHandle, GWL_STYLE, WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); 00486 SetWindowLong(myHandle, GWL_EXSTYLE, WS_EX_APPWINDOW); 00487 00488 // Resize the window so that it fits the entire screen 00489 SetWindowPos(myHandle, HWND_TOP, 0, 0, Mode.Width, Mode.Height, SWP_FRAMECHANGED); 00490 ShowWindow(myHandle, SW_SHOW); 00491 00492 // Set "this" as the current fullscreen window 00493 ourFullscreenWindow = this; 00494 } 00495 00496 00500 void WindowImplWin32::CreateContext(const VideoMode& Mode, WindowSettings& Params) 00501 { 00502 // Get the device context attached to the window 00503 myDeviceContext = GetDC(myHandle); 00504 if (myDeviceContext == NULL) 00505 { 00506 std::cerr << "Failed to get device context of window -- cannot create OpenGL context" << std::endl; 00507 return; 00508 } 00509 00510 // Let's find a suitable pixel format -- first try with antialiasing 00511 int BestFormat = 0; 00512 if (Params.AntialiasingLevel > 0) 00513 { 00514 // Get the wglChoosePixelFormatARB function (it is an extension) 00515 PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = reinterpret_cast<PFNWGLCHOOSEPIXELFORMATARBPROC>(wglGetProcAddress("wglChoosePixelFormatARB")); 00516 if (wglChoosePixelFormatARB) 00517 { 00518 // Define the basic attributes we want for our window 00519 int IntAttributes[] = 00520 { 00521 WGL_DRAW_TO_WINDOW_ARB, GL_TRUE, 00522 WGL_SUPPORT_OPENGL_ARB, GL_TRUE, 00523 WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, 00524 WGL_DOUBLE_BUFFER_ARB, GL_TRUE, 00525 WGL_SAMPLE_BUFFERS_ARB, (Params.AntialiasingLevel ? GL_TRUE : GL_FALSE), 00526 WGL_SAMPLES_ARB, Params.AntialiasingLevel, 00527 0, 0 00528 }; 00529 00530 // Let's check how many formats are supporting our requirements 00531 int Formats[128]; 00532 UINT NbFormats; 00533 float FloatAttributes[] = {0, 0}; 00534 bool IsValid = wglChoosePixelFormatARB(myDeviceContext, IntAttributes, FloatAttributes, sizeof(Formats) / sizeof(*Formats), Formats, &NbFormats) != 0; 00535 if (!IsValid || (NbFormats == 0)) 00536 { 00537 if (Params.AntialiasingLevel > 2) 00538 { 00539 // No format matching our needs : reduce the multisampling level 00540 std::cerr << "Failed to find a pixel format supporting " 00541 << Params.AntialiasingLevel << " antialiasing levels ; trying with 2 levels" << std::endl; 00542 00543 Params.AntialiasingLevel = IntAttributes[11] = 2; 00544 IsValid = wglChoosePixelFormatARB(myDeviceContext, IntAttributes, FloatAttributes, sizeof(Formats) / sizeof(*Formats), Formats, &NbFormats) != 0; 00545 } 00546 00547 if (!IsValid || (NbFormats == 0)) 00548 { 00549 // Cannot find any pixel format supporting multisampling ; disabling antialiasing 00550 std::cerr << "Failed to find a pixel format supporting antialiasing ; antialiasing will be disabled" << std::endl; 00551 Params.AntialiasingLevel = 0; 00552 } 00553 } 00554 00555 // Get the best format among the returned ones 00556 if (IsValid && (NbFormats > 0)) 00557 { 00558 int BestScore = 0xFFFF; 00559 for (UINT i = 0; i < NbFormats; ++i) 00560 { 00561 // Get the current format's attributes 00562 PIXELFORMATDESCRIPTOR Attribs; 00563 Attribs.nSize = sizeof(PIXELFORMATDESCRIPTOR); 00564 Attribs.nVersion = 1; 00565 DescribePixelFormat(myDeviceContext, Formats[i], sizeof(PIXELFORMATDESCRIPTOR), &Attribs); 00566 00567 // Evaluate the current configuration 00568 int Color = Attribs.cRedBits + Attribs.cGreenBits + Attribs.cBlueBits + Attribs.cAlphaBits; 00569 int Score = EvaluateConfig(Mode, Params, Color, Attribs.cDepthBits, Attribs.cStencilBits, Params.AntialiasingLevel); 00570 00571 // Keep it if it's better than the current best 00572 if (Score < BestScore) 00573 { 00574 BestScore = Score; 00575 BestFormat = Formats[i]; 00576 } 00577 } 00578 } 00579 } 00580 else 00581 { 00582 // wglChoosePixelFormatARB not supported ; disabling antialiasing 00583 std::cerr << "Antialiasing is not supported ; it will be disabled" << std::endl; 00584 Params.AntialiasingLevel = 0; 00585 } 00586 } 00587 00588 // Find a pixel format with no antialiasing, if not needed or not supported 00589 if (BestFormat == 0) 00590 { 00591 // Setup a pixel format descriptor from the rendering settings 00592 PIXELFORMATDESCRIPTOR PixelDescriptor; 00593 ZeroMemory(&PixelDescriptor, sizeof(PIXELFORMATDESCRIPTOR)); 00594 PixelDescriptor.nSize = sizeof(PIXELFORMATDESCRIPTOR); 00595 PixelDescriptor.nVersion = 1; 00596 PixelDescriptor.iLayerType = PFD_MAIN_PLANE; 00597 PixelDescriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; 00598 PixelDescriptor.iPixelType = PFD_TYPE_RGBA; 00599 PixelDescriptor.cColorBits = static_cast<BYTE>(Mode.BitsPerPixel); 00600 PixelDescriptor.cDepthBits = static_cast<BYTE>(Params.DepthBits); 00601 PixelDescriptor.cStencilBits = static_cast<BYTE>(Params.StencilBits); 00602 PixelDescriptor.cAlphaBits = Mode.BitsPerPixel == 32 ? 8 : 0; 00603 00604 // Get the pixel format that best matches our requirements 00605 BestFormat = ChoosePixelFormat(myDeviceContext, &PixelDescriptor); 00606 if (BestFormat == 0) 00607 { 00608 std::cerr << "Failed to find a suitable pixel format for device context -- cannot create OpenGL context" << std::endl; 00609 return; 00610 } 00611 } 00612 00613 // Extract the depth and stencil bits from the chosen format 00614 PIXELFORMATDESCRIPTOR ActualFormat; 00615 ActualFormat.nSize = sizeof(PIXELFORMATDESCRIPTOR); 00616 ActualFormat.nVersion = 1; 00617 DescribePixelFormat(myDeviceContext, BestFormat, sizeof(PIXELFORMATDESCRIPTOR), &ActualFormat); 00618 Params.DepthBits = ActualFormat.cDepthBits; 00619 Params.StencilBits = ActualFormat.cStencilBits; 00620 00621 // Set the chosen pixel format 00622 if (!SetPixelFormat(myDeviceContext, BestFormat, &ActualFormat)) 00623 { 00624 std::cerr << "Failed to set pixel format for device context -- cannot create OpenGL context" << std::endl; 00625 return; 00626 } 00627 00628 // Create the OpenGL context from the device context 00629 myGLContext = wglCreateContext(myDeviceContext); 00630 if (myGLContext == NULL) 00631 { 00632 std::cerr << "Failed to create an OpenGL context for this window" << std::endl; 00633 return; 00634 } 00635 00636 // Share display lists with other contexts 00637 HGLRC CurrentContext = wglGetCurrentContext(); 00638 if (CurrentContext) 00639 wglShareLists(CurrentContext, myGLContext); 00640 00641 // Activate the context 00642 SetActive(true); 00643 00644 // Enable multisampling 00645 if (Params.AntialiasingLevel > 0) 00646 glEnable(GL_MULTISAMPLE_ARB); 00647 } 00648 00649 00653 void WindowImplWin32::Cleanup() 00654 { 00655 // Restore the previous video mode (in case we were running in fullscreen) 00656 if (ourFullscreenWindow == this) 00657 { 00658 ChangeDisplaySettings(NULL, 0); 00659 ourFullscreenWindow = NULL; 00660 } 00661 00662 // Unhide the mouse cursor (in case it was hidden) 00663 ShowMouseCursor(true); 00664 00665 // Destroy the OpenGL context 00666 if (myGLContext) 00667 { 00668 // Unbind the context before destroying it 00669 SetActive(false); 00670 00671 wglDeleteContext(myGLContext); 00672 myGLContext = NULL; 00673 } 00674 if (myDeviceContext) 00675 { 00676 ReleaseDC(myHandle, myDeviceContext); 00677 myDeviceContext = NULL; 00678 } 00679 } 00680 00681 00685 void WindowImplWin32::ProcessEvent(UINT Message, WPARAM WParam, LPARAM LParam) 00686 { 00687 // Don't process any message until window is created 00688 if (myHandle == NULL) 00689 return; 00690 00691 switch (Message) 00692 { 00693 // Destroy event 00694 case WM_DESTROY : 00695 { 00696 // Here we must cleanup resources ! 00697 Cleanup(); 00698 break; 00699 } 00700 00701 // Set cursor event 00702 case WM_SETCURSOR : 00703 { 00704 // The mouse has moved, if the cursor is in our window we must refresh the cursor 00705 if (LOWORD(LParam) == HTCLIENT) 00706 SetCursor(myCursor); 00707 00708 break; 00709 } 00710 00711 // Close event 00712 case WM_CLOSE : 00713 { 00714 Event Evt; 00715 Evt.Type = Event::Closed; 00716 SendEvent(Evt); 00717 break; 00718 } 00719 00720 // Resize event 00721 case WM_SIZE : 00722 { 00723 // Update window size 00724 RECT Rect; 00725 GetClientRect(myHandle, &Rect); 00726 myWidth = Rect.right - Rect.left; 00727 myHeight = Rect.bottom - Rect.top; 00728 00729 Event Evt; 00730 Evt.Type = Event::Resized; 00731 Evt.Size.Width = myWidth; 00732 Evt.Size.Height = myHeight; 00733 SendEvent(Evt); 00734 break; 00735 } 00736 00737 // Gain focus event 00738 case WM_SETFOCUS : 00739 { 00740 Event Evt; 00741 Evt.Type = Event::GainedFocus; 00742 SendEvent(Evt); 00743 break; 00744 } 00745 00746 // Lost focus event 00747 case WM_KILLFOCUS : 00748 { 00749 Event Evt; 00750 Evt.Type = Event::LostFocus; 00751 SendEvent(Evt); 00752 break; 00753 } 00754 00755 // Text event 00756 case WM_CHAR : 00757 { 00758 if (myKeyRepeatEnabled || ((LParam & (1 << 30)) == 0)) 00759 { 00760 Event Evt; 00761 Evt.Type = Event::TextEntered; 00762 Evt.Text.Unicode = static_cast<Uint32>(WParam); 00763 SendEvent(Evt); 00764 } 00765 break; 00766 } 00767 00768 // Keydown event 00769 case WM_KEYDOWN : 00770 case WM_SYSKEYDOWN : 00771 { 00772 if (myKeyRepeatEnabled || ((HIWORD(LParam) & KF_REPEAT) == 0)) 00773 { 00774 Event Evt; 00775 Evt.Type = Event::KeyPressed; 00776 Evt.Key.Alt = HIWORD(GetAsyncKeyState(VK_MENU)) != 0; 00777 Evt.Key.Control = HIWORD(GetAsyncKeyState(VK_CONTROL)) != 0; 00778 Evt.Key.Shift = HIWORD(GetAsyncKeyState(VK_SHIFT)) != 0; 00779 Evt.Key.Code = VirtualKeyCodeToSF(WParam, LParam); 00780 SendEvent(Evt); 00781 } 00782 break; 00783 } 00784 00785 // Keyup event 00786 case WM_KEYUP : 00787 case WM_SYSKEYUP : 00788 { 00789 Event Evt; 00790 Evt.Type = Event::KeyReleased; 00791 Evt.Key.Alt = HIWORD(GetAsyncKeyState(VK_MENU)) != 0; 00792 Evt.Key.Control = HIWORD(GetAsyncKeyState(VK_CONTROL)) != 0; 00793 Evt.Key.Shift = HIWORD(GetAsyncKeyState(VK_SHIFT)) != 0; 00794 Evt.Key.Code = VirtualKeyCodeToSF(WParam, LParam); 00795 SendEvent(Evt); 00796 00797 break; 00798 } 00799 00800 // Mouse wheel event 00801 case WM_MOUSEWHEEL : 00802 { 00803 Event Evt; 00804 Evt.Type = Event::MouseWheelMoved; 00805 Evt.MouseWheel.Delta = static_cast<Int16>(HIWORD(WParam)) / 120; 00806 SendEvent(Evt); 00807 break; 00808 } 00809 00810 // Mouse left button down event 00811 case WM_LBUTTONDOWN : 00812 { 00813 Event Evt; 00814 Evt.Type = Event::MouseButtonPressed; 00815 Evt.MouseButton.Button = Mouse::Left; 00816 Evt.MouseButton.X = LOWORD(LParam); 00817 Evt.MouseButton.Y = HIWORD(LParam); 00818 SendEvent(Evt); 00819 break; 00820 } 00821 00822 // Mouse left button up event 00823 case WM_LBUTTONUP : 00824 { 00825 Event Evt; 00826 Evt.Type = Event::MouseButtonReleased; 00827 Evt.MouseButton.Button = Mouse::Left; 00828 Evt.MouseButton.X = LOWORD(LParam); 00829 Evt.MouseButton.Y = HIWORD(LParam); 00830 SendEvent(Evt); 00831 break; 00832 } 00833 00834 // Mouse right button down event 00835 case WM_RBUTTONDOWN : 00836 { 00837 Event Evt; 00838 Evt.Type = Event::MouseButtonPressed; 00839 Evt.MouseButton.Button = Mouse::Right; 00840 Evt.MouseButton.X = LOWORD(LParam); 00841 Evt.MouseButton.Y = HIWORD(LParam); 00842 SendEvent(Evt); 00843 break; 00844 } 00845 00846 // Mouse right button up event 00847 case WM_RBUTTONUP : 00848 { 00849 Event Evt; 00850 Evt.Type = Event::MouseButtonReleased; 00851 Evt.MouseButton.Button = Mouse::Right; 00852 Evt.MouseButton.X = LOWORD(LParam); 00853 Evt.MouseButton.Y = HIWORD(LParam); 00854 SendEvent(Evt); 00855 break; 00856 } 00857 00858 // Mouse wheel button down event 00859 case WM_MBUTTONDOWN : 00860 { 00861 Event Evt; 00862 Evt.Type = Event::MouseButtonPressed; 00863 Evt.MouseButton.Button = Mouse::Middle; 00864 Evt.MouseButton.X = LOWORD(LParam); 00865 Evt.MouseButton.Y = HIWORD(LParam); 00866 SendEvent(Evt); 00867 break; 00868 } 00869 00870 // Mouse wheel button up event 00871 case WM_MBUTTONUP : 00872 { 00873 Event Evt; 00874 Evt.Type = Event::MouseButtonReleased; 00875 Evt.MouseButton.Button = Mouse::Middle; 00876 Evt.MouseButton.X = LOWORD(LParam); 00877 Evt.MouseButton.Y = HIWORD(LParam); 00878 SendEvent(Evt); 00879 break; 00880 } 00881 00882 // Mouse X button down event 00883 case WM_XBUTTONDOWN : 00884 { 00885 Event Evt; 00886 Evt.Type = Event::MouseButtonPressed; 00887 Evt.MouseButton.Button = HIWORD(WParam) == XBUTTON1 ? Mouse::XButton1 : Mouse::XButton2; 00888 Evt.MouseButton.X = LOWORD(LParam); 00889 Evt.MouseButton.Y = HIWORD(LParam); 00890 SendEvent(Evt); 00891 break; 00892 } 00893 00894 // Mouse X button up event 00895 case WM_XBUTTONUP : 00896 { 00897 Event Evt; 00898 Evt.Type = Event::MouseButtonReleased; 00899 Evt.MouseButton.Button = HIWORD(WParam) == XBUTTON1 ? Mouse::XButton1 : Mouse::XButton2; 00900 Evt.MouseButton.X = LOWORD(LParam); 00901 Evt.MouseButton.Y = HIWORD(LParam); 00902 SendEvent(Evt); 00903 break; 00904 } 00905 00906 // Mouse move event 00907 case WM_MOUSEMOVE : 00908 { 00909 // Check if we need to generate a MouseEntered event 00910 if (!myIsCursorIn) 00911 { 00912 TRACKMOUSEEVENT MouseEvent; 00913 MouseEvent.cbSize = sizeof(TRACKMOUSEEVENT); 00914 MouseEvent.hwndTrack = myHandle; 00915 MouseEvent.dwFlags = TME_LEAVE; 00916 TrackMouseEvent(&MouseEvent); 00917 00918 myIsCursorIn = true; 00919 00920 Event Evt; 00921 Evt.Type = Event::MouseEntered; 00922 SendEvent(Evt); 00923 } 00924 00925 Event Evt; 00926 Evt.Type = Event::MouseMoved; 00927 Evt.MouseMove.X = LOWORD(LParam); 00928 Evt.MouseMove.Y = HIWORD(LParam); 00929 SendEvent(Evt); 00930 break; 00931 } 00932 00933 // Mouse leave event 00934 case WM_MOUSELEAVE : 00935 { 00936 myIsCursorIn = false; 00937 00938 Event Evt; 00939 Evt.Type = Event::MouseLeft; 00940 SendEvent(Evt); 00941 break; 00942 } 00943 } 00944 } 00945 00946 00950 Key::Code WindowImplWin32::VirtualKeyCodeToSF(WPARAM VirtualKey, LPARAM Flags) 00951 { 00952 switch (VirtualKey) 00953 { 00954 // Check the scancode to distinguish between left and right shift 00955 case VK_SHIFT : 00956 { 00957 static UINT LShift = MapVirtualKey(VK_LSHIFT, MAPVK_VK_TO_VSC); 00958 UINT scancode = (Flags & (0xFF << 16)) >> 16; 00959 return scancode == LShift ? Key::LShift : Key::RShift; 00960 } 00961 00962 // Check the "extended" flag to distinguish between left and right alt 00963 case VK_MENU : return (HIWORD(Flags) & KF_EXTENDED) ? Key::RAlt : Key::LAlt; 00964 00965 // Check the "extended" flag to distinguish between left and right control 00966 case VK_CONTROL : return (HIWORD(Flags) & KF_EXTENDED) ? Key::RControl : Key::LControl; 00967 00968 // Other keys are reported properly 00969 case VK_LWIN : return Key::LSystem; 00970 case VK_RWIN : return Key::RSystem; 00971 case VK_APPS : return Key::Menu; 00972 case VK_OEM_1 : return Key::SemiColon; 00973 case VK_OEM_2 : return Key::Slash; 00974 case VK_OEM_PLUS : return Key::Equal; 00975 case VK_OEM_MINUS : return Key::Dash; 00976 case VK_OEM_4 : return Key::LBracket; 00977 case VK_OEM_6 : return Key::RBracket; 00978 case VK_OEM_COMMA : return Key::Comma; 00979 case VK_OEM_PERIOD : return Key::Period; 00980 case VK_OEM_7 : return Key::Quote; 00981 case VK_OEM_5 : return Key::BackSlash; 00982 case VK_OEM_3 : return Key::Tilde; 00983 case VK_ESCAPE : return Key::Escape; 00984 case VK_SPACE : return Key::Space; 00985 case VK_RETURN : return Key::Return; 00986 case VK_BACK : return Key::Back; 00987 case VK_TAB : return Key::Tab; 00988 case VK_PRIOR : return Key::PageUp; 00989 case VK_NEXT : return Key::PageDown; 00990 case VK_END : return Key::End; 00991 case VK_HOME : return Key::Home; 00992 case VK_INSERT : return Key::Insert; 00993 case VK_DELETE : return Key::Delete; 00994 case VK_ADD : return Key::Add; 00995 case VK_SUBTRACT : return Key::Subtract; 00996 case VK_MULTIPLY : return Key::Multiply; 00997 case VK_DIVIDE : return Key::Divide; 00998 case VK_PAUSE : return Key::Pause; 00999 case VK_F1 : return Key::F1; 01000 case VK_F2 : return Key::F2; 01001 case VK_F3 : return Key::F3; 01002 case VK_F4 : return Key::F4; 01003 case VK_F5 : return Key::F5; 01004 case VK_F6 : return Key::F6; 01005 case VK_F7 : return Key::F7; 01006 case VK_F8 : return Key::F8; 01007 case VK_F9 : return Key::F9; 01008 case VK_F10 : return Key::F10; 01009 case VK_F11 : return Key::F11; 01010 case VK_F12 : return Key::F12; 01011 case VK_F13 : return Key::F13; 01012 case VK_F14 : return Key::F14; 01013 case VK_F15 : return Key::F15; 01014 case VK_LEFT : return Key::Left; 01015 case VK_RIGHT : return Key::Right; 01016 case VK_UP : return Key::Up; 01017 case VK_DOWN : return Key::Down; 01018 case VK_NUMPAD0 : return Key::Numpad0; 01019 case VK_NUMPAD1 : return Key::Numpad1; 01020 case VK_NUMPAD2 : return Key::Numpad2; 01021 case VK_NUMPAD3 : return Key::Numpad3; 01022 case VK_NUMPAD4 : return Key::Numpad4; 01023 case VK_NUMPAD5 : return Key::Numpad5; 01024 case VK_NUMPAD6 : return Key::Numpad6; 01025 case VK_NUMPAD7 : return Key::Numpad7; 01026 case VK_NUMPAD8 : return Key::Numpad8; 01027 case VK_NUMPAD9 : return Key::Numpad9; 01028 case 'A' : return Key::A; 01029 case 'Z' : return Key::Z; 01030 case 'E' : return Key::E; 01031 case 'R' : return Key::R; 01032 case 'T' : return Key::T; 01033 case 'Y' : return Key::Y; 01034 case 'U' : return Key::U; 01035 case 'I' : return Key::I; 01036 case 'O' : return Key::O; 01037 case 'P' : return Key::P; 01038 case 'Q' : return Key::Q; 01039 case 'S' : return Key::S; 01040 case 'D' : return Key::D; 01041 case 'F' : return Key::F; 01042 case 'G' : return Key::G; 01043 case 'H' : return Key::H; 01044 case 'J' : return Key::J; 01045 case 'K' : return Key::K; 01046 case 'L' : return Key::L; 01047 case 'M' : return Key::M; 01048 case 'W' : return Key::W; 01049 case 'X' : return Key::X; 01050 case 'C' : return Key::C; 01051 case 'V' : return Key::V; 01052 case 'B' : return Key::B; 01053 case 'N' : return Key::N; 01054 case '0' : return Key::Num0; 01055 case '1' : return Key::Num1; 01056 case '2' : return Key::Num2; 01057 case '3' : return Key::Num3; 01058 case '4' : return Key::Num4; 01059 case '5' : return Key::Num5; 01060 case '6' : return Key::Num6; 01061 case '7' : return Key::Num7; 01062 case '8' : return Key::Num8; 01063 case '9' : return Key::Num9; 01064 } 01065 01066 return Key::Code(0); 01067 } 01068 01069 01075 bool WindowImplWin32::HasUnicodeSupport() 01076 { 01077 OSVERSIONINFO VersionInfo; 01078 ZeroMemory(&VersionInfo, sizeof(VersionInfo)); 01079 VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo); 01080 01081 if (GetVersionEx(&VersionInfo)) 01082 { 01083 return VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT; 01084 } 01085 else 01086 { 01087 return false; 01088 } 01089 } 01090 01091 01095 LRESULT CALLBACK WindowImplWin32::GlobalOnEvent(HWND Handle, UINT Message, WPARAM WParam, LPARAM LParam) 01096 { 01097 // Associate handle and Window instance when the creation message is received 01098 if (Message == WM_CREATE) 01099 { 01100 // Get WindowImplWin32 instance (it was passed as the last argument of CreateWindow) 01101 long This = reinterpret_cast<long>(reinterpret_cast<CREATESTRUCT*>(LParam)->lpCreateParams); 01102 01103 // Set as the "user data" parameter of the window 01104 SetWindowLongPtr(Handle, GWLP_USERDATA, This); 01105 } 01106 01107 // Get the WindowImpl instance corresponding to the window handle 01108 WindowImplWin32* Window = reinterpret_cast<WindowImplWin32*>(GetWindowLongPtr(Handle, GWLP_USERDATA)); 01109 01110 // Forward the event to the appropriate function 01111 if (Window) 01112 { 01113 Window->ProcessEvent(Message, WParam, LParam); 01114 01115 if (Window->myCallback) 01116 return CallWindowProc(reinterpret_cast<WNDPROC>(Window->myCallback), Handle, Message, WParam, LParam); 01117 } 01118 01119 // We don't forward the WM_CLOSE message to prevent the OS from automatically destroying the window 01120 if (Message == WM_CLOSE) 01121 return 0; 01122 01123 static const bool HasUnicode = HasUnicodeSupport(); 01124 return HasUnicode ? DefWindowProcW(Handle, Message, WParam, LParam) : 01125 DefWindowProcA(Handle, Message, WParam, LParam); 01126 } 01127 01128 } // namespace priv 01129 01130 } // namespace sf
:: Copyright © 2007-2008 Laurent Gomila, all rights reserved :: Documentation generated by doxygen 1.5.2 ::