SFML logo
  • Main Page
  • Namespaces
  • Classes
  • Files
  • File List

WindowImplWin32.cpp

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  ::