WindowImplWin32.cpp

00001 
00002 //
00003 // SFML - Simple and Fast Multimedia Library
00004 // Copyright (C) 2007 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_WINNT 0x500
00029 #include <SFML/Window/Win32/WindowImplWin32.hpp>
00030 #include <GL/gl.h>
00031 #include <SFML/Window/glext/wglext.h>
00032 #include <SFML/Window/glext/glext.h>
00033 #include <mmsystem.h>
00034 #include <iostream>
00035 
00036 
00037 namespace sf
00038 {
00039 namespace priv
00040 {
00042 // Static member data
00044 unsigned int     WindowImplWin32::ourWindowCount      = 0;
00045 const wchar_t*   WindowImplWin32::ourClassName        = L"SFML_Window";
00046 WindowImplWin32* WindowImplWin32::ourDummyWindow      = NULL;
00047 WindowImplWin32* WindowImplWin32::ourFullscreenWindow = NULL;
00048 
00049 
00054 WindowImplWin32::WindowImplWin32() :
00055 myHandle  (NULL),
00056 myCallback(0),
00057 myCursor  (NULL)
00058 {
00059     // Register the window class at first call
00060     if (ourWindowCount == 0)
00061         RegisterWindowClass();
00062 
00063     // Use small dimensions
00064     myWidth  = 1;
00065     myHeight = 1;
00066 
00067     // Create a dummy window (disabled and hidden)
00068     myHandle = CreateWindow(ourClassName, TEXT(""), WS_POPUP | WS_DISABLED, 0, 0, myWidth, myHeight, NULL, NULL, GetModuleHandle(NULL), NULL);
00069     ShowWindow(myHandle, SW_HIDE);
00070 
00071     // Create the rendering context
00072     if (myHandle)
00073         CreateContext(VideoMode(myWidth, myHeight, 32), false, 0);
00074 
00075     // Save as the dummy window
00076     if (!ourDummyWindow)
00077         ourDummyWindow = this;
00078 }
00079 
00080 
00084 WindowImplWin32::WindowImplWin32(WindowHandle Handle, int AntialiasingLevel) :
00085 myCallback(0),
00086 myCursor  (NULL)
00087 {
00088     // Save window handle
00089     myHandle = static_cast<HWND>(Handle);
00090 
00091     if (myHandle)
00092     {
00093         // Get window client size
00094         RECT Rect;
00095         GetClientRect(myHandle, &Rect);
00096         myWidth  = Rect.right - Rect.left;
00097         myHeight = Rect.bottom - Rect.top;
00098 
00099         // Create the rendering context
00100         VideoMode Mode = VideoMode::GetDesktopMode();
00101         Mode.Width  = myWidth;
00102         Mode.Height = myHeight;
00103         CreateContext(Mode, false, AntialiasingLevel);
00104 
00105         // We change the event procedure of the control (it is important to save the old one)
00106         SetWindowLongPtr(myHandle, GWLP_USERDATA, reinterpret_cast<long>(this));
00107         myCallback = SetWindowLongPtr(myHandle, GWLP_WNDPROC, reinterpret_cast<long>(&WindowImplWin32::GlobalOnEvent));
00108 
00109         // Setup joysticks
00110         SetupJoysticks();
00111     }
00112 }
00113 
00114 
00118 WindowImplWin32::WindowImplWin32(VideoMode Mode, const std::string& Title, unsigned long WindowStyle, int AntialiasingLevel) :
00119 myHandle  (NULL),
00120 myCallback(0),
00121 myCursor  (NULL)
00122 {
00123     // Register the window class at first call
00124     if (ourWindowCount == 0)
00125         RegisterWindowClass();
00126 
00127     // Compute position and size
00128     int Left   = (GetDeviceCaps(GetDC(NULL), HORZRES) - Mode.Width)  / 2;
00129     int Top    = (GetDeviceCaps(GetDC(NULL), VERTRES) - Mode.Height) / 2;
00130     int Width  = myWidth  = Mode.Width;
00131     int Height = myHeight = Mode.Height;
00132 
00133     // Choose the window style according to the Style parameter
00134     DWORD Win32Style = WS_VISIBLE;
00135     Win32Style |= (WindowStyle == Resizable ? WS_OVERLAPPEDWINDOW : WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX);
00136 
00137     // In windowed mode, adjust width and height so that window will have the requested client area
00138     if (WindowStyle != Fullscreen)
00139     {
00140         RECT Rect = {0, 0, Width, Height};
00141         AdjustWindowRect(&Rect, Win32Style, false);
00142         Width  = Rect.right - Rect.left;
00143         Height = Rect.bottom - Rect.top;
00144     }
00145 
00146     // Create the window
00147     wchar_t WTitle[256];
00148     int NbChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, Title.c_str(), static_cast<int>(Title.size()), WTitle, sizeof(WTitle) / sizeof(*WTitle));
00149     WTitle[NbChars] = L'\0';
00150     myHandle = CreateWindow(ourClassName, WTitle, Win32Style, Left, Top, Width, Height, NULL, NULL, GetModuleHandle(NULL), this);
00151 
00152     // Create the rendering context
00153     if (myHandle)
00154         CreateContext(Mode, WindowStyle == Fullscreen, AntialiasingLevel);
00155 
00156     // Increment window count
00157     ourWindowCount++;
00158 
00159     // Setup joysticks
00160     SetupJoysticks();
00161 }
00162 
00163 
00167 WindowImplWin32::~WindowImplWin32()
00168 {
00169     if (!myCallback)
00170     {
00171         // Destroy the window
00172         if (myHandle)
00173             DestroyWindow(myHandle);
00174 
00175         // Decrement the window count
00176         ourWindowCount--;
00177 
00178         // Unregister window class if we were the last window
00179         if (ourWindowCount == 0)
00180             UnregisterClass(ourClassName, GetModuleHandle(NULL));
00181     }
00182     else
00183     {
00184         // The window is external : remove the hook on its message callback
00185         SetWindowLongPtr(myHandle, GWLP_WNDPROC, myCallback);
00186     }
00187 }
00188 
00189 
00193 void WindowImplWin32::Display()
00194 {
00195     if (myDeviceContext && myGLContext)
00196         SwapBuffers(myDeviceContext);
00197 }
00198 
00199 
00203 void WindowImplWin32::ProcessEvents()
00204 {
00205     // We update the window only if we own it
00206     if (!myCallback)
00207     {
00208         MSG Message;
00209         while (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE))
00210         {
00211             TranslateMessage(&Message);
00212             DispatchMessage(&Message);
00213         }
00214     }
00215 }
00216 
00217 
00221 void WindowImplWin32::MakeCurrent() const
00222 {
00223     if (myDeviceContext && myGLContext)
00224         wglMakeCurrent(myDeviceContext, myGLContext);
00225 }
00226 
00227 
00231 void WindowImplWin32::UseVerticalSync(bool Enabled)
00232 {
00233     PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = reinterpret_cast<PFNWGLSWAPINTERVALEXTPROC>(wglGetProcAddress("wglSwapIntervalEXT"));
00234     if (wglSwapIntervalEXT)
00235         wglSwapIntervalEXT(Enabled ? 1 : 0);
00236 }
00237 
00238 
00242 void WindowImplWin32::ShowMouseCursor(bool Show)
00243 {
00244     if (Show)
00245         myCursor = LoadCursor(NULL, IDC_ARROW);
00246     else
00247         myCursor = NULL;
00248 
00249     SetCursor(myCursor);
00250 }
00251 
00252 
00256 void WindowImplWin32::SetPosition(int Left, int Top)
00257 {
00258     SetWindowPos(myHandle, NULL, Left, Top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
00259 }
00260 
00261 
00265 void WindowImplWin32::RegisterWindowClass()
00266 {
00267     WNDCLASSW WindowClass;
00268     WindowClass.style         = 0;
00269     WindowClass.lpfnWndProc   = &WindowImplWin32::GlobalOnEvent;
00270     WindowClass.cbClsExtra    = 0;
00271     WindowClass.cbWndExtra    = 0;
00272     WindowClass.hInstance     = GetModuleHandle(NULL);
00273     WindowClass.hIcon         = NULL;
00274     WindowClass.hCursor       = 0;
00275     WindowClass.hbrBackground = 0;
00276     WindowClass.lpszMenuName  = NULL;
00277     WindowClass.lpszClassName = ourClassName;
00278 
00279     RegisterClass(&WindowClass);
00280 }
00281 
00282 
00286 void WindowImplWin32::CreateContext(VideoMode Mode, bool Fullscreen, int AntialiasingLevel)
00287 {
00288     // Fullscreen mode
00289     if (Fullscreen)
00290     {
00291         DEVMODE DevMode;
00292         DevMode.dmSize       = sizeof(DEVMODE);
00293         DevMode.dmPelsWidth  = Mode.Width;
00294         DevMode.dmPelsHeight = Mode.Height;
00295         DevMode.dmBitsPerPel = Mode.BitsPerPixel;
00296         DevMode.dmFields     = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
00297 
00298         // Apply fullscreen mode
00299         if (ChangeDisplaySettings(&DevMode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
00300         {
00301             std::cerr << "Failed to change display mode for fullscreen -- cannot create OpenGL context" << std::endl;
00302             return;
00303         }
00304 
00305         // Change window style (no border, no titlebar, ...)
00306         SetWindowLong(myHandle, GWL_STYLE,   WS_POPUP);
00307         SetWindowLong(myHandle, GWL_EXSTYLE, WS_EX_APPWINDOW);
00308 
00309         // And resize it so that it fits the entire screen
00310         SetWindowPos(myHandle, HWND_TOP, 0, 0, Mode.Width, Mode.Height, SWP_FRAMECHANGED);
00311         ShowWindow(myHandle, SW_SHOW);
00312 
00313         // Set "this" as the current fullscreen window
00314         ourFullscreenWindow = this;
00315     }
00316 
00317     // SetPixelFormat can fail (really ?) if window style doesn't contain these flags
00318     long Style = GetWindowLong(myHandle, GWL_STYLE);
00319     SetWindowLong(myHandle, GWL_STYLE, Style | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
00320 
00321     // Get the device context attached to the window
00322     myDeviceContext = GetDC(myHandle);
00323     if (myDeviceContext == NULL)
00324     {
00325         std::cerr << "Failed to get device context of window -- cannot create OpenGL context" << std::endl;
00326         return;
00327     }
00328 
00329     // Let's find a suitable pixel format -- first try with antialiasing
00330     int PixelFormat = 0;
00331     if (AntialiasingLevel > 0)
00332     {
00333         // Get the wglChoosePixelFormatARB function (it is an extension)
00334         PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = reinterpret_cast<PFNWGLCHOOSEPIXELFORMATARBPROC>(wglGetProcAddress("wglChoosePixelFormatARB"));
00335 
00336         // Define the basic attributes we want for our window
00337         int IntAttributes[] =
00338         {
00339             WGL_SAMPLES_ARB,        AntialiasingLevel,
00340             WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
00341             WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
00342             WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
00343             WGL_ACCELERATION_ARB,   WGL_FULL_ACCELERATION_ARB,
00344             WGL_COLOR_BITS_ARB,     Mode.BitsPerPixel,
00345             WGL_DOUBLE_BUFFER_ARB,  GL_TRUE,
00346             0,                      0
00347         };
00348 
00349         // Let's check how many formats are supporting our requirements
00350         int   Formats[64];
00351         UINT  NbFormats;
00352         float FloatAttributes[] = {0, 0};
00353         bool  IsValid = wglChoosePixelFormatARB(myDeviceContext, IntAttributes, FloatAttributes, sizeof(Formats) / sizeof(*Formats), Formats, &NbFormats) != 0;
00354         if (!IsValid || (NbFormats == 0))
00355         {
00356             if (AntialiasingLevel > 2)
00357             {
00358                 // No format matching our needs : reduce the multisampling level
00359                 std::cerr << "Failed to find a pixel format supporting "
00360                           << AntialiasingLevel << " antialiasing levels ; trying with 2 levels" << std::endl;
00361 
00362                 IntAttributes[1] = 2;
00363                 IsValid = wglChoosePixelFormatARB(myDeviceContext, IntAttributes, FloatAttributes, sizeof(Formats) / sizeof(*Formats), Formats, &NbFormats) != 0;
00364             }
00365 
00366             if (!IsValid || (NbFormats == 0))
00367             {
00368                 // Cannot find any pixel format supporting multisampling ; disabling antialiasing
00369                 std::cerr << "Failed to find a pixel format supporting antialiasing ; antialiasing will be disabled" << std::endl;
00370                 AntialiasingLevel = 0;
00371             }
00372         }
00373 
00374         // Get the best format among the returned ones
00375         if (IsValid && (NbFormats > 0))
00376         {
00377             PixelFormat = Formats[0];
00378             PIXELFORMATDESCRIPTOR BestAttribs;
00379             BestAttribs.nSize    = sizeof(PIXELFORMATDESCRIPTOR);
00380             BestAttribs.nVersion = 1;
00381             DescribePixelFormat(myDeviceContext, PixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &BestAttribs);
00382             for (UINT i = 1; i < NbFormats; ++i)
00383             {
00384                 // Get the current format's attributes
00385                 PIXELFORMATDESCRIPTOR Attribs;
00386                 Attribs.nSize    = sizeof(PIXELFORMATDESCRIPTOR);
00387                 Attribs.nVersion = 1;
00388                 DescribePixelFormat(myDeviceContext, Formats[i], sizeof(PIXELFORMATDESCRIPTOR), &Attribs);
00389 
00390                 // Compare them with the current best format
00391                 if ((BestAttribs.cStencilBits < Attribs.cStencilBits) || (BestAttribs.cDepthBits < Attribs.cDepthBits))
00392                 {
00393                     PixelFormat = Formats[i];
00394                     BestAttribs = Attribs;
00395                 }
00396             }
00397         }
00398     }
00399 
00400     // Find a pixel format with no antialiasing, if not needed or not supported
00401     if (AntialiasingLevel == 0)
00402     {
00403         // Setup a pixel format descriptor from the rendering settings
00404         PIXELFORMATDESCRIPTOR PixelDescriptor;
00405         ZeroMemory(&PixelDescriptor, sizeof(PIXELFORMATDESCRIPTOR));
00406         PixelDescriptor.nSize        = sizeof(PIXELFORMATDESCRIPTOR);
00407         PixelDescriptor.nVersion     = 1;
00408         PixelDescriptor.iLayerType   = PFD_MAIN_PLANE;
00409         PixelDescriptor.dwFlags      = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
00410         PixelDescriptor.iPixelType   = PFD_TYPE_RGBA;
00411         PixelDescriptor.cColorBits   = static_cast<BYTE>(Mode.BitsPerPixel);
00412         PixelDescriptor.cDepthBits   = 32; // It's only a hint
00413         PixelDescriptor.cStencilBits = 8;  // It's only a hint
00414 
00415         // Get the pixel format that best matches our requirements
00416         PixelFormat = ChoosePixelFormat(myDeviceContext, &PixelDescriptor);
00417         if (PixelFormat == 0)
00418         {
00419             std::cerr << "Failed to find a suitable pixel format for device context -- cannot create OpenGL context" << std::endl;
00420             return;
00421         }
00422     }
00423 
00424     // Extract the depth and stencil bits from the chosen format
00425     PIXELFORMATDESCRIPTOR ActualDescriptor;
00426     ActualDescriptor.nSize    = sizeof(PIXELFORMATDESCRIPTOR);
00427     ActualDescriptor.nVersion = 1;
00428     DescribePixelFormat(myDeviceContext, PixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &ActualDescriptor);
00429     myDepthBits   = ActualDescriptor.cDepthBits;
00430     myStencilBits = ActualDescriptor.cStencilBits;
00431 
00432     // Set the chosen pixel format
00433     if (!SetPixelFormat(myDeviceContext, PixelFormat, &ActualDescriptor))
00434     {
00435         std::cerr << "Failed to set pixel format for device context -- cannot create OpenGL context" << std::endl;
00436         return;
00437     }
00438 
00439     // Create the OpenGL context from the device context
00440     myGLContext = wglCreateContext(myDeviceContext);
00441     if (myGLContext == NULL)
00442     {
00443         std::cerr << "Failed to create an OpenGL context for this window" << std::endl;
00444         return;
00445     }
00446 
00447     // Share display lists with other contexts
00448     if (wglGetCurrentContext())
00449         wglShareLists(wglGetCurrentContext(), myGLContext);
00450 
00451     // Set our context as the current OpenGL context for rendering
00452     SetCurrent();
00453 
00454     // Enable multisampling
00455     if (AntialiasingLevel > 0)
00456         glEnable(GL_MULTISAMPLE_ARB);
00457 }
00458 
00459 
00463 void WindowImplWin32::Cleanup()
00464 {
00465     // Restore the previous video mode (in case we were running in fullscreen)
00466     if (ourFullscreenWindow == this)
00467     {
00468         ChangeDisplaySettings(NULL, 0);
00469         ourFullscreenWindow = NULL;
00470     }
00471 
00472     // Unhide the mouse cursor (in case it was hidden)
00473     ShowMouseCursor(true);
00474 
00475     // Destroy the OpenGL context
00476     if (myGLContext)
00477     {
00478         // If this is not the dummy window, we must set it as the valid rendering context to avoid a crash with next OpenGL command
00479         if (this != ourDummyWindow)
00480         {
00481             if (ourDummyWindow)
00482                 ourDummyWindow->SetCurrent();
00483         }
00484         else
00485         {
00486             ourDummyWindow = NULL;
00487             wglMakeCurrent(NULL, NULL);
00488         }
00489 
00490         // Destroy the context
00491         wglDeleteContext(myGLContext);
00492         myGLContext = NULL;
00493     }
00494 
00495     // Release the device context
00496     if (myDeviceContext)
00497     {
00498         ReleaseDC(myHandle, myDeviceContext);
00499         myDeviceContext = NULL;
00500     }
00501 }
00502 
00503 
00507 void WindowImplWin32::ProcessEvent(UINT Message, WPARAM WParam, LPARAM LParam)
00508 {
00509     // Don't process any message until window is created
00510     if (myHandle == NULL)
00511         return;
00512 
00513     switch (Message)
00514     {
00515         // Destroy event
00516         case WM_DESTROY :
00517         {
00518             // Here we must cleanup resources !
00519             Cleanup();
00520             break;
00521         }
00522 
00523         // Set cursor event
00524         case WM_SETCURSOR :
00525         {
00526             // The mouse has moved, if the cursor is in our window we must refresh the cursor
00527             if (LOWORD(LParam) == HTCLIENT)
00528                 SetCursor(myCursor);
00529 
00530             break;
00531         }
00532 
00533         // Close event
00534         case WM_CLOSE :
00535         {
00536             Event Evt;
00537             Evt.Type = Event::Close;
00538             SendEvent(Evt);
00539             break;
00540         }
00541 
00542         // Resize event
00543         case WM_SIZE :
00544         {
00545             // Update window size
00546             RECT Rect;
00547             GetClientRect(myHandle, &Rect);
00548             myWidth  = Rect.right - Rect.left;
00549             myHeight = Rect.bottom - Rect.top;
00550 
00551             Event Evt;
00552             Evt.Type        = Event::Resize;
00553             Evt.Size.Width  = myWidth;
00554             Evt.Size.Height = myHeight;
00555             SendEvent(Evt);
00556             break;
00557         }
00558 
00559         // Gain focus event
00560         case WM_SETFOCUS :
00561         {
00562             Event Evt;
00563             Evt.Type = Event::GainedFocus;
00564             SendEvent(Evt);
00565             break;
00566         }
00567 
00568         // Lost focus event
00569         case WM_KILLFOCUS :
00570         {
00571             Event Evt;
00572             Evt.Type = Event::LostFocus;
00573             SendEvent(Evt);
00574             break;
00575         }
00576 
00577         // Text event
00578         case WM_CHAR :
00579         {
00580             Event Evt;
00581             Evt.Type = Event::TextEntered;
00582             Evt.Text.Unicode = static_cast<Uint16>(WParam);
00583             SendEvent(Evt);
00584             break;
00585         }
00586 
00587         // Keydown event
00588         case WM_KEYDOWN :
00589         case WM_SYSKEYDOWN :
00590         {
00591             Event Evt;
00592             Evt.Type        = Event::KeyPressed;
00593             Evt.Key.Code    = VirtualKeyCodeToSF(WParam);
00594             Evt.Key.Alt     = GetAsyncKeyState(VK_RMENU)    || GetAsyncKeyState(VK_LMENU);
00595             Evt.Key.Control = GetAsyncKeyState(VK_RCONTROL) || GetAsyncKeyState(VK_LCONTROL);
00596             Evt.Key.Shift   = GetAsyncKeyState(VK_RSHIFT)   || GetAsyncKeyState(VK_LSHIFT);
00597             SendEvent(Evt);
00598             break;
00599         }
00600 
00601         // Keyup event
00602         case WM_KEYUP :
00603         case WM_SYSKEYUP :
00604         {
00605             Event Evt;
00606             Evt.Type        = Event::KeyReleased;
00607             Evt.Key.Code    = VirtualKeyCodeToSF(WParam);
00608             Evt.Key.Alt     = GetAsyncKeyState(VK_RMENU)    || GetAsyncKeyState(VK_LMENU);
00609             Evt.Key.Control = GetAsyncKeyState(VK_RCONTROL) || GetAsyncKeyState(VK_LCONTROL);
00610             Evt.Key.Shift   = GetAsyncKeyState(VK_RSHIFT)   || GetAsyncKeyState(VK_LSHIFT);
00611             SendEvent(Evt);
00612             break;
00613         }
00614 
00615         // Mouse wheel event
00616         case WM_MOUSEWHEEL :
00617         {
00618             Event Evt;
00619             Evt.Type = Event::MouseWheelMoved;
00620             Evt.MouseWheel.Delta = static_cast<Int16>(HIWORD(WParam)) / WHEEL_DELTA;
00621             SendEvent(Evt);
00622             break;
00623         }
00624 
00625         // Mouse left button down event
00626         case WM_LBUTTONDOWN :
00627         {
00628             Event Evt;
00629             Evt.Type          = Event::MouseButtonPressed;
00630             Evt.Mouse.Buttons = Mouse::Left;
00631             Evt.Mouse.X       = LOWORD(LParam);
00632             Evt.Mouse.Y       = HIWORD(LParam);
00633             SendEvent(Evt);
00634             break;
00635         }
00636 
00637         // Mouse left button up event
00638         case WM_LBUTTONUP :
00639         {
00640             Event Evt;
00641             Evt.Type          = Event::MouseButtonReleased;
00642             Evt.Mouse.Buttons = Mouse::Left;
00643             Evt.Mouse.X       = LOWORD(LParam);
00644             Evt.Mouse.Y       = HIWORD(LParam);
00645             SendEvent(Evt);
00646             break;
00647         }
00648 
00649         // Mouse right button down event
00650         case WM_RBUTTONDOWN :
00651         {
00652             Event Evt;
00653             Evt.Type          = Event::MouseButtonPressed;
00654             Evt.Mouse.Buttons = Mouse::Right;
00655             Evt.Mouse.X       = LOWORD(LParam);
00656             Evt.Mouse.Y       = HIWORD(LParam);
00657             SendEvent(Evt);
00658             break;
00659         }
00660 
00661         // Mouse right button up event
00662         case WM_RBUTTONUP :
00663         {
00664             Event Evt;
00665             Evt.Type          = Event::MouseButtonReleased;
00666             Evt.Mouse.Buttons = Mouse::Right;
00667             Evt.Mouse.X       = LOWORD(LParam);
00668             Evt.Mouse.Y       = HIWORD(LParam);
00669             SendEvent(Evt);
00670             break;
00671         }
00672 
00673         // Mouse wheel button down event
00674         case WM_MBUTTONDOWN :
00675         {
00676             Event Evt;
00677             Evt.Type          = Event::MouseButtonPressed;
00678             Evt.Mouse.Buttons = Mouse::Middle;
00679             Evt.Mouse.X       = LOWORD(LParam);
00680             Evt.Mouse.Y       = HIWORD(LParam);
00681             SendEvent(Evt);
00682             break;
00683         }
00684 
00685         // Mouse wheel button up event
00686         case WM_MBUTTONUP :
00687         {
00688             Event Evt;
00689             Evt.Type          = Event::MouseButtonReleased;
00690             Evt.Mouse.Buttons = Mouse::Middle;
00691             Evt.Mouse.X       = LOWORD(LParam);
00692             Evt.Mouse.Y       = HIWORD(LParam);
00693             SendEvent(Evt);
00694             break;
00695         }
00696 
00697         // Mouse move event
00698         case WM_MOUSEMOVE :
00699         {
00700             Event Evt;
00701             Evt.Type = Event::MouseMove;
00702             Evt.Mouse.Buttons = 0;
00703             if (GetAsyncKeyState(VK_LBUTTON)) Evt.Mouse.Buttons |= Mouse::Left;
00704             if (GetAsyncKeyState(VK_RBUTTON)) Evt.Mouse.Buttons |= Mouse::Right;
00705             if (GetAsyncKeyState(VK_MBUTTON)) Evt.Mouse.Buttons |= Mouse::Middle;
00706             Evt.Mouse.X = LOWORD(LParam);
00707             Evt.Mouse.Y = HIWORD(LParam);
00708             SendEvent(Evt);
00709             break;
00710         }
00711 
00712         // Joystick XY move event
00713         case MM_JOY1MOVE :
00714         case MM_JOY2MOVE :
00715         {
00716             Event Evt;
00717             Evt.Type                = Event::JoystickMove;
00718             Evt.Joystick.JoystickId = Message == MM_JOY1MOVE ? 0 : 1;
00719 
00720             JOYINFO JoyState;
00721             joyGetPos(Message == MM_JOY1MOVE ? JOYSTICKID1 : JOYSTICKID2, &JoyState);
00722 
00723             JoyCaps Caps = myJoystickCaps[Evt.Joystick.JoystickId];
00724             Evt.Joystick.X = (LOWORD(LParam) - Caps.CenterX) * 200 / Caps.RangeX;
00725             Evt.Joystick.Y = (HIWORD(LParam) - Caps.CenterY) * 200 / Caps.RangeY;
00726             Evt.Joystick.Z = (JoyState.wZpos - Caps.CenterZ) * 200 / Caps.RangeZ;
00727 
00728             SendEvent(Evt);
00729             break;
00730         }
00731 
00732         // Joystick Z move event
00733         case MM_JOY1ZMOVE :
00734         case MM_JOY2ZMOVE :
00735         {
00736             Event Evt;
00737             Evt.Type                = Event::JoystickMove;
00738             Evt.Joystick.JoystickId = Message == MM_JOY1ZMOVE ? 0 : 1;
00739 
00740             JOYINFO JoyState;
00741             joyGetPos(Message == MM_JOY1MOVE ? JOYSTICKID1 : JOYSTICKID2, &JoyState);
00742 
00743             JoyCaps Caps = myJoystickCaps[Evt.Joystick.JoystickId];
00744             Evt.Joystick.X = (JoyState.wXpos - Caps.CenterX) * 200 / Caps.RangeX;
00745             Evt.Joystick.Y = (JoyState.wYpos - Caps.CenterY) * 200 / Caps.RangeY;
00746             Evt.Joystick.Z = (LOWORD(LParam) - Caps.CenterZ) * 200 / Caps.RangeZ;
00747 
00748             SendEvent(Evt);
00749             break;
00750         }
00751 
00752         // Joystick button down events
00753         case MM_JOY1BUTTONDOWN :
00754         case MM_JOY2BUTTONDOWN :
00755         {
00756             Event Evt;
00757             Evt.Type                = Event::JoystickButtonPressed;
00758             Evt.Joystick.JoystickId = Message == MM_JOY1BUTTONDOWN ? 0 : 1;
00759 
00760             JOYINFO JoyState;
00761             joyGetPos(Message == MM_JOY1MOVE ? JOYSTICKID1 : JOYSTICKID2, &JoyState);
00762 
00763             JoyCaps Caps = myJoystickCaps[Evt.Joystick.JoystickId];
00764             Evt.Joystick.X = (LOWORD(LParam) - Caps.CenterX) * 200 / Caps.RangeX;
00765             Evt.Joystick.Y = (HIWORD(LParam) - Caps.CenterY) * 200 / Caps.RangeY;
00766             Evt.Joystick.Z = (JoyState.wZpos - Caps.CenterZ) * 200 / Caps.RangeZ;
00767 
00768             if      ((WParam & JOY_BUTTON1) && (WParam & JOY_BUTTON1CHG)) Evt.Joystick.Button = 0;
00769             else if ((WParam & JOY_BUTTON2) && (WParam & JOY_BUTTON2CHG)) Evt.Joystick.Button = 1;
00770             else if ((WParam & JOY_BUTTON3) && (WParam & JOY_BUTTON3CHG)) Evt.Joystick.Button = 2;
00771             else if ((WParam & JOY_BUTTON4) && (WParam & JOY_BUTTON4CHG)) Evt.Joystick.Button = 3;
00772 
00773             SendEvent(Evt);
00774             break;
00775         }
00776 
00777         // Joystick button up events
00778         case MM_JOY1BUTTONUP :
00779         case MM_JOY2BUTTONUP :
00780         {
00781             Event Evt;
00782             Evt.Type                = Event::JoystickButtonReleased;
00783             Evt.Joystick.JoystickId = Message == MM_JOY1BUTTONUP ? 0 : 1;
00784 
00785             JOYINFO JoyState;
00786             joyGetPos(Message == MM_JOY1MOVE ? JOYSTICKID1 : JOYSTICKID2, &JoyState);
00787 
00788             JoyCaps Caps = myJoystickCaps[Evt.Joystick.JoystickId];
00789             Evt.Joystick.X = (LOWORD(LParam) - Caps.CenterX) * 200 / Caps.RangeX;
00790             Evt.Joystick.Y = (HIWORD(LParam) - Caps.CenterY) * 200 / Caps.RangeY;
00791             Evt.Joystick.Z = (JoyState.wZpos - Caps.CenterZ) * 200 / Caps.RangeZ;
00792 
00793             if      (!(WParam & JOY_BUTTON1) && (WParam & JOY_BUTTON1CHG)) Evt.Joystick.Button = 0;
00794             else if (!(WParam & JOY_BUTTON2) && (WParam & JOY_BUTTON2CHG)) Evt.Joystick.Button = 1;
00795             else if (!(WParam & JOY_BUTTON3) && (WParam & JOY_BUTTON3CHG)) Evt.Joystick.Button = 2;
00796             else if (!(WParam & JOY_BUTTON4) && (WParam & JOY_BUTTON4CHG)) Evt.Joystick.Button = 3;
00797 
00798             SendEvent(Evt);
00799             break;
00800         }
00801     }
00802 }
00803 
00804 
00808 void WindowImplWin32::SetupJoysticks()
00809 {
00810     // Get the number of connected joysticks
00811     MMRESULT Error;
00812     JOYINFOEX JoyInfo;
00813     unsigned int Count = 0;
00814     while ((Count < 2) && (Error = joyGetPosEx(JOYSTICKID1 + Count, &JoyInfo)) != JOYERR_PARMS)
00815     {
00816         // Check if the current joystick is connected
00817         if (Error == JOYERR_NOERROR)
00818         {
00819             // Start capturing joystick
00820             joySetCapture(myHandle, JOYSTICKID1 + Count, 10, TRUE);
00821 
00822             // Store its caps
00823             JOYCAPS WinCaps;
00824             joyGetDevCaps(JOYSTICKID1 + Count, &WinCaps, sizeof(WinCaps));
00825             myJoystickCaps[Count].CenterX = (WinCaps.wXmax + WinCaps.wXmin) / 2;
00826             myJoystickCaps[Count].CenterY = (WinCaps.wYmax + WinCaps.wYmin) / 2;
00827             myJoystickCaps[Count].CenterZ = (WinCaps.wZmax + WinCaps.wZmin) / 2;
00828             myJoystickCaps[Count].RangeX  = WinCaps.wXmax - WinCaps.wXmin;
00829             myJoystickCaps[Count].RangeY  = WinCaps.wYmax - WinCaps.wYmin;
00830             myJoystickCaps[Count].RangeZ  = WinCaps.wZmax - WinCaps.wZmin;
00831         }
00832 
00833         // Go to the next joystick
00834         ++Count;
00835     }
00836 }
00837 
00838 
00842 Key::Code WindowImplWin32::VirtualKeyCodeToSF(WPARAM VirtualKey)
00843 {
00844     switch (VirtualKey)
00845     {
00846         case VK_ESCAPE :   return Key::Escape;
00847         case VK_SPACE :    return Key::Space;
00848         case VK_RETURN :   return Key::Return;
00849         case VK_BACK :     return Key::Back;
00850         case VK_TAB :      return Key::Tab;
00851         case VK_PRIOR :    return Key::PageUp;
00852         case VK_NEXT :     return Key::PageDown;
00853         case VK_END :      return Key::End;
00854         case VK_HOME :     return Key::Home;
00855         case VK_INSERT :   return Key::Insert;
00856         case VK_DELETE :   return Key::Delete;
00857         case VK_ADD :      return Key::Add;
00858         case VK_SUBTRACT : return Key::Subtract;
00859         case VK_MULTIPLY : return Key::Multiply;
00860         case VK_DIVIDE :   return Key::Divide;
00861         case VK_PAUSE :    return Key::Pause;
00862         case VK_F1 :       return Key::F1;
00863         case VK_F2 :       return Key::F2;
00864         case VK_F3 :       return Key::F3;
00865         case VK_F4 :       return Key::F4;
00866         case VK_F5 :       return Key::F5;
00867         case VK_F6 :       return Key::F6;
00868         case VK_F7 :       return Key::F7;
00869         case VK_F8 :       return Key::F8;
00870         case VK_F9 :       return Key::F9;
00871         case VK_F10 :      return Key::F10;
00872         case VK_F11 :      return Key::F11;
00873         case VK_F12 :      return Key::F12;
00874         case VK_F13 :      return Key::F13;
00875         case VK_F14 :      return Key::F14;
00876         case VK_F15 :      return Key::F15;
00877         case VK_LEFT :     return Key::Left;
00878         case VK_RIGHT :    return Key::Right;
00879         case VK_UP :       return Key::Up;
00880         case VK_DOWN :     return Key::Down;
00881         case VK_NUMPAD0 :  return Key::Numpad0;
00882         case VK_NUMPAD1 :  return Key::Numpad1;
00883         case VK_NUMPAD2 :  return Key::Numpad2;
00884         case VK_NUMPAD3 :  return Key::Numpad3;
00885         case VK_NUMPAD4 :  return Key::Numpad4;
00886         case VK_NUMPAD5 :  return Key::Numpad5;
00887         case VK_NUMPAD6 :  return Key::Numpad6;
00888         case VK_NUMPAD7 :  return Key::Numpad7;
00889         case VK_NUMPAD8 :  return Key::Numpad8;
00890         case VK_NUMPAD9 :  return Key::Numpad9;
00891         case 'A' :         return Key::A;
00892         case 'Z' :         return Key::Z;
00893         case 'E' :         return Key::E;
00894         case 'R' :         return Key::R;
00895         case 'T' :         return Key::T;
00896         case 'Y' :         return Key::Y;
00897         case 'U' :         return Key::U;
00898         case 'I' :         return Key::I;
00899         case 'O' :         return Key::O;
00900         case 'P' :         return Key::P;
00901         case 'Q' :         return Key::Q;
00902         case 'S' :         return Key::S;
00903         case 'D' :         return Key::D;
00904         case 'F' :         return Key::F;
00905         case 'G' :         return Key::G;
00906         case 'H' :         return Key::H;
00907         case 'J' :         return Key::J;
00908         case 'K' :         return Key::K;
00909         case 'L' :         return Key::L;
00910         case 'M' :         return Key::M;
00911         case 'W' :         return Key::W;
00912         case 'X' :         return Key::X;
00913         case 'C' :         return Key::C;
00914         case 'V' :         return Key::V;
00915         case 'B' :         return Key::B;
00916         case 'N' :         return Key::N;
00917         case '0' :         return Key::Num0;
00918         case '1' :         return Key::Num1;
00919         case '2' :         return Key::Num2;
00920         case '3' :         return Key::Num3;
00921         case '4' :         return Key::Num4;
00922         case '5' :         return Key::Num5;
00923         case '6' :         return Key::Num6;
00924         case '7' :         return Key::Num7;
00925         case '8' :         return Key::Num8;
00926         case '9' :         return Key::Num9;
00927     }
00928 
00929     return Key::Code(0);
00930 }
00931 
00932 
00936 LRESULT CALLBACK WindowImplWin32::GlobalOnEvent(HWND Handle, UINT Message, WPARAM WParam, LPARAM LParam)
00937 {
00938     // Associate handle and Window instance when the creation message is received
00939     if (Message == WM_CREATE)
00940     {
00941         // Get sfWindowImplWin32 instance (it was passed as the last argument of CreateWindow)
00942         long This = reinterpret_cast<long>(reinterpret_cast<CREATESTRUCT*>(LParam)->lpCreateParams);
00943 
00944         // Set as the "user data" parameter of the window
00945         SetWindowLongPtr(Handle, GWLP_USERDATA, This);
00946     }
00947 
00948     // Get the WindowImpl instance corresponding to the window handle
00949     WindowImplWin32* Window = reinterpret_cast<WindowImplWin32*>(GetWindowLongPtr(Handle, GWLP_USERDATA));
00950 
00951     // Forward the event to the appropriate function
00952     if (Window)
00953     {
00954         Window->ProcessEvent(Message, WParam, LParam);
00955 
00956         if (Window->myCallback)
00957             return CallWindowProc(reinterpret_cast<WNDPROC>(Window->myCallback), Handle, Message, WParam, LParam);
00958     }
00959 
00960     return DefWindowProc(Handle, Message, WParam, LParam);
00961 }
00962 
00963 } // namespace priv
00964 
00965 } // namespace sf