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