WindowImplWin32.cpp
1
2//
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
51namespace sf
52{
53namespace priv
54{
56// Static member data
58unsigned int WindowImplWin32::ourWindowCount = 0;
59const char* WindowImplWin32::ourClassNameA = "SFML_Window";
60const wchar_t* WindowImplWin32::ourClassNameW = L"SFML_Window";
61WindowImplWin32* WindowImplWin32::ourFullscreenWindow = NULL;
62
63
68WindowImplWin32::WindowImplWin32() :
69myHandle (NULL),
70myCallback (0),
71myCursor (NULL),
72myIcon (NULL),
73myKeyRepeatEnabled(true),
74myIsCursorIn (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
110WindowImplWin32::WindowImplWin32(WindowHandle Handle, WindowSettings& Params) :
111myHandle (NULL),
112myCallback (0),
113myCursor (NULL),
114myIcon (NULL),
115myKeyRepeatEnabled(true),
116myIsCursorIn (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
143WindowImplWin32::WindowImplWin32(VideoMode Mode, const std::string& Title, unsigned long WindowStyle, WindowSettings& Params) :
144myHandle (NULL),
145myCallback (0),
146myCursor (NULL),
147myIcon (NULL),
148myKeyRepeatEnabled(true),
149myIsCursorIn (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
222WindowImplWin32::~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
261bool WindowImplWin32::IsContextActive()
262{
263 return wglGetCurrentContext() != NULL;
264}
265
266
270void 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
288void WindowImplWin32::Display()
289{
290 if (myDeviceContext && myGLContext)
291 SwapBuffers(myDeviceContext);
292}
293
294
298void 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
316void WindowImplWin32::UseVerticalSync(bool Enabled)
317{
318 PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = reinterpret_cast<PFNWGLSWAPINTERVALEXTPROC>(wglGetProcAddress("wglSwapIntervalEXT"));
319 if (wglSwapIntervalEXT)
320 wglSwapIntervalEXT(Enabled ? 1 : 0);
321}
322
323
327void 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
341void 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
352void WindowImplWin32::SetPosition(int Left, int Top)
353{
354 SetWindowPos(myHandle, NULL, Left, Top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
355}
356
357
361void 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
377void WindowImplWin32::Show(bool State)
378{
379 ShowWindow(myHandle, State ? SW_SHOW : SW_HIDE);
380}
381
382
386void WindowImplWin32::EnableKeyRepeat(bool Enabled)
387{
388 myKeyRepeatEnabled = Enabled;
389}
390
391
395void 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
430void 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
468void 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
500void 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
653void 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
685void 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
950Key::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
1075bool 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
1095LRESULT 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
@ Left
Left arrow.
Definition Event.hpp:114
@ Fullscreen
Fullscreen mode (this flag and all others are mutually exclusive).