WindowImplWin32.cpp
1 //
3 // SFML - Simple and Fast Multimedia Library
4 // Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
5 //
6 // This software is provided 'as-is', without any express or implied warranty.
7 // In no event will the authors be held liable for any damages arising from the use of this software.
8 //
9 // Permission is granted to anyone to use this software for any purpose,
10 // including commercial applications, and to alter it and redistribute it freely,
11 // subject to the following restrictions:
12 //
13 // 1. The origin of this software must not be misrepresented;
14 // you must not claim that you wrote the original software.
15 // If you use this software in a product, an acknowledgment
16 // in the product documentation would be appreciated but is not required.
17 //
18 // 2. Altered source versions must be plainly marked as such,
19 // and must not be misrepresented as being the original software.
20 //
21 // 3. This notice may not be removed or altered from any source distribution.
22 //
24 
26 // Headers
28 #define _WIN32_WINDOWS 0x0501
29 #define _WIN32_WINNT 0x0501
30 #include <SFML/Window/Win32/WindowImplWin32.hpp>
31 #include <SFML/Window/WindowSettings.hpp>
32 #include <SFML/Window/WindowStyle.hpp>
33 #include <GL/gl.h>
34 #include <SFML/Window/glext/wglext.h>
35 #include <SFML/Window/glext/glext.h>
36 #include <iostream>
37 #include <vector>
38 
39 // MinGW lacks the definition of some Win32 constants
40 #ifndef XBUTTON1
41  #define XBUTTON1 0x0001
42 #endif
43 #ifndef XBUTTON2
44  #define XBUTTON2 0x0002
45 #endif
46 #ifndef MAPVK_VK_TO_VSC
47  #define MAPVK_VK_TO_VSC (0)
48 #endif
49 
50 
51 namespace sf
52 {
53 namespace priv
54 {
56 // Static member data
58 unsigned int WindowImplWin32::ourWindowCount = 0;
59 const char* WindowImplWin32::ourClassNameA = "SFML_Window";
60 const wchar_t* WindowImplWin32::ourClassNameW = L"SFML_Window";
61 WindowImplWin32* WindowImplWin32::ourFullscreenWindow = NULL;
62 
63 
68 WindowImplWin32::WindowImplWin32() :
69 myHandle (NULL),
70 myCallback (0),
71 myCursor (NULL),
72 myIcon (NULL),
73 myKeyRepeatEnabled(true),
74 myIsCursorIn (false)
75 {
76  // Register the window class at first call
77  if (ourWindowCount == 0)
78  RegisterWindowClass();
79 
80  // Use small dimensions
81  myWidth = 1;
82  myHeight = 1;
83 
84  // Create a dummy window (disabled and hidden)
85  if (HasUnicodeSupport())
86  {
87  myHandle = CreateWindowW(ourClassNameW, L"", WS_POPUP | WS_DISABLED, 0, 0, myWidth, myHeight, NULL, NULL, GetModuleHandle(NULL), NULL);
88  }
89  else
90  {
91  myHandle = CreateWindowA(ourClassNameA, "", WS_POPUP | WS_DISABLED, 0, 0, myWidth, myHeight, NULL, NULL, GetModuleHandle(NULL), NULL);
92  }
93  ShowWindow(myHandle, SW_HIDE);
94 
95  // Create the rendering context
96  if (myHandle)
97  {
98  WindowSettings Params(0, 0, 0);
99  CreateContext(VideoMode(myWidth, myHeight, 32), Params);
100 
101  // Don't activate by default
102  SetActive(false);
103  }
104 }
105 
106 
110 WindowImplWin32::WindowImplWin32(WindowHandle Handle, WindowSettings& Params) :
111 myHandle (NULL),
112 myCallback (0),
113 myCursor (NULL),
114 myIcon (NULL),
115 myKeyRepeatEnabled(true),
116 myIsCursorIn (false)
117 {
118  // Save window handle
119  myHandle = static_cast<HWND>(Handle);
120 
121  if (myHandle)
122  {
123  // Get window client size
124  RECT Rect;
125  GetClientRect(myHandle, &Rect);
126  myWidth = Rect.right - Rect.left;
127  myHeight = Rect.bottom - Rect.top;
128 
129  // Create the rendering context
130  VideoMode Mode(myWidth, myHeight, VideoMode::GetDesktopMode().BitsPerPixel);
131  CreateContext(Mode, Params);
132 
133  // We change the event procedure of the control (it is important to save the old one)
134  SetWindowLongPtr(myHandle, GWLP_USERDATA, reinterpret_cast<long>(this));
135  myCallback = SetWindowLongPtr(myHandle, GWLP_WNDPROC, reinterpret_cast<long>(&WindowImplWin32::GlobalOnEvent));
136  }
137 }
138 
139 
143 WindowImplWin32::WindowImplWin32(VideoMode Mode, const std::string& Title, unsigned long WindowStyle, WindowSettings& Params) :
144 myHandle (NULL),
145 myCallback (0),
146 myCursor (NULL),
147 myIcon (NULL),
148 myKeyRepeatEnabled(true),
149 myIsCursorIn (false)
150 {
151  // Register the window class at first call
152  if (ourWindowCount == 0)
153  RegisterWindowClass();
154 
155  // Compute position and size
156  HDC ScreenDC = GetDC(NULL);
157  int Left = (GetDeviceCaps(ScreenDC, HORZRES) - Mode.Width) / 2;
158  int Top = (GetDeviceCaps(ScreenDC, VERTRES) - Mode.Height) / 2;
159  int Width = myWidth = Mode.Width;
160  int Height = myHeight = Mode.Height;
161  ReleaseDC(NULL, ScreenDC);
162 
163  // Choose the window style according to the Style parameter
164  DWORD Win32Style = WS_VISIBLE;
165  if (WindowStyle == Style::None)
166  {
167  Win32Style |= WS_POPUP;
168  }
169  else
170  {
171  if (WindowStyle & Style::Titlebar) Win32Style |= WS_CAPTION | WS_MINIMIZEBOX;
172  if (WindowStyle & Style::Resize) Win32Style |= WS_THICKFRAME | WS_MAXIMIZEBOX;
173  if (WindowStyle & Style::Close) Win32Style |= WS_SYSMENU;
174  }
175 
176  // In windowed mode, adjust width and height so that window will have the requested client area
177  bool Fullscreen = (WindowStyle & Style::Fullscreen) != 0;
178  if (!Fullscreen)
179  {
180  RECT Rect = {0, 0, Width, Height};
181  AdjustWindowRect(&Rect, Win32Style, false);
182  Width = Rect.right - Rect.left;
183  Height = Rect.bottom - Rect.top;
184  }
185 
186  // Create the window
187  if (HasUnicodeSupport())
188  {
189  wchar_t WTitle[256];
190  int NbChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, Title.c_str(), static_cast<int>(Title.size()), WTitle, sizeof(WTitle) / sizeof(*WTitle));
191  WTitle[NbChars] = L'\0';
192  myHandle = CreateWindowW(ourClassNameW, WTitle, Win32Style, Left, Top, Width, Height, NULL, NULL, GetModuleHandle(NULL), this);
193  }
194  else
195  {
196  myHandle = CreateWindowA(ourClassNameA, Title.c_str(), Win32Style, Left, Top, Width, Height, NULL, NULL, GetModuleHandle(NULL), this);
197  }
198 
199  // Switch to fullscreen if requested
200  if (Fullscreen)
201  SwitchToFullscreen(Mode);
202 
203  // Create the rendering context
204  if (myHandle)
205  CreateContext(Mode, Params);
206 
207  // Increment window count
208  ourWindowCount++;
209 
210  // Get the actual size of the window, which can be smaller even after the call to AdjustWindowRect
211  // This happens when the window is bigger than the desktop
212  RECT ActualRect;
213  GetClientRect(myHandle, &ActualRect);
214  myWidth = ActualRect.right - ActualRect.left;
215  myHeight = ActualRect.bottom - ActualRect.top;
216 }
217 
218 
222 WindowImplWin32::~WindowImplWin32()
223 {
224  // Destroy the custom icon, if any
225  if (myIcon)
226  DestroyIcon(myIcon);
227 
228  if (!myCallback)
229  {
230  // Destroy the window
231  if (myHandle)
232  DestroyWindow(myHandle);
233 
234  // Decrement the window count
235  ourWindowCount--;
236 
237  // Unregister window class if we were the last window
238  if (ourWindowCount == 0)
239  {
240  if (HasUnicodeSupport())
241  {
242  UnregisterClassW(ourClassNameW, GetModuleHandle(NULL));
243  }
244  else
245  {
246  UnregisterClassA(ourClassNameA, GetModuleHandle(NULL));
247  }
248  }
249  }
250  else
251  {
252  // The window is external : remove the hook on its message callback
253  SetWindowLongPtr(myHandle, GWLP_WNDPROC, myCallback);
254  }
255 }
256 
257 
261 bool WindowImplWin32::IsContextActive()
262 {
263  return wglGetCurrentContext() != NULL;
264 }
265 
266 
270 void WindowImplWin32::ProcessEvents()
271 {
272  // We update the window only if we own it
273  if (!myCallback)
274  {
275  MSG Message;
276  while (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE))
277  {
278  TranslateMessage(&Message);
279  DispatchMessage(&Message);
280  }
281  }
282 }
283 
284 
288 void WindowImplWin32::Display()
289 {
290  if (myDeviceContext && myGLContext)
291  SwapBuffers(myDeviceContext);
292 }
293 
294 
298 void WindowImplWin32::SetActive(bool Active) const
299 {
300  if (Active)
301  {
302  if (myDeviceContext && myGLContext && (wglGetCurrentContext() != myGLContext))
303  wglMakeCurrent(myDeviceContext, myGLContext);
304  }
305  else
306  {
307  if (wglGetCurrentContext() == myGLContext)
308  wglMakeCurrent(NULL, NULL);
309  }
310 }
311 
312 
316 void WindowImplWin32::UseVerticalSync(bool Enabled)
317 {
318  PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = reinterpret_cast<PFNWGLSWAPINTERVALEXTPROC>(wglGetProcAddress("wglSwapIntervalEXT"));
319  if (wglSwapIntervalEXT)
320  wglSwapIntervalEXT(Enabled ? 1 : 0);
321 }
322 
323 
327 void WindowImplWin32::ShowMouseCursor(bool Show)
328 {
329  if (Show)
330  myCursor = LoadCursor(NULL, IDC_ARROW);
331  else
332  myCursor = NULL;
333 
334  SetCursor(myCursor);
335 }
336 
337 
341 void WindowImplWin32::SetCursorPosition(unsigned int Left, unsigned int Top)
342 {
343  POINT Pos = {Left, Top};
344  ClientToScreen(myHandle, &Pos);
345  SetCursorPos(Pos.x, Pos.y);
346 }
347 
348 
352 void WindowImplWin32::SetPosition(int Left, int Top)
353 {
354  SetWindowPos(myHandle, NULL, Left, Top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
355 }
356 
357 
361 void WindowImplWin32::SetSize(unsigned int Width, unsigned int Height)
362 {
363  // SetWindowPos wants the total size of the window (including title bar and borders),
364  // so we have to compute it
365  RECT Rect = {0, 0, Width, Height};
366  AdjustWindowRect(&Rect, GetWindowLong(myHandle, GWL_STYLE), false);
367  Width = Rect.right - Rect.left;
368  Height = Rect.bottom - Rect.top;
369 
370  SetWindowPos(myHandle, NULL, 0, 0, Width, Height, SWP_NOMOVE | SWP_NOZORDER);
371 }
372 
373 
377 void WindowImplWin32::Show(bool State)
378 {
379  ShowWindow(myHandle, State ? SW_SHOW : SW_HIDE);
380 }
381 
382 
386 void WindowImplWin32::EnableKeyRepeat(bool Enabled)
387 {
388  myKeyRepeatEnabled = Enabled;
389 }
390 
391 
395 void WindowImplWin32::SetIcon(unsigned int Width, unsigned int Height, const Uint8* Pixels)
396 {
397  // First destroy the previous one
398  if (myIcon)
399  DestroyIcon(myIcon);
400 
401  // Windows wants BGRA pixels : swap red and blue channels
402  std::vector<Uint8> IconPixels(Width * Height * 4);
403  for (std::size_t i = 0; i < IconPixels.size() / 4; ++i)
404  {
405  IconPixels[i * 4 + 0] = Pixels[i * 4 + 2];
406  IconPixels[i * 4 + 1] = Pixels[i * 4 + 1];
407  IconPixels[i * 4 + 2] = Pixels[i * 4 + 0];
408  IconPixels[i * 4 + 3] = Pixels[i * 4 + 3];
409  }
410 
411  // Create the icon from the pixels array
412  myIcon = CreateIcon(GetModuleHandle(NULL), Width, Height, 1, 32, NULL, &IconPixels[0]);
413 
414  // Set it as both big and small icon of the window
415  if (myIcon)
416  {
417  SendMessage(myHandle, WM_SETICON, ICON_BIG, (LPARAM)myIcon);
418  SendMessage(myHandle, WM_SETICON, ICON_SMALL, (LPARAM)myIcon);
419  }
420  else
421  {
422  std::cerr << "Failed to set the window's icon" << std::endl;
423  }
424 }
425 
426 
430 void WindowImplWin32::RegisterWindowClass()
431 {
432  if (HasUnicodeSupport())
433  {
434  WNDCLASSW WindowClass;
435  WindowClass.style = 0;
436  WindowClass.lpfnWndProc = &WindowImplWin32::GlobalOnEvent;
437  WindowClass.cbClsExtra = 0;
438  WindowClass.cbWndExtra = 0;
439  WindowClass.hInstance = GetModuleHandle(NULL);
440  WindowClass.hIcon = NULL;
441  WindowClass.hCursor = 0;
442  WindowClass.hbrBackground = 0;
443  WindowClass.lpszMenuName = NULL;
444  WindowClass.lpszClassName = ourClassNameW;
445  RegisterClassW(&WindowClass);
446  }
447  else
448  {
449  WNDCLASSA WindowClass;
450  WindowClass.style = 0;
451  WindowClass.lpfnWndProc = &WindowImplWin32::GlobalOnEvent;
452  WindowClass.cbClsExtra = 0;
453  WindowClass.cbWndExtra = 0;
454  WindowClass.hInstance = GetModuleHandle(NULL);
455  WindowClass.hIcon = NULL;
456  WindowClass.hCursor = 0;
457  WindowClass.hbrBackground = 0;
458  WindowClass.lpszMenuName = NULL;
459  WindowClass.lpszClassName = ourClassNameA;
460  RegisterClassA(&WindowClass);
461  }
462 }
463 
464 
468 void WindowImplWin32::SwitchToFullscreen(const VideoMode& Mode)
469 {
470  DEVMODE DevMode;
471  DevMode.dmSize = sizeof(DEVMODE);
472  DevMode.dmPelsWidth = Mode.Width;
473  DevMode.dmPelsHeight = Mode.Height;
474  DevMode.dmBitsPerPel = Mode.BitsPerPixel;
475  DevMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
476 
477  // Apply fullscreen mode
478  if (ChangeDisplaySettings(&DevMode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
479  {
480  std::cerr << "Failed to change display mode for fullscreen" << std::endl;
481  return;
482  }
483 
484  // Make the window flags compatible with fullscreen mode
485  SetWindowLong(myHandle, GWL_STYLE, WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
486  SetWindowLong(myHandle, GWL_EXSTYLE, WS_EX_APPWINDOW);
487 
488  // Resize the window so that it fits the entire screen
489  SetWindowPos(myHandle, HWND_TOP, 0, 0, Mode.Width, Mode.Height, SWP_FRAMECHANGED);
490  ShowWindow(myHandle, SW_SHOW);
491 
492  // Set "this" as the current fullscreen window
493  ourFullscreenWindow = this;
494 }
495 
496 
500 void WindowImplWin32::CreateContext(const VideoMode& Mode, WindowSettings& Params)
501 {
502  // Get the device context attached to the window
503  myDeviceContext = GetDC(myHandle);
504  if (myDeviceContext == NULL)
505  {
506  std::cerr << "Failed to get device context of window -- cannot create OpenGL context" << std::endl;
507  return;
508  }
509 
510  // Let's find a suitable pixel format -- first try with antialiasing
511  int BestFormat = 0;
512  if (Params.AntialiasingLevel > 0)
513  {
514  // Get the wglChoosePixelFormatARB function (it is an extension)
515  PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = reinterpret_cast<PFNWGLCHOOSEPIXELFORMATARBPROC>(wglGetProcAddress("wglChoosePixelFormatARB"));
516  if (wglChoosePixelFormatARB)
517  {
518  // Define the basic attributes we want for our window
519  int IntAttributes[] =
520  {
521  WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
522  WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
523  WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
524  WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
525  WGL_SAMPLE_BUFFERS_ARB, (Params.AntialiasingLevel ? GL_TRUE : GL_FALSE),
526  WGL_SAMPLES_ARB, Params.AntialiasingLevel,
527  0, 0
528  };
529 
530  // Let's check how many formats are supporting our requirements
531  int Formats[128];
532  UINT NbFormats;
533  float FloatAttributes[] = {0, 0};
534  bool IsValid = wglChoosePixelFormatARB(myDeviceContext, IntAttributes, FloatAttributes, sizeof(Formats) / sizeof(*Formats), Formats, &NbFormats) != 0;
535  if (!IsValid || (NbFormats == 0))
536  {
537  if (Params.AntialiasingLevel > 2)
538  {
539  // No format matching our needs : reduce the multisampling level
540  std::cerr << "Failed to find a pixel format supporting "
541  << Params.AntialiasingLevel << " antialiasing levels ; trying with 2 levels" << std::endl;
542 
543  Params.AntialiasingLevel = IntAttributes[11] = 2;
544  IsValid = wglChoosePixelFormatARB(myDeviceContext, IntAttributes, FloatAttributes, sizeof(Formats) / sizeof(*Formats), Formats, &NbFormats) != 0;
545  }
546 
547  if (!IsValid || (NbFormats == 0))
548  {
549  // Cannot find any pixel format supporting multisampling ; disabling antialiasing
550  std::cerr << "Failed to find a pixel format supporting antialiasing ; antialiasing will be disabled" << std::endl;
551  Params.AntialiasingLevel = 0;
552  }
553  }
554 
555  // Get the best format among the returned ones
556  if (IsValid && (NbFormats > 0))
557  {
558  int BestScore = 0xFFFF;
559  for (UINT i = 0; i < NbFormats; ++i)
560  {
561  // Get the current format's attributes
562  PIXELFORMATDESCRIPTOR Attribs;
563  Attribs.nSize = sizeof(PIXELFORMATDESCRIPTOR);
564  Attribs.nVersion = 1;
565  DescribePixelFormat(myDeviceContext, Formats[i], sizeof(PIXELFORMATDESCRIPTOR), &Attribs);
566 
567  // Evaluate the current configuration
568  int Color = Attribs.cRedBits + Attribs.cGreenBits + Attribs.cBlueBits + Attribs.cAlphaBits;
569  int Score = EvaluateConfig(Mode, Params, Color, Attribs.cDepthBits, Attribs.cStencilBits, Params.AntialiasingLevel);
570 
571  // Keep it if it's better than the current best
572  if (Score < BestScore)
573  {
574  BestScore = Score;
575  BestFormat = Formats[i];
576  }
577  }
578  }
579  }
580  else
581  {
582  // wglChoosePixelFormatARB not supported ; disabling antialiasing
583  std::cerr << "Antialiasing is not supported ; it will be disabled" << std::endl;
584  Params.AntialiasingLevel = 0;
585  }
586  }
587 
588  // Find a pixel format with no antialiasing, if not needed or not supported
589  if (BestFormat == 0)
590  {
591  // Setup a pixel format descriptor from the rendering settings
592  PIXELFORMATDESCRIPTOR PixelDescriptor;
593  ZeroMemory(&PixelDescriptor, sizeof(PIXELFORMATDESCRIPTOR));
594  PixelDescriptor.nSize = sizeof(PIXELFORMATDESCRIPTOR);
595  PixelDescriptor.nVersion = 1;
596  PixelDescriptor.iLayerType = PFD_MAIN_PLANE;
597  PixelDescriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
598  PixelDescriptor.iPixelType = PFD_TYPE_RGBA;
599  PixelDescriptor.cColorBits = static_cast<BYTE>(Mode.BitsPerPixel);
600  PixelDescriptor.cDepthBits = static_cast<BYTE>(Params.DepthBits);
601  PixelDescriptor.cStencilBits = static_cast<BYTE>(Params.StencilBits);
602  PixelDescriptor.cAlphaBits = Mode.BitsPerPixel == 32 ? 8 : 0;
603 
604  // Get the pixel format that best matches our requirements
605  BestFormat = ChoosePixelFormat(myDeviceContext, &PixelDescriptor);
606  if (BestFormat == 0)
607  {
608  std::cerr << "Failed to find a suitable pixel format for device context -- cannot create OpenGL context" << std::endl;
609  return;
610  }
611  }
612 
613  // Extract the depth and stencil bits from the chosen format
614  PIXELFORMATDESCRIPTOR ActualFormat;
615  ActualFormat.nSize = sizeof(PIXELFORMATDESCRIPTOR);
616  ActualFormat.nVersion = 1;
617  DescribePixelFormat(myDeviceContext, BestFormat, sizeof(PIXELFORMATDESCRIPTOR), &ActualFormat);
618  Params.DepthBits = ActualFormat.cDepthBits;
619  Params.StencilBits = ActualFormat.cStencilBits;
620 
621  // Set the chosen pixel format
622  if (!SetPixelFormat(myDeviceContext, BestFormat, &ActualFormat))
623  {
624  std::cerr << "Failed to set pixel format for device context -- cannot create OpenGL context" << std::endl;
625  return;
626  }
627 
628  // Create the OpenGL context from the device context
629  myGLContext = wglCreateContext(myDeviceContext);
630  if (myGLContext == NULL)
631  {
632  std::cerr << "Failed to create an OpenGL context for this window" << std::endl;
633  return;
634  }
635 
636  // Share display lists with other contexts
637  HGLRC CurrentContext = wglGetCurrentContext();
638  if (CurrentContext)
639  wglShareLists(CurrentContext, myGLContext);
640 
641  // Activate the context
642  SetActive(true);
643 
644  // Enable multisampling
645  if (Params.AntialiasingLevel > 0)
646  glEnable(GL_MULTISAMPLE_ARB);
647 }
648 
649 
653 void WindowImplWin32::Cleanup()
654 {
655  // Restore the previous video mode (in case we were running in fullscreen)
656  if (ourFullscreenWindow == this)
657  {
658  ChangeDisplaySettings(NULL, 0);
659  ourFullscreenWindow = NULL;
660  }
661 
662  // Unhide the mouse cursor (in case it was hidden)
663  ShowMouseCursor(true);
664 
665  // Destroy the OpenGL context
666  if (myGLContext)
667  {
668  // Unbind the context before destroying it
669  SetActive(false);
670 
671  wglDeleteContext(myGLContext);
672  myGLContext = NULL;
673  }
674  if (myDeviceContext)
675  {
676  ReleaseDC(myHandle, myDeviceContext);
677  myDeviceContext = NULL;
678  }
679 }
680 
681 
685 void WindowImplWin32::ProcessEvent(UINT Message, WPARAM WParam, LPARAM LParam)
686 {
687  // Don't process any message until window is created
688  if (myHandle == NULL)
689  return;
690 
691  switch (Message)
692  {
693  // Destroy event
694  case WM_DESTROY :
695  {
696  // Here we must cleanup resources !
697  Cleanup();
698  break;
699  }
700 
701  // Set cursor event
702  case WM_SETCURSOR :
703  {
704  // The mouse has moved, if the cursor is in our window we must refresh the cursor
705  if (LOWORD(LParam) == HTCLIENT)
706  SetCursor(myCursor);
707 
708  break;
709  }
710 
711  // Close event
712  case WM_CLOSE :
713  {
714  Event Evt;
715  Evt.Type = Event::Closed;
716  SendEvent(Evt);
717  break;
718  }
719 
720  // Resize event
721  case WM_SIZE :
722  {
723  // Update window size
724  RECT Rect;
725  GetClientRect(myHandle, &Rect);
726  myWidth = Rect.right - Rect.left;
727  myHeight = Rect.bottom - Rect.top;
728 
729  Event Evt;
730  Evt.Type = Event::Resized;
731  Evt.Size.Width = myWidth;
732  Evt.Size.Height = myHeight;
733  SendEvent(Evt);
734  break;
735  }
736 
737  // Gain focus event
738  case WM_SETFOCUS :
739  {
740  Event Evt;
741  Evt.Type = Event::GainedFocus;
742  SendEvent(Evt);
743  break;
744  }
745 
746  // Lost focus event
747  case WM_KILLFOCUS :
748  {
749  Event Evt;
750  Evt.Type = Event::LostFocus;
751  SendEvent(Evt);
752  break;
753  }
754 
755  // Text event
756  case WM_CHAR :
757  {
758  if (myKeyRepeatEnabled || ((LParam & (1 << 30)) == 0))
759  {
760  Event Evt;
761  Evt.Type = Event::TextEntered;
762  Evt.Text.Unicode = static_cast<Uint32>(WParam);
763  SendEvent(Evt);
764  }
765  break;
766  }
767 
768  // Keydown event
769  case WM_KEYDOWN :
770  case WM_SYSKEYDOWN :
771  {
772  if (myKeyRepeatEnabled || ((HIWORD(LParam) & KF_REPEAT) == 0))
773  {
774  Event Evt;
775  Evt.Type = Event::KeyPressed;
776  Evt.Key.Alt = HIWORD(GetAsyncKeyState(VK_MENU)) != 0;
777  Evt.Key.Control = HIWORD(GetAsyncKeyState(VK_CONTROL)) != 0;
778  Evt.Key.Shift = HIWORD(GetAsyncKeyState(VK_SHIFT)) != 0;
779  Evt.Key.Code = VirtualKeyCodeToSF(WParam, LParam);
780  SendEvent(Evt);
781  }
782  break;
783  }
784 
785  // Keyup event
786  case WM_KEYUP :
787  case WM_SYSKEYUP :
788  {
789  Event Evt;
790  Evt.Type = Event::KeyReleased;
791  Evt.Key.Alt = HIWORD(GetAsyncKeyState(VK_MENU)) != 0;
792  Evt.Key.Control = HIWORD(GetAsyncKeyState(VK_CONTROL)) != 0;
793  Evt.Key.Shift = HIWORD(GetAsyncKeyState(VK_SHIFT)) != 0;
794  Evt.Key.Code = VirtualKeyCodeToSF(WParam, LParam);
795  SendEvent(Evt);
796 
797  break;
798  }
799 
800  // Mouse wheel event
801  case WM_MOUSEWHEEL :
802  {
803  Event Evt;
804  Evt.Type = Event::MouseWheelMoved;
805  Evt.MouseWheel.Delta = static_cast<Int16>(HIWORD(WParam)) / 120;
806  SendEvent(Evt);
807  break;
808  }
809 
810  // Mouse left button down event
811  case WM_LBUTTONDOWN :
812  {
813  Event Evt;
814  Evt.Type = Event::MouseButtonPressed;
815  Evt.MouseButton.Button = Mouse::Left;
816  Evt.MouseButton.X = LOWORD(LParam);
817  Evt.MouseButton.Y = HIWORD(LParam);
818  SendEvent(Evt);
819  break;
820  }
821 
822  // Mouse left button up event
823  case WM_LBUTTONUP :
824  {
825  Event Evt;
826  Evt.Type = Event::MouseButtonReleased;
827  Evt.MouseButton.Button = Mouse::Left;
828  Evt.MouseButton.X = LOWORD(LParam);
829  Evt.MouseButton.Y = HIWORD(LParam);
830  SendEvent(Evt);
831  break;
832  }
833 
834  // Mouse right button down event
835  case WM_RBUTTONDOWN :
836  {
837  Event Evt;
838  Evt.Type = Event::MouseButtonPressed;
839  Evt.MouseButton.Button = Mouse::Right;
840  Evt.MouseButton.X = LOWORD(LParam);
841  Evt.MouseButton.Y = HIWORD(LParam);
842  SendEvent(Evt);
843  break;
844  }
845 
846  // Mouse right button up event
847  case WM_RBUTTONUP :
848  {
849  Event Evt;
850  Evt.Type = Event::MouseButtonReleased;
851  Evt.MouseButton.Button = Mouse::Right;
852  Evt.MouseButton.X = LOWORD(LParam);
853  Evt.MouseButton.Y = HIWORD(LParam);
854  SendEvent(Evt);
855  break;
856  }
857 
858  // Mouse wheel button down event
859  case WM_MBUTTONDOWN :
860  {
861  Event Evt;
862  Evt.Type = Event::MouseButtonPressed;
863  Evt.MouseButton.Button = Mouse::Middle;
864  Evt.MouseButton.X = LOWORD(LParam);
865  Evt.MouseButton.Y = HIWORD(LParam);
866  SendEvent(Evt);
867  break;
868  }
869 
870  // Mouse wheel button up event
871  case WM_MBUTTONUP :
872  {
873  Event Evt;
874  Evt.Type = Event::MouseButtonReleased;
875  Evt.MouseButton.Button = Mouse::Middle;
876  Evt.MouseButton.X = LOWORD(LParam);
877  Evt.MouseButton.Y = HIWORD(LParam);
878  SendEvent(Evt);
879  break;
880  }
881 
882  // Mouse X button down event
883  case WM_XBUTTONDOWN :
884  {
885  Event Evt;
886  Evt.Type = Event::MouseButtonPressed;
887  Evt.MouseButton.Button = HIWORD(WParam) == XBUTTON1 ? Mouse::XButton1 : Mouse::XButton2;
888  Evt.MouseButton.X = LOWORD(LParam);
889  Evt.MouseButton.Y = HIWORD(LParam);
890  SendEvent(Evt);
891  break;
892  }
893 
894  // Mouse X button up event
895  case WM_XBUTTONUP :
896  {
897  Event Evt;
898  Evt.Type = Event::MouseButtonReleased;
899  Evt.MouseButton.Button = HIWORD(WParam) == XBUTTON1 ? Mouse::XButton1 : Mouse::XButton2;
900  Evt.MouseButton.X = LOWORD(LParam);
901  Evt.MouseButton.Y = HIWORD(LParam);
902  SendEvent(Evt);
903  break;
904  }
905 
906  // Mouse move event
907  case WM_MOUSEMOVE :
908  {
909  // Check if we need to generate a MouseEntered event
910  if (!myIsCursorIn)
911  {
912  TRACKMOUSEEVENT MouseEvent;
913  MouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
914  MouseEvent.hwndTrack = myHandle;
915  MouseEvent.dwFlags = TME_LEAVE;
916  TrackMouseEvent(&MouseEvent);
917 
918  myIsCursorIn = true;
919 
920  Event Evt;
921  Evt.Type = Event::MouseEntered;
922  SendEvent(Evt);
923  }
924 
925  Event Evt;
926  Evt.Type = Event::MouseMoved;
927  Evt.MouseMove.X = LOWORD(LParam);
928  Evt.MouseMove.Y = HIWORD(LParam);
929  SendEvent(Evt);
930  break;
931  }
932 
933  // Mouse leave event
934  case WM_MOUSELEAVE :
935  {
936  myIsCursorIn = false;
937 
938  Event Evt;
939  Evt.Type = Event::MouseLeft;
940  SendEvent(Evt);
941  break;
942  }
943  }
944 }
945 
946 
950 Key::Code WindowImplWin32::VirtualKeyCodeToSF(WPARAM VirtualKey, LPARAM Flags)
951 {
952  switch (VirtualKey)
953  {
954  // Check the scancode to distinguish between left and right shift
955  case VK_SHIFT :
956  {
957  static UINT LShift = MapVirtualKey(VK_LSHIFT, MAPVK_VK_TO_VSC);
958  UINT scancode = (Flags & (0xFF << 16)) >> 16;
959  return scancode == LShift ? Key::LShift : Key::RShift;
960  }
961 
962  // Check the "extended" flag to distinguish between left and right alt
963  case VK_MENU : return (HIWORD(Flags) & KF_EXTENDED) ? Key::RAlt : Key::LAlt;
964 
965  // Check the "extended" flag to distinguish between left and right control
966  case VK_CONTROL : return (HIWORD(Flags) & KF_EXTENDED) ? Key::RControl : Key::LControl;
967 
968  // Other keys are reported properly
969  case VK_LWIN : return Key::LSystem;
970  case VK_RWIN : return Key::RSystem;
971  case VK_APPS : return Key::Menu;
972  case VK_OEM_1 : return Key::SemiColon;
973  case VK_OEM_2 : return Key::Slash;
974  case VK_OEM_PLUS : return Key::Equal;
975  case VK_OEM_MINUS : return Key::Dash;
976  case VK_OEM_4 : return Key::LBracket;
977  case VK_OEM_6 : return Key::RBracket;
978  case VK_OEM_COMMA : return Key::Comma;
979  case VK_OEM_PERIOD : return Key::Period;
980  case VK_OEM_7 : return Key::Quote;
981  case VK_OEM_5 : return Key::BackSlash;
982  case VK_OEM_3 : return Key::Tilde;
983  case VK_ESCAPE : return Key::Escape;
984  case VK_SPACE : return Key::Space;
985  case VK_RETURN : return Key::Return;
986  case VK_BACK : return Key::Back;
987  case VK_TAB : return Key::Tab;
988  case VK_PRIOR : return Key::PageUp;
989  case VK_NEXT : return Key::PageDown;
990  case VK_END : return Key::End;
991  case VK_HOME : return Key::Home;
992  case VK_INSERT : return Key::Insert;
993  case VK_DELETE : return Key::Delete;
994  case VK_ADD : return Key::Add;
995  case VK_SUBTRACT : return Key::Subtract;
996  case VK_MULTIPLY : return Key::Multiply;
997  case VK_DIVIDE : return Key::Divide;
998  case VK_PAUSE : return Key::Pause;
999  case VK_F1 : return Key::F1;
1000  case VK_F2 : return Key::F2;
1001  case VK_F3 : return Key::F3;
1002  case VK_F4 : return Key::F4;
1003  case VK_F5 : return Key::F5;
1004  case VK_F6 : return Key::F6;
1005  case VK_F7 : return Key::F7;
1006  case VK_F8 : return Key::F8;
1007  case VK_F9 : return Key::F9;
1008  case VK_F10 : return Key::F10;
1009  case VK_F11 : return Key::F11;
1010  case VK_F12 : return Key::F12;
1011  case VK_F13 : return Key::F13;
1012  case VK_F14 : return Key::F14;
1013  case VK_F15 : return Key::F15;
1014  case VK_LEFT : return Key::Left;
1015  case VK_RIGHT : return Key::Right;
1016  case VK_UP : return Key::Up;
1017  case VK_DOWN : return Key::Down;
1018  case VK_NUMPAD0 : return Key::Numpad0;
1019  case VK_NUMPAD1 : return Key::Numpad1;
1020  case VK_NUMPAD2 : return Key::Numpad2;
1021  case VK_NUMPAD3 : return Key::Numpad3;
1022  case VK_NUMPAD4 : return Key::Numpad4;
1023  case VK_NUMPAD5 : return Key::Numpad5;
1024  case VK_NUMPAD6 : return Key::Numpad6;
1025  case VK_NUMPAD7 : return Key::Numpad7;
1026  case VK_NUMPAD8 : return Key::Numpad8;
1027  case VK_NUMPAD9 : return Key::Numpad9;
1028  case 'A' : return Key::A;
1029  case 'Z' : return Key::Z;
1030  case 'E' : return Key::E;
1031  case 'R' : return Key::R;
1032  case 'T' : return Key::T;
1033  case 'Y' : return Key::Y;
1034  case 'U' : return Key::U;
1035  case 'I' : return Key::I;
1036  case 'O' : return Key::O;
1037  case 'P' : return Key::P;
1038  case 'Q' : return Key::Q;
1039  case 'S' : return Key::S;
1040  case 'D' : return Key::D;
1041  case 'F' : return Key::F;
1042  case 'G' : return Key::G;
1043  case 'H' : return Key::H;
1044  case 'J' : return Key::J;
1045  case 'K' : return Key::K;
1046  case 'L' : return Key::L;
1047  case 'M' : return Key::M;
1048  case 'W' : return Key::W;
1049  case 'X' : return Key::X;
1050  case 'C' : return Key::C;
1051  case 'V' : return Key::V;
1052  case 'B' : return Key::B;
1053  case 'N' : return Key::N;
1054  case '0' : return Key::Num0;
1055  case '1' : return Key::Num1;
1056  case '2' : return Key::Num2;
1057  case '3' : return Key::Num3;
1058  case '4' : return Key::Num4;
1059  case '5' : return Key::Num5;
1060  case '6' : return Key::Num6;
1061  case '7' : return Key::Num7;
1062  case '8' : return Key::Num8;
1063  case '9' : return Key::Num9;
1064  }
1065 
1066  return Key::Code(0);
1067 }
1068 
1069 
1075 bool WindowImplWin32::HasUnicodeSupport()
1076 {
1077  OSVERSIONINFO VersionInfo;
1078  ZeroMemory(&VersionInfo, sizeof(VersionInfo));
1079  VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo);
1080 
1081  if (GetVersionEx(&VersionInfo))
1082  {
1083  return VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT;
1084  }
1085  else
1086  {
1087  return false;
1088  }
1089 }
1090 
1091 
1095 LRESULT CALLBACK WindowImplWin32::GlobalOnEvent(HWND Handle, UINT Message, WPARAM WParam, LPARAM LParam)
1096 {
1097  // Associate handle and Window instance when the creation message is received
1098  if (Message == WM_CREATE)
1099  {
1100  // Get WindowImplWin32 instance (it was passed as the last argument of CreateWindow)
1101  long This = reinterpret_cast<long>(reinterpret_cast<CREATESTRUCT*>(LParam)->lpCreateParams);
1102 
1103  // Set as the "user data" parameter of the window
1104  SetWindowLongPtr(Handle, GWLP_USERDATA, This);
1105  }
1106 
1107  // Get the WindowImpl instance corresponding to the window handle
1108  WindowImplWin32* Window = reinterpret_cast<WindowImplWin32*>(GetWindowLongPtr(Handle, GWLP_USERDATA));
1109 
1110  // Forward the event to the appropriate function
1111  if (Window)
1112  {
1113  Window->ProcessEvent(Message, WParam, LParam);
1114 
1115  if (Window->myCallback)
1116  return CallWindowProc(reinterpret_cast<WNDPROC>(Window->myCallback), Handle, Message, WParam, LParam);
1117  }
1118 
1119  // We don't forward the WM_CLOSE message to prevent the OS from automatically destroying the window
1120  if (Message == WM_CLOSE)
1121  return 0;
1122 
1123  static const bool HasUnicode = HasUnicodeSupport();
1124  return HasUnicode ? DefWindowProcW(Handle, Message, WParam, LParam) :
1125  DefWindowProcA(Handle, Message, WParam, LParam);
1126 }
1127 
1128 } // namespace priv
1129 
1130 } // namespace sf
OS specific key (left side) : windows (Win and Linux), apple (MacOS), ...
Definition: Event.hpp:83
Titlebar + resizable border + maximize button.
Definition: WindowStyle.hpp:41
static VideoMode GetDesktopMode()
Get the current desktop video mode.
Definition: VideoMode.cpp:91
Title bar + fixed border.
Definition: WindowStyle.hpp:40
No border / title bar (this flag and all others are mutually exclusive)
Definition: WindowStyle.hpp:39
Right arrow.
Definition: Event.hpp:115
&#39;
Definition: Event.hpp:94
Fullscreen mode (this flag and all others are mutually exclusive)
Definition: WindowStyle.hpp:43
bool SetActive(bool Active=true) const
Activate of deactivate the window as the current target for rendering.
Definition: Window.cpp:338
Down arrow.
Definition: Event.hpp:117
Titlebar + close button.
Definition: WindowStyle.hpp:42
OS specific key (right side) : windows (Win and Linux), apple (MacOS), ...
Definition: Event.hpp:87
Up arrow.
Definition: Event.hpp:116
Left arrow.
Definition: Event.hpp:114