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