3 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version. The Blender
9 * Foundation also sells licenses for use in proprietary software under
10 * the Blender License. See http://www.blender.org/BL/ for information
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23 * All rights reserved.
25 * The Original Code is: all of this file.
27 * Contributor(s): none yet.
29 * ***** END GPL/BL DUAL LICENSE BLOCK *****
35 * Copyright (C) 2001 NaN Technologies B.V.
36 * @author Maarten Gribnau
44 #pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning
46 #include "GHOST_SystemWin32.h"
49 * According to the docs the mouse wheel message is supported from windows 98
50 * upwards. Leaving WINVER at default value, the WM_MOUSEWHEEL message and the
51 * wheel detent value are undefined.
54 #define WM_MOUSEWHEEL 0x020A
55 #endif // WM_MOUSEWHEEL
57 #define WHEEL_DELTA 120 /* Value for rolling one detent */
61 #include "GHOST_Debug.h"
62 #include "GHOST_DisplayManagerWin32.h"
63 #include "GHOST_EventButton.h"
64 #include "GHOST_EventCursor.h"
65 #include "GHOST_EventKey.h"
66 #include "GHOST_EventWheel.h"
67 #include "GHOST_TimerTask.h"
68 #include "GHOST_TimerManager.h"
69 #include "GHOST_WindowManager.h"
70 #include "GHOST_WindowWin32.h"
72 // Key code values not found in winuser.h
77 #define VK_SEMICOLON 0xBA
78 #endif // VK_SEMICOLON
80 #define VK_PERIOD 0xBE
89 #define VK_BACK_QUOTE 0xC0
90 #endif // VK_BACK_QUOTE
95 #define VK_BACK_SLASH 0xDC
96 #endif // VK_BACK_SLASH
98 #define VK_EQUALS 0xBB
100 #ifndef VK_OPEN_BRACKET
101 #define VK_OPEN_BRACKET 0xDB
102 #endif // VK_OPEN_BRACKET
103 #ifndef VK_CLOSE_BRACKET
104 #define VK_CLOSE_BRACKET 0xDD
105 #endif // VK_CLOSE_BRACKET
108 GHOST_SystemWin32::GHOST_SystemWin32()
109 : m_hasPerformanceCounter(false), m_freq(0), m_start(0),
110 m_seperateLeftRight(false),
111 m_seperateLeftRightInitialized(false)
113 m_displayManager = new GHOST_DisplayManagerWin32 ();
114 GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::GHOST_SystemWin32(): m_displayManager==0\n");
115 m_displayManager->initialize();
118 GHOST_SystemWin32::~GHOST_SystemWin32()
123 GHOST_TUns64 GHOST_SystemWin32::getMilliSeconds() const
125 // Hardware does not support high resolution timers. We will use GetTickCount instead then.
126 if (!m_hasPerformanceCounter) {
127 return ::GetTickCount();
130 // Retrieve current count
132 ::QueryPerformanceCounter((LARGE_INTEGER*)&count);
134 // Calculate the time passed since system initialization.
135 __int64 delta = 1000*(count-m_start);
137 GHOST_TUns64 t = (GHOST_TUns64)(delta/m_freq);
142 GHOST_TUns8 GHOST_SystemWin32::getNumDisplays() const
144 GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::getNumDisplays(): m_displayManager==0\n");
145 GHOST_TUns8 numDisplays;
146 m_displayManager->getNumDisplays(numDisplays);
151 void GHOST_SystemWin32::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const
153 width = ::GetSystemMetrics(SM_CXSCREEN);
154 height= ::GetSystemMetrics(SM_CYSCREEN);
158 GHOST_IWindow* GHOST_SystemWin32::createWindow(
159 const STR_String& title,
160 GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height,
161 GHOST_TWindowState state, GHOST_TDrawingContextType type,
164 GHOST_Window* window = 0;
165 window = new GHOST_WindowWin32 (title, left, top, width, height, state, type, stereoVisual);
167 if (window->getValid()) {
168 // Store the pointer to the window
169 // if (state != GHOST_kWindowStateFullScreen) {
170 m_windowManager->addWindow(window);
182 bool GHOST_SystemWin32::processEvents(bool waitForEvent)
185 bool anyProcessed = false;
188 GHOST_TimerManager* timerMgr = getTimerManager();
190 if (waitForEvent && !::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE)) {
194 GHOST_TUns64 next = timerMgr->nextFireTime();
196 if (next == GHOST_kFireTimeNever) {
199 ::SetTimer(NULL, 0, next - getMilliSeconds(), NULL);
201 ::KillTimer(NULL, 0);
206 if (timerMgr->fireTimers(getMilliSeconds())) {
210 // Process all the events waiting for us
211 while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE) != 0) {
212 ::TranslateMessage(&msg);
213 ::DispatchMessage(&msg);
216 } while (waitForEvent && !anyProcessed);
222 GHOST_TSuccess GHOST_SystemWin32::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const
225 bool success = ::GetCursorPos(&point) == TRUE;
228 return GHOST_kSuccess;
232 GHOST_TSuccess GHOST_SystemWin32::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) const
234 return ::SetCursorPos(x, y) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
238 GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys& keys) const
241 GetKeyState and GetAsyncKeyState only work with Win95, Win98, NT4,
242 Terminal Server and Windows 2000.
243 But on WinME it always returns zero. These two functions are simply
244 skipped by Millenium Edition!
246 Official explanation from Microsoft:
247 Intentionally disabled.
248 It didn't work all that well on some newer hardware, and worked less
249 well with the passage of time, so it was fully disabled in ME.
251 if (m_seperateLeftRight && m_seperateLeftRightInitialized) {
252 bool down = HIBYTE(::GetKeyState(VK_LSHIFT)) != 0;
253 keys.set(GHOST_kModifierKeyLeftShift, down);
254 down = HIBYTE(::GetKeyState(VK_RSHIFT)) != 0;
255 keys.set(GHOST_kModifierKeyRightShift, down);
256 down = HIBYTE(::GetKeyState(VK_LMENU)) != 0;
257 keys.set(GHOST_kModifierKeyLeftAlt, down);
258 down = HIBYTE(::GetKeyState(VK_RMENU)) != 0;
259 keys.set(GHOST_kModifierKeyRightAlt, down);
260 down = HIBYTE(::GetKeyState(VK_LCONTROL)) != 0;
261 keys.set(GHOST_kModifierKeyLeftControl, down);
262 down = HIBYTE(::GetKeyState(VK_RCONTROL)) != 0;
263 keys.set(GHOST_kModifierKeyRightControl, down);
266 bool down = HIBYTE(::GetKeyState(VK_SHIFT)) != 0;
267 keys.set(GHOST_kModifierKeyLeftShift, down);
268 keys.set(GHOST_kModifierKeyRightShift, down);
269 down = HIBYTE(::GetKeyState(VK_MENU)) != 0;
270 keys.set(GHOST_kModifierKeyLeftAlt, down);
271 keys.set(GHOST_kModifierKeyRightAlt, down);
272 down = HIBYTE(::GetKeyState(VK_CONTROL)) != 0;
273 keys.set(GHOST_kModifierKeyLeftControl, down);
274 keys.set(GHOST_kModifierKeyRightControl, down);
276 return GHOST_kSuccess;
280 GHOST_TSuccess GHOST_SystemWin32::getButtons(GHOST_Buttons& buttons) const
282 /* Check for swapped buttons (left-handed mouse buttons)
283 * GetAsyncKeyState() will give back the state of the physical mouse buttons.
285 bool swapped = ::GetSystemMetrics(SM_SWAPBUTTON) == TRUE;
287 bool down = HIBYTE(::GetKeyState(VK_LBUTTON)) != 0;
288 buttons.set(swapped ? GHOST_kButtonMaskRight : GHOST_kButtonMaskLeft, down);
290 down = HIBYTE(::GetKeyState(VK_MBUTTON)) != 0;
291 buttons.set(GHOST_kButtonMaskMiddle, down);
293 down = HIBYTE(::GetKeyState(VK_RBUTTON)) != 0;
294 buttons.set(swapped ? GHOST_kButtonMaskLeft : GHOST_kButtonMaskRight, down);
295 return GHOST_kSuccess;
299 GHOST_TSuccess GHOST_SystemWin32::init()
301 GHOST_TSuccess success = GHOST_System::init();
303 // Determine whether this system has a high frequency performance counter. */
304 m_hasPerformanceCounter = ::QueryPerformanceFrequency((LARGE_INTEGER*)&m_freq) == TRUE;
305 if (m_hasPerformanceCounter) {
306 GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer available\n")
307 ::QueryPerformanceCounter((LARGE_INTEGER*)&m_start);
310 GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer not available\n")
315 wc.style= CS_HREDRAW | CS_VREDRAW;
316 wc.lpfnWndProc= s_wndProc;
319 wc.hInstance= ::GetModuleHandle(0);
321 wc.hIcon = ::LoadIcon(wc.hInstance, "APPICON");
323 wc.hIcon = ::LoadIcon(NULL, "APPICON");
326 ::LoadIcon(NULL, IDI_APPLICATION);
328 wc.hCursor = ::LoadCursor(0, IDC_ARROW);
329 wc.hbrBackground= (HBRUSH)::GetStockObject(BLACK_BRUSH);
331 wc.lpszClassName= GHOST_WindowWin32::getWindowClassName();
333 // Use RegisterClassEx for setting small icon
334 if (::RegisterClass(&wc) == 0) {
335 success = GHOST_kFailure;
342 GHOST_TSuccess GHOST_SystemWin32::exit()
344 return GHOST_System::exit();
348 GHOST_TKey GHOST_SystemWin32::convertKey(WPARAM wParam, LPARAM lParam) const
351 bool isExtended = (lParam&(1<<24))?true:false;
353 if ((wParam >= '0') && (wParam <= '9')) {
354 // VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39)
355 key = (GHOST_TKey)(wParam - '0' + GHOST_kKey0);
357 else if ((wParam >= 'A') && (wParam <= 'Z')) {
358 // VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A)
359 key = (GHOST_TKey)(wParam - 'A' + GHOST_kKeyA);
361 else if ((wParam >= VK_F1) && (wParam <= VK_F24)) {
362 key = (GHOST_TKey)(wParam - VK_F1 + GHOST_kKeyF1);
367 key = isExtended?GHOST_kKeyNumpadEnter:GHOST_kKeyEnter;
370 case VK_BACK: key = GHOST_kKeyBackSpace; break;
371 case VK_TAB: key = GHOST_kKeyTab; break;
372 case VK_ESCAPE: key = GHOST_kKeyEsc; break;
373 case VK_SPACE: key = GHOST_kKeySpace; break;
374 case VK_PRIOR: key = GHOST_kKeyUpPage; break;
375 case VK_NEXT: key = GHOST_kKeyDownPage; break;
376 case VK_END: key = GHOST_kKeyEnd; break;
377 case VK_HOME: key = GHOST_kKeyHome; break;
378 case VK_INSERT: key = GHOST_kKeyInsert; break;
379 case VK_DELETE: key = GHOST_kKeyDelete; break;
380 case VK_LEFT: key = GHOST_kKeyLeftArrow; break;
381 case VK_RIGHT: key = GHOST_kKeyRightArrow; break;
382 case VK_UP: key = GHOST_kKeyUpArrow; break;
383 case VK_DOWN: key = GHOST_kKeyDownArrow; break;
384 case VK_NUMPAD0: key = GHOST_kKeyNumpad0; break;
385 case VK_NUMPAD1: key = GHOST_kKeyNumpad1; break;
386 case VK_NUMPAD2: key = GHOST_kKeyNumpad2; break;
387 case VK_NUMPAD3: key = GHOST_kKeyNumpad3; break;
388 case VK_NUMPAD4: key = GHOST_kKeyNumpad4; break;
389 case VK_NUMPAD5: key = GHOST_kKeyNumpad5; break;
390 case VK_NUMPAD6: key = GHOST_kKeyNumpad6; break;
391 case VK_NUMPAD7: key = GHOST_kKeyNumpad7; break;
392 case VK_NUMPAD8: key = GHOST_kKeyNumpad8; break;
393 case VK_NUMPAD9: key = GHOST_kKeyNumpad9; break;
394 case VK_SNAPSHOT: key = GHOST_kKeyPrintScreen; break;
395 case VK_PAUSE: key = GHOST_kKeyPause; break;
396 case VK_MULTIPLY: key = GHOST_kKeyNumpadAsterisk; break;
397 case VK_SUBTRACT: key = GHOST_kKeyNumpadMinus; break;
398 case VK_DECIMAL: key = GHOST_kKeyNumpadPeriod; break;
399 case VK_DIVIDE: key = GHOST_kKeyNumpadSlash; break;
400 case VK_ADD: key = GHOST_kKeyNumpadPlus; break;
402 case VK_SEMICOLON: key = GHOST_kKeySemicolon; break;
403 case VK_EQUALS: key = GHOST_kKeyEqual; break;
404 case VK_COMMA: key = GHOST_kKeyComma; break;
405 case VK_MINUS: key = GHOST_kKeyMinus; break;
406 case VK_PERIOD: key = GHOST_kKeyPeriod; break;
407 case VK_SLASH: key = GHOST_kKeySlash; break;
408 case VK_BACK_QUOTE: key = GHOST_kKeyAccentGrave; break;
409 case VK_OPEN_BRACKET: key = GHOST_kKeyLeftBracket; break;
410 case VK_BACK_SLASH: key = GHOST_kKeyBackslash; break;
411 case VK_CLOSE_BRACKET: key = GHOST_kKeyRightBracket; break;
412 case VK_QUOTE: key = GHOST_kKeyQuote; break;
414 // Process these keys separately because we need to distinguish right from left modifier keys
424 key = GHOST_kKeyUnknown;
432 void GHOST_SystemWin32::processModifierKeys(GHOST_IWindow *window)
434 GHOST_ModifierKeys oldModifiers, newModifiers;
435 // Retrieve old state of the modifier keys
436 ((GHOST_SystemWin32*)getSystem())->retrieveModifierKeys(oldModifiers);
437 // Retrieve current state of the modifier keys
438 ((GHOST_SystemWin32*)getSystem())->getModifierKeys(newModifiers);
440 // Compare the old and the new
441 if (!newModifiers.equals(oldModifiers)) {
442 // Create events for the masks that changed
443 for (int i = 0; i < GHOST_kModifierKeyNumMasks; i++) {
444 if (newModifiers.get((GHOST_TModifierKeyMask)i) != oldModifiers.get((GHOST_TModifierKeyMask)i)) {
445 // Convert the mask to a key code
446 GHOST_TKey key = GHOST_ModifierKeys::getModifierKeyCode((GHOST_TModifierKeyMask)i);
447 bool keyDown = newModifiers.get((GHOST_TModifierKeyMask)i);
448 GHOST_EventKey* event;
449 if (key != GHOST_kKeyUnknown) {
451 event = new GHOST_EventKey(getSystem()->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key);
458 // Store new modifier keys state
459 ((GHOST_SystemWin32*)getSystem())->storeModifierKeys(newModifiers);
463 GHOST_EventButton* GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, GHOST_IWindow *window, GHOST_TButtonMask mask)
465 return new GHOST_EventButton (getSystem()->getMilliSeconds(), type, window, mask);
469 GHOST_EventCursor* GHOST_SystemWin32::processCursorEvent(GHOST_TEventType type, GHOST_IWindow *window)
472 getSystem()->getCursorPosition(x, y);
473 printf("%d %d\n",x,y);
474 return new GHOST_EventCursor (getSystem()->getMilliSeconds(), type, window, x, y);
478 GHOST_EventWheel* GHOST_SystemWin32::processWheelEvent(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam)
480 // short fwKeys = LOWORD(wParam); // key flags
481 int zDelta = (short) HIWORD(wParam); // wheel rotation
482 zDelta /= WHEEL_DELTA;
483 // short xPos = (short) LOWORD(lParam); // horizontal position of pointer
484 // short yPos = (short) HIWORD(lParam); // vertical position of pointer
485 return new GHOST_EventWheel (getSystem()->getMilliSeconds(), window, zDelta);
489 GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, bool keyDown, WPARAM wParam, LPARAM lParam)
491 GHOST_TKey key = ((GHOST_SystemWin32*)getSystem())->convertKey(wParam, lParam);
492 GHOST_EventKey* event;
493 if (key != GHOST_kKeyUnknown) {
497 /* Eat any character related messages */
498 if (::PeekMessage(&keyMsg, NULL, WM_CHAR, WM_SYSDEADCHAR, PM_REMOVE)) {
499 ascii = (char) keyMsg.wParam;
502 event = new GHOST_EventKey(getSystem()->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key, ascii);
511 GHOST_Event* GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type, GHOST_IWindow* window)
513 return new GHOST_Event(getSystem()->getMilliSeconds(), type, window);
517 LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
519 GHOST_Event* event = 0;
521 GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem());
522 GHOST_ASSERT(system, "GHOST_SystemWin32::s_wndProc(): system not initialized")
525 GHOST_WindowWin32* window = (GHOST_WindowWin32*)::GetWindowLong(hwnd, GWL_USERDATA);
528 ////////////////////////////////////////////////////////////////////////
529 // Keyboard events, processed
530 ////////////////////////////////////////////////////////////////////////
532 /* The WM_KEYDOWN message is posted to the window with the keyboard focus when a
533 * nonsystem key is pressed. A nonsystem key is a key that is pressed when the alt
534 * key is not pressed.
537 /* The WM_SYSKEYDOWN message is posted to the window with the keyboard focus when
538 * the user presses the F10 key (which activates the menu bar) or holds down the
539 * alt key and then presses another key. It also occurs when no window currently
540 * has the keyboard focus; in this case, the WM_SYSKEYDOWN message is sent to the
541 * active window. The window that receives the message can distinguish between these
542 * two contexts by checking the context code in the lKeyData parameter.
548 if (!system->m_seperateLeftRightInitialized) {
549 // Check whether this system supports seperate left and right keys
552 system->m_seperateLeftRight =
553 (HIBYTE(::GetKeyState(VK_LSHIFT)) != 0) ||
554 (HIBYTE(::GetKeyState(VK_RSHIFT)) != 0) ?
558 system->m_seperateLeftRight =
559 (HIBYTE(::GetKeyState(VK_LCONTROL)) != 0) ||
560 (HIBYTE(::GetKeyState(VK_RCONTROL)) != 0) ?
564 system->m_seperateLeftRight =
565 (HIBYTE(::GetKeyState(VK_LMENU)) != 0) ||
566 (HIBYTE(::GetKeyState(VK_RMENU)) != 0) ?
570 system->m_seperateLeftRightInitialized = true;
572 system->processModifierKeys(window);
573 // Bypass call to DefWindowProc
576 event = processKeyEvent(window, true, wParam, lParam);
578 GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
580 GHOST_PRINT(" key ignored\n")
592 system->processModifierKeys(window);
593 // Bypass call to DefWindowProc
596 event = processKeyEvent(window, false, wParam, lParam);
598 GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
600 GHOST_PRINT(" key ignored\n")
606 ////////////////////////////////////////////////////////////////////////
607 // Keyboard events, ignored
608 ////////////////////////////////////////////////////////////////////////
610 /* The WM_CHAR message is posted to the window with the keyboard focus when
611 * a WM_KEYDOWN message is translated by the TranslateMessage function. WM_CHAR
612 * contains the character code of the key that was pressed.
615 /* The WM_DEADCHAR message is posted to the window with the keyboard focus when a
616 * WM_KEYUP message is translated by the TranslateMessage function. WM_DEADCHAR
617 * specifies a character code generated by a dead key. A dead key is a key that
618 * generates a character, such as the umlaut (double-dot), that is combined with
619 * another character to form a composite character. For example, the umlaut-O
620 * character (Ù) is generated by typing the dead key for the umlaut character, and
621 * then typing the O key.
624 /* The WM_SYSDEADCHAR message is sent to the window with the keyboard focus when
625 * a WM_SYSKEYDOWN message is translated by the TranslateMessage function.
626 * WM_SYSDEADCHAR specifies the character code of a system dead key - that is,
627 * a dead key that is pressed while holding down the alt key.
631 ////////////////////////////////////////////////////////////////////////
632 // Mouse events, processed
633 ////////////////////////////////////////////////////////////////////////
635 window->registerMouseClickEvent(true);
636 event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft);
639 window->registerMouseClickEvent(true);
640 event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskMiddle);
643 window->registerMouseClickEvent(true);
644 event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight);
647 window->registerMouseClickEvent(false);
648 event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft);
651 window->registerMouseClickEvent(false);
652 event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskMiddle);
655 window->registerMouseClickEvent(false);
656 event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight);
659 event = processCursorEvent(GHOST_kEventCursorMove, window);
662 /* The WM_MOUSEWHEEL message is sent to the focus window
663 * when the mouse wheel is rotated. The DefWindowProc
664 * function propagates the message to the window's parent.
665 * There should be no internal forwarding of the message,
666 * since DefWindowProc propagates it up the parent chain
667 * until it finds a window that processes it.
669 event = processWheelEvent(window, wParam, lParam);
672 /* The WM_SETCURSOR message is sent to a window if the mouse causes the cursor
673 * to move within a window and mouse input is not captured.
674 * This means we have to set the cursor shape every time the mouse moves!
675 * The DefWindowProc function uses this message to set the cursor to an
676 * arrow if it is not in the client area.
678 if (LOWORD(lParam) == HTCLIENT) {
679 // Load the current cursor
680 window->loadCursor(window->getCursorVisibility(), window->getCursorShape());
681 // Bypass call to DefWindowProc
685 // Outside of client area show standard cursor
686 window->loadCursor(true, GHOST_kStandardCursorDefault);
690 ////////////////////////////////////////////////////////////////////////
691 // Mouse events, ignored
692 ////////////////////////////////////////////////////////////////////////
694 /* The WM_NCMOUSEMOVE message is posted to a window when the cursor is moved
695 * within the nonclient area of the window. This message is posted to the window
696 * that contains the cursor. If a window has captured the mouse, this message is not posted.
699 /* The WM_NCHITTEST message is sent to a window when the cursor moves, or
700 * when a mouse button is pressed or released. If the mouse is not captured,
701 * the message is sent to the window beneath the cursor. Otherwise, the message
702 * is sent to the window that has captured the mouse.
706 ////////////////////////////////////////////////////////////////////////
707 // Window events, processed
708 ////////////////////////////////////////////////////////////////////////
710 /* The WM_CLOSE message is sent as a signal that a window or an application should terminate. */
711 event = processWindowEvent(GHOST_kEventWindowClose, window);
714 /* The WM_ACTIVATE message is sent to both the window being activated and the window being
715 * deactivated. If the windows use the same input queue, the message is sent synchronously,
716 * first to the window procedure of the top-level window being deactivated, then to the window
717 * procedure of the top-level window being activated. If the windows use different input queues,
718 * the message is sent asynchronously, so the window is activated immediately.
720 event = processWindowEvent(LOWORD(wParam) ? GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate, window);
723 /* An application sends the WM_PAINT message when the system or another application
724 * makes a request to paint a portion of an application's window. The message is sent
725 * when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage
726 * function when the application obtains a WM_PAINT message by using the GetMessage or
727 * PeekMessage function.
729 event = processWindowEvent(GHOST_kEventWindowUpdate, window);
730 ::ValidateRect(hwnd, NULL);
733 /* The WM_SIZE message is sent to a window after its size has changed.
734 * The WM_SIZE and WM_MOVE messages are not sent if an application handles the
735 * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
736 * to perform any move or size change processing during the WM_WINDOWPOSCHANGED
737 * message without calling DefWindowProc.
739 event = processWindowEvent(GHOST_kEventWindowSize, window);
740 case WM_CAPTURECHANGED:
741 window->lostMouseCapture();
744 ////////////////////////////////////////////////////////////////////////
745 // Window events, ignored
746 ////////////////////////////////////////////////////////////////////////
747 case WM_WINDOWPOSCHANGED:
748 /* The WM_WINDOWPOSCHANGED message is sent to a window whose size, position, or place
749 * in the Z order has changed as a result of a call to the SetWindowPos function or
750 * another window-management function.
751 * The WM_SIZE and WM_MOVE messages are not sent if an application handles the
752 * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
753 * to perform any move or size change processing during the WM_WINDOWPOSCHANGED
754 * message without calling DefWindowProc.
757 /* The WM_SIZE and WM_MOVE messages are not sent if an application handles the
758 * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
759 * to perform any move or size change processing during the WM_WINDOWPOSCHANGED
760 * message without calling DefWindowProc.
763 /* An application sends the WM_ERASEBKGND message when the window background must be
764 * erased (for example, when a window is resized). The message is sent to prepare an
765 * invalidated portion of a window for painting.
768 /* An application sends the WM_NCPAINT message to a window when its frame must be painted. */
770 /* The WM_NCACTIVATE message is sent to a window when its nonclient area needs to be changed
771 * to indicate an active or inactive state.
774 /* The WM_DESTROY message is sent when a window is being destroyed. It is sent to the window
775 * procedure of the window being destroyed after the window is removed from the screen.
776 * This message is sent first to the window being destroyed and then to the child windows
777 * (if any) as they are destroyed. During the processing of the message, it can be assumed
778 * that all child windows still exist.
781 /* The WM_NCDESTROY message informs a window that its nonclient area is being destroyed. The
782 * DestroyWindow function sends the WM_NCDESTROY message to the window following the WM_DESTROY
783 * message. WM_DESTROY is used to free the allocated memory object associated with the window.
786 /* The WM_KILLFOCUS message is sent to a window immediately before it loses the keyboard focus. */
788 /* The WM_SHOWWINDOW message is sent to a window when the window is about to be hidden or shown. */
789 case WM_WINDOWPOSCHANGING:
790 /* The WM_WINDOWPOSCHANGING message is sent to a window whose size, position, or place in
791 * the Z order is about to change as a result of a call to the SetWindowPos function or
792 * another window-management function.
795 /* The WM_SETFOCUS message is sent to a window after it has gained the keyboard focus. */
797 /* The WM_MOVING message is sent to a window that the user is moving. By processing
798 * this message, an application can monitor the size and position of the drag rectangle
799 * and, if needed, change its size or position.
801 case WM_ENTERSIZEMOVE:
802 /* The WM_ENTERSIZEMOVE message is sent one time to a window after it enters the moving
803 * or sizing modal loop. The window enters the moving or sizing modal loop when the user
804 * clicks the window's title bar or sizing border, or when the window passes the
805 * WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the
806 * message specifies the SC_MOVE or SC_SIZE value. The operation is complete when
807 * DefWindowProc returns.
811 ////////////////////////////////////////////////////////////////////////
813 ////////////////////////////////////////////////////////////////////////
815 /* An application sends a WM_GETTEXT message to copy the text that
816 * corresponds to a window into a buffer provided by the caller.
819 /* The WM_ACTIVATEAPP message is sent when a window belonging to a
820 * different application than the active window is about to be activated.
821 * The message is sent to the application whose window is being activated
822 * and to the application whose window is being deactivated.
825 /* The WIN32 docs say:
826 * The WM_TIMER message is posted to the installing thread's message queue
827 * when a timer expires. You can process the message by providing a WM_TIMER
828 * case in the window procedure. Otherwise, the default window procedure will
829 * call the TimerProc callback function specified in the call to the SetTimer
830 * function used to install the timer.
832 * In GHOST, we let DefWindowProc call the timer callback.
838 // Event found for a window before the pointer to the class has been set.
839 GHOST_PRINT("GHOST_SystemWin32::wndProc: GHOST window event before creation\n")
840 /* These are events we typically miss at this point:
841 WM_GETMINMAXINFO 0x24
845 We let DefWindowProc do the work.
850 // Events without valid hwnd
851 GHOST_PRINT("GHOST_SystemWin32::wndProc: event without window\n")
855 system->pushEvent(event);
859 lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);