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);
320 wc.hIcon = ::LoadIcon(wc.hInstance, "APPICON");
322 ::LoadIcon(NULL, IDI_APPLICATION);
324 wc.hCursor = ::LoadCursor(0, IDC_ARROW);
325 wc.hbrBackground= (HBRUSH)::GetStockObject(BLACK_BRUSH);
327 wc.lpszClassName= GHOST_WindowWin32::getWindowClassName();
329 // Use RegisterClassEx for setting small icon
330 if (::RegisterClass(&wc) == 0) {
331 success = GHOST_kFailure;
338 GHOST_TSuccess GHOST_SystemWin32::exit()
340 return GHOST_System::exit();
344 GHOST_TKey GHOST_SystemWin32::convertKey(WPARAM wParam, LPARAM lParam) const
347 bool isExtended = (lParam&(1<<24))?true:false;
349 if ((wParam >= '0') && (wParam <= '9')) {
350 // VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39)
351 key = (GHOST_TKey)(wParam - '0' + GHOST_kKey0);
353 else if ((wParam >= 'A') && (wParam <= 'Z')) {
354 // VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A)
355 key = (GHOST_TKey)(wParam - 'A' + GHOST_kKeyA);
357 else if ((wParam >= VK_F1) && (wParam <= VK_F24)) {
358 key = (GHOST_TKey)(wParam - VK_F1 + GHOST_kKeyF1);
363 key = isExtended?GHOST_kKeyNumpadEnter:GHOST_kKeyEnter;
366 case VK_BACK: key = GHOST_kKeyBackSpace; break;
367 case VK_TAB: key = GHOST_kKeyTab; break;
368 case VK_ESCAPE: key = GHOST_kKeyEsc; break;
369 case VK_SPACE: key = GHOST_kKeySpace; break;
370 case VK_PRIOR: key = GHOST_kKeyUpPage; break;
371 case VK_NEXT: key = GHOST_kKeyDownPage; break;
372 case VK_END: key = GHOST_kKeyEnd; break;
373 case VK_HOME: key = GHOST_kKeyHome; break;
374 case VK_INSERT: key = GHOST_kKeyInsert; break;
375 case VK_DELETE: key = GHOST_kKeyDelete; break;
376 case VK_LEFT: key = GHOST_kKeyLeftArrow; break;
377 case VK_RIGHT: key = GHOST_kKeyRightArrow; break;
378 case VK_UP: key = GHOST_kKeyUpArrow; break;
379 case VK_DOWN: key = GHOST_kKeyDownArrow; break;
380 case VK_NUMPAD0: key = GHOST_kKeyNumpad0; break;
381 case VK_NUMPAD1: key = GHOST_kKeyNumpad1; break;
382 case VK_NUMPAD2: key = GHOST_kKeyNumpad2; break;
383 case VK_NUMPAD3: key = GHOST_kKeyNumpad3; break;
384 case VK_NUMPAD4: key = GHOST_kKeyNumpad4; break;
385 case VK_NUMPAD5: key = GHOST_kKeyNumpad5; break;
386 case VK_NUMPAD6: key = GHOST_kKeyNumpad6; break;
387 case VK_NUMPAD7: key = GHOST_kKeyNumpad7; break;
388 case VK_NUMPAD8: key = GHOST_kKeyNumpad8; break;
389 case VK_NUMPAD9: key = GHOST_kKeyNumpad9; break;
390 case VK_SNAPSHOT: key = GHOST_kKeyPrintScreen; break;
391 case VK_PAUSE: key = GHOST_kKeyPause; break;
392 case VK_MULTIPLY: key = GHOST_kKeyNumpadAsterisk; break;
393 case VK_SUBTRACT: key = GHOST_kKeyNumpadMinus; break;
394 case VK_DECIMAL: key = GHOST_kKeyNumpadPeriod; break;
395 case VK_DIVIDE: key = GHOST_kKeyNumpadSlash; break;
396 case VK_ADD: key = GHOST_kKeyNumpadPlus; break;
398 case VK_SEMICOLON: key = GHOST_kKeySemicolon; break;
399 case VK_EQUALS: key = GHOST_kKeyEqual; break;
400 case VK_COMMA: key = GHOST_kKeyComma; break;
401 case VK_MINUS: key = GHOST_kKeyMinus; break;
402 case VK_PERIOD: key = GHOST_kKeyPeriod; break;
403 case VK_SLASH: key = GHOST_kKeySlash; break;
404 case VK_BACK_QUOTE: key = GHOST_kKeyAccentGrave; break;
405 case VK_OPEN_BRACKET: key = GHOST_kKeyLeftBracket; break;
406 case VK_BACK_SLASH: key = GHOST_kKeyBackslash; break;
407 case VK_CLOSE_BRACKET: key = GHOST_kKeyRightBracket; break;
408 case VK_QUOTE: key = GHOST_kKeyQuote; break;
410 // Process these keys separately because we need to distinguish right from left modifier keys
420 key = GHOST_kKeyUnknown;
428 void GHOST_SystemWin32::processModifierKeys(GHOST_IWindow *window)
430 GHOST_ModifierKeys oldModifiers, newModifiers;
431 // Retrieve old state of the modifier keys
432 ((GHOST_SystemWin32*)getSystem())->retrieveModifierKeys(oldModifiers);
433 // Retrieve current state of the modifier keys
434 ((GHOST_SystemWin32*)getSystem())->getModifierKeys(newModifiers);
436 // Compare the old and the new
437 if (!newModifiers.equals(oldModifiers)) {
438 // Create events for the masks that changed
439 for (int i = 0; i < GHOST_kModifierKeyNumMasks; i++) {
440 if (newModifiers.get((GHOST_TModifierKeyMask)i) != oldModifiers.get((GHOST_TModifierKeyMask)i)) {
441 // Convert the mask to a key code
442 GHOST_TKey key = GHOST_ModifierKeys::getModifierKeyCode((GHOST_TModifierKeyMask)i);
443 bool keyDown = newModifiers.get((GHOST_TModifierKeyMask)i);
444 GHOST_EventKey* event;
445 if (key != GHOST_kKeyUnknown) {
447 event = new GHOST_EventKey(getSystem()->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key);
454 // Store new modifier keys state
455 ((GHOST_SystemWin32*)getSystem())->storeModifierKeys(newModifiers);
459 GHOST_EventButton* GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, GHOST_IWindow *window, GHOST_TButtonMask mask)
461 return new GHOST_EventButton (getSystem()->getMilliSeconds(), type, window, mask);
465 GHOST_EventCursor* GHOST_SystemWin32::processCursorEvent(GHOST_TEventType type, GHOST_IWindow *window)
468 getSystem()->getCursorPosition(x, y);
469 return new GHOST_EventCursor (getSystem()->getMilliSeconds(), type, window, x, y);
473 GHOST_EventWheel* GHOST_SystemWin32::processWheelEvent(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam)
475 // short fwKeys = LOWORD(wParam); // key flags
476 int zDelta = (short) HIWORD(wParam); // wheel rotation
477 zDelta /= WHEEL_DELTA;
478 // short xPos = (short) LOWORD(lParam); // horizontal position of pointer
479 // short yPos = (short) HIWORD(lParam); // vertical position of pointer
480 return new GHOST_EventWheel (getSystem()->getMilliSeconds(), window, zDelta);
484 GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, bool keyDown, WPARAM wParam, LPARAM lParam)
486 GHOST_TKey key = ((GHOST_SystemWin32*)getSystem())->convertKey(wParam, lParam);
487 GHOST_EventKey* event;
488 if (key != GHOST_kKeyUnknown) {
492 /* Eat any character related messages */
493 if (::PeekMessage(&keyMsg, NULL, WM_CHAR, WM_SYSDEADCHAR, PM_REMOVE)) {
494 ascii = (char) keyMsg.wParam;
497 event = new GHOST_EventKey(getSystem()->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key, ascii);
506 GHOST_Event* GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type, GHOST_IWindow* window)
508 return new GHOST_Event(getSystem()->getMilliSeconds(), type, window);
512 LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
514 GHOST_Event* event = 0;
516 GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem());
517 GHOST_ASSERT(system, "GHOST_SystemWin32::s_wndProc(): system not initialized")
520 GHOST_WindowWin32* window = (GHOST_WindowWin32*)::GetWindowLong(hwnd, GWL_USERDATA);
523 ////////////////////////////////////////////////////////////////////////
524 // Keyboard events, processed
525 ////////////////////////////////////////////////////////////////////////
527 /* The WM_KEYDOWN message is posted to the window with the keyboard focus when a
528 * nonsystem key is pressed. A nonsystem key is a key that is pressed when the alt
529 * key is not pressed.
532 /* The WM_SYSKEYDOWN message is posted to the window with the keyboard focus when
533 * the user presses the F10 key (which activates the menu bar) or holds down the
534 * alt key and then presses another key. It also occurs when no window currently
535 * has the keyboard focus; in this case, the WM_SYSKEYDOWN message is sent to the
536 * active window. The window that receives the message can distinguish between these
537 * two contexts by checking the context code in the lKeyData parameter.
543 if (!system->m_seperateLeftRightInitialized) {
544 // Check whether this system supports seperate left and right keys
547 system->m_seperateLeftRight =
548 (HIBYTE(::GetKeyState(VK_LSHIFT)) != 0) ||
549 (HIBYTE(::GetKeyState(VK_RSHIFT)) != 0) ?
553 system->m_seperateLeftRight =
554 (HIBYTE(::GetKeyState(VK_LCONTROL)) != 0) ||
555 (HIBYTE(::GetKeyState(VK_RCONTROL)) != 0) ?
559 system->m_seperateLeftRight =
560 (HIBYTE(::GetKeyState(VK_LMENU)) != 0) ||
561 (HIBYTE(::GetKeyState(VK_RMENU)) != 0) ?
565 system->m_seperateLeftRightInitialized = true;
567 system->processModifierKeys(window);
568 // Bypass call to DefWindowProc
571 event = processKeyEvent(window, true, wParam, lParam);
573 GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
575 GHOST_PRINT(" key ignored\n")
587 system->processModifierKeys(window);
588 // Bypass call to DefWindowProc
591 event = processKeyEvent(window, false, wParam, lParam);
593 GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
595 GHOST_PRINT(" key ignored\n")
601 ////////////////////////////////////////////////////////////////////////
602 // Keyboard events, ignored
603 ////////////////////////////////////////////////////////////////////////
605 /* The WM_CHAR message is posted to the window with the keyboard focus when
606 * a WM_KEYDOWN message is translated by the TranslateMessage function. WM_CHAR
607 * contains the character code of the key that was pressed.
610 /* The WM_DEADCHAR message is posted to the window with the keyboard focus when a
611 * WM_KEYUP message is translated by the TranslateMessage function. WM_DEADCHAR
612 * specifies a character code generated by a dead key. A dead key is a key that
613 * generates a character, such as the umlaut (double-dot), that is combined with
614 * another character to form a composite character. For example, the umlaut-O
615 * character (Ù) is generated by typing the dead key for the umlaut character, and
616 * then typing the O key.
619 /* The WM_SYSDEADCHAR message is sent to the window with the keyboard focus when
620 * a WM_SYSKEYDOWN message is translated by the TranslateMessage function.
621 * WM_SYSDEADCHAR specifies the character code of a system dead key - that is,
622 * a dead key that is pressed while holding down the alt key.
626 ////////////////////////////////////////////////////////////////////////
627 // Mouse events, processed
628 ////////////////////////////////////////////////////////////////////////
630 window->registerMouseClickEvent(true);
631 event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft);
634 window->registerMouseClickEvent(true);
635 event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskMiddle);
638 window->registerMouseClickEvent(true);
639 event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight);
642 window->registerMouseClickEvent(false);
643 event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft);
646 window->registerMouseClickEvent(false);
647 event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskMiddle);
650 window->registerMouseClickEvent(false);
651 event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight);
654 event = processCursorEvent(GHOST_kEventCursorMove, window);
657 /* The WM_MOUSEWHEEL message is sent to the focus window
658 * when the mouse wheel is rotated. The DefWindowProc
659 * function propagates the message to the window's parent.
660 * There should be no internal forwarding of the message,
661 * since DefWindowProc propagates it up the parent chain
662 * until it finds a window that processes it.
664 event = processWheelEvent(window, wParam, lParam);
667 /* The WM_SETCURSOR message is sent to a window if the mouse causes the cursor
668 * to move within a window and mouse input is not captured.
669 * This means we have to set the cursor shape every time the mouse moves!
670 * The DefWindowProc function uses this message to set the cursor to an
671 * arrow if it is not in the client area.
673 if (LOWORD(lParam) == HTCLIENT) {
674 // Load the current cursor
675 window->loadCursor(window->getCursorVisibility(), window->getCursorShape());
676 // Bypass call to DefWindowProc
680 // Outside of client area show standard cursor
681 window->loadCursor(true, GHOST_kStandardCursorDefault);
685 ////////////////////////////////////////////////////////////////////////
686 // Mouse events, ignored
687 ////////////////////////////////////////////////////////////////////////
689 /* The WM_NCMOUSEMOVE message is posted to a window when the cursor is moved
690 * within the nonclient area of the window. This message is posted to the window
691 * that contains the cursor. If a window has captured the mouse, this message is not posted.
694 /* The WM_NCHITTEST message is sent to a window when the cursor moves, or
695 * when a mouse button is pressed or released. If the mouse is not captured,
696 * the message is sent to the window beneath the cursor. Otherwise, the message
697 * is sent to the window that has captured the mouse.
701 ////////////////////////////////////////////////////////////////////////
702 // Window events, processed
703 ////////////////////////////////////////////////////////////////////////
705 /* The WM_CLOSE message is sent as a signal that a window or an application should terminate. */
706 event = processWindowEvent(GHOST_kEventWindowClose, window);
709 /* The WM_ACTIVATE message is sent to both the window being activated and the window being
710 * deactivated. If the windows use the same input queue, the message is sent synchronously,
711 * first to the window procedure of the top-level window being deactivated, then to the window
712 * procedure of the top-level window being activated. If the windows use different input queues,
713 * the message is sent asynchronously, so the window is activated immediately.
715 event = processWindowEvent(LOWORD(wParam) ? GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate, window);
718 /* An application sends the WM_PAINT message when the system or another application
719 * makes a request to paint a portion of an application's window. The message is sent
720 * when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage
721 * function when the application obtains a WM_PAINT message by using the GetMessage or
722 * PeekMessage function.
724 event = processWindowEvent(GHOST_kEventWindowUpdate, window);
725 ::ValidateRect(hwnd, NULL);
728 /* The WM_SIZE message is sent to a window after its size has changed.
729 * The WM_SIZE and WM_MOVE messages are not sent if an application handles the
730 * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
731 * to perform any move or size change processing during the WM_WINDOWPOSCHANGED
732 * message without calling DefWindowProc.
734 event = processWindowEvent(GHOST_kEventWindowSize, window);
735 case WM_CAPTURECHANGED:
736 window->lostMouseCapture();
739 ////////////////////////////////////////////////////////////////////////
740 // Window events, ignored
741 ////////////////////////////////////////////////////////////////////////
742 case WM_WINDOWPOSCHANGED:
743 /* The WM_WINDOWPOSCHANGED message is sent to a window whose size, position, or place
744 * in the Z order has changed as a result of a call to the SetWindowPos function or
745 * another window-management function.
746 * The WM_SIZE and WM_MOVE messages are not sent if an application handles the
747 * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
748 * to perform any move or size change processing during the WM_WINDOWPOSCHANGED
749 * message without calling DefWindowProc.
752 /* The WM_SIZE and WM_MOVE messages are not sent if an application handles the
753 * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
754 * to perform any move or size change processing during the WM_WINDOWPOSCHANGED
755 * message without calling DefWindowProc.
758 /* An application sends the WM_ERASEBKGND message when the window background must be
759 * erased (for example, when a window is resized). The message is sent to prepare an
760 * invalidated portion of a window for painting.
763 /* An application sends the WM_NCPAINT message to a window when its frame must be painted. */
765 /* The WM_NCACTIVATE message is sent to a window when its nonclient area needs to be changed
766 * to indicate an active or inactive state.
769 /* The WM_DESTROY message is sent when a window is being destroyed. It is sent to the window
770 * procedure of the window being destroyed after the window is removed from the screen.
771 * This message is sent first to the window being destroyed and then to the child windows
772 * (if any) as they are destroyed. During the processing of the message, it can be assumed
773 * that all child windows still exist.
776 /* The WM_NCDESTROY message informs a window that its nonclient area is being destroyed. The
777 * DestroyWindow function sends the WM_NCDESTROY message to the window following the WM_DESTROY
778 * message. WM_DESTROY is used to free the allocated memory object associated with the window.
781 /* The WM_KILLFOCUS message is sent to a window immediately before it loses the keyboard focus. */
783 /* The WM_SHOWWINDOW message is sent to a window when the window is about to be hidden or shown. */
784 case WM_WINDOWPOSCHANGING:
785 /* The WM_WINDOWPOSCHANGING message is sent to a window whose size, position, or place in
786 * the Z order is about to change as a result of a call to the SetWindowPos function or
787 * another window-management function.
790 /* The WM_SETFOCUS message is sent to a window after it has gained the keyboard focus. */
792 /* The WM_MOVING message is sent to a window that the user is moving. By processing
793 * this message, an application can monitor the size and position of the drag rectangle
794 * and, if needed, change its size or position.
796 case WM_ENTERSIZEMOVE:
797 /* The WM_ENTERSIZEMOVE message is sent one time to a window after it enters the moving
798 * or sizing modal loop. The window enters the moving or sizing modal loop when the user
799 * clicks the window's title bar or sizing border, or when the window passes the
800 * WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the
801 * message specifies the SC_MOVE or SC_SIZE value. The operation is complete when
802 * DefWindowProc returns.
806 ////////////////////////////////////////////////////////////////////////
808 ////////////////////////////////////////////////////////////////////////
810 /* An application sends a WM_GETTEXT message to copy the text that
811 * corresponds to a window into a buffer provided by the caller.
814 /* The WM_ACTIVATEAPP message is sent when a window belonging to a
815 * different application than the active window is about to be activated.
816 * The message is sent to the application whose window is being activated
817 * and to the application whose window is being deactivated.
820 /* The WIN32 docs say:
821 * The WM_TIMER message is posted to the installing thread's message queue
822 * when a timer expires. You can process the message by providing a WM_TIMER
823 * case in the window procedure. Otherwise, the default window procedure will
824 * call the TimerProc callback function specified in the call to the SetTimer
825 * function used to install the timer.
827 * In GHOST, we let DefWindowProc call the timer callback.
833 // Event found for a window before the pointer to the class has been set.
834 GHOST_PRINT("GHOST_SystemWin32::wndProc: GHOST window event before creation\n")
835 /* These are events we typically miss at this point:
836 WM_GETMINMAXINFO 0x24
840 We let DefWindowProc do the work.
845 // Events without valid hwnd
846 GHOST_PRINT("GHOST_SystemWin32::wndProc: event without window\n")
850 system->pushEvent(event);
854 lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);