Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/ghost/intern/GHOST_SystemWin32.cpp')
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp817
1 files changed, 817 insertions, 0 deletions
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
new file mode 100644
index 00000000000..6dc00bd1847
--- /dev/null
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -0,0 +1,817 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/**
+
+ * $Id$
+ * Copyright (C) 2001 NaN Technologies B.V.
+ * @author Maarten Gribnau
+ * @date May 7, 2001
+ */
+
+#include "GHOST_SystemWin32.h"
+
+
+#include "GHOST_Debug.h"
+#include "GHOST_DisplayManagerWin32.h"
+#include "GHOST_EventButton.h"
+#include "GHOST_EventCursor.h"
+#include "GHOST_EventKey.h"
+#include "GHOST_TimerTask.h"
+#include "GHOST_TimerManager.h"
+#include "GHOST_WindowManager.h"
+#include "GHOST_WindowWin32.h"
+
+// Key code values not found in winuser.h
+#ifndef VK_MINUS
+#define VK_MINUS 0xBD
+#endif // VK_MINUS
+#ifndef VK_SEMICOLON
+#define VK_SEMICOLON 0xBA
+#endif // VK_SEMICOLON
+#ifndef VK_PERIOD
+#define VK_PERIOD 0xBE
+#endif // VK_PERIOD
+#ifndef VK_COMMA
+#define VK_COMMA 0xBC
+#endif // VK_COMMA
+#ifndef VK_QUOTE
+#define VK_QUOTE 0xDE
+#endif // VK_QUOTE
+#ifndef VK_BACK_QUOTE
+#define VK_BACK_QUOTE 0xC0
+#endif // VK_BACK_QUOTE
+#ifndef VK_SLASH
+#define VK_SLASH 0xBF
+#endif // VK_SLASH
+#ifndef VK_BACK_SLASH
+#define VK_BACK_SLASH 0xDC
+#endif // VK_BACK_SLASH
+#ifndef VK_EQUALS
+#define VK_EQUALS 0xBB
+#endif // VK_EQUALS
+#ifndef VK_OPEN_BRACKET
+#define VK_OPEN_BRACKET 0xDB
+#endif // VK_OPEN_BRACKET
+#ifndef VK_CLOSE_BRACKET
+#define VK_CLOSE_BRACKET 0xDD
+#endif // VK_CLOSE_BRACKET
+
+
+GHOST_SystemWin32::GHOST_SystemWin32()
+: m_hasPerformanceCounter(false), m_freq(0), m_start(0),
+ m_seperateLeftRight(false),
+ m_seperateLeftRightInitialized(false)
+{
+ m_displayManager = new GHOST_DisplayManagerWin32 ();
+ GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::GHOST_SystemWin32(): m_displayManager==0\n");
+ m_displayManager->initialize();
+}
+
+GHOST_SystemWin32::~GHOST_SystemWin32()
+{
+}
+
+
+GHOST_TUns64 GHOST_SystemWin32::getMilliSeconds() const
+{
+ // Hardware does not support high resolution timers. We will use GetTickCount instead then.
+ if (!m_hasPerformanceCounter) {
+ return ::GetTickCount();
+ }
+
+ // Retrieve current count
+ __int64 count = 0;
+ ::QueryPerformanceCounter((LARGE_INTEGER*)&count);
+
+ // Calculate the time passed since system initialization.
+ __int64 delta = 1000*(count-m_start);
+
+ GHOST_TUns64 t = (GHOST_TUns64)(delta/m_freq);
+ return t;
+}
+
+
+GHOST_TUns8 GHOST_SystemWin32::getNumDisplays() const
+{
+ GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::getNumDisplays(): m_displayManager==0\n");
+ GHOST_TUns8 numDisplays;
+ m_displayManager->getNumDisplays(numDisplays);
+ return numDisplays;
+}
+
+
+void GHOST_SystemWin32::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const
+{
+ width = ::GetSystemMetrics(SM_CXSCREEN);
+ height= ::GetSystemMetrics(SM_CYSCREEN);
+}
+
+
+GHOST_IWindow* GHOST_SystemWin32::createWindow(
+ const STR_String& title,
+ GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height,
+ GHOST_TWindowState state, GHOST_TDrawingContextType type,
+ bool stereoVisual)
+{
+ GHOST_Window* window = 0;
+ window = new GHOST_WindowWin32 (title, left, top, width, height, state, type, stereoVisual);
+ if (window) {
+ if (window->getValid()) {
+ // Store the pointer to the window
+ if (state != GHOST_kWindowStateFullScreen) {
+ m_windowManager->addWindow(window);
+ }
+ }
+ else {
+ delete window;
+ window = 0;
+ }
+ }
+ return window;
+}
+
+
+bool GHOST_SystemWin32::processEvents(bool waitForEvent)
+{
+ MSG msg;
+ bool anyProcessed = false;
+
+ do {
+ GHOST_TimerManager* timerMgr = getTimerManager();
+
+ if (waitForEvent && !::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE)) {
+#if 1
+ ::Sleep(1);
+#else
+ GHOST_TUns64 next = timerMgr->nextFireTime();
+
+ if (next == GHOST_kFireTimeNever) {
+ ::WaitMessage();
+ } else {
+ ::SetTimer(NULL, 0, next - getMilliSeconds(), NULL);
+ ::WaitMessage();
+ ::KillTimer(NULL, 0);
+ }
+#endif
+ }
+
+ if (timerMgr->fireTimers(getMilliSeconds())) {
+ anyProcessed = true;
+ }
+
+ // Process all the events waiting for us
+ while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE) != 0) {
+ ::TranslateMessage(&msg);
+ ::DispatchMessage(&msg);
+ anyProcessed = true;
+ }
+ } while (waitForEvent && !anyProcessed);
+
+ return anyProcessed;
+}
+
+
+GHOST_TSuccess GHOST_SystemWin32::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const
+{
+ POINT point;
+ bool success = ::GetCursorPos(&point) == TRUE;
+ x = point.x;
+ y = point.y;
+ return GHOST_kSuccess;
+}
+
+
+GHOST_TSuccess GHOST_SystemWin32::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) const
+{
+ return ::SetCursorPos(x, y) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
+}
+
+
+GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys& keys) const
+{
+ /*
+ GetKeyState and GetAsyncKeyState only work with Win95, Win98, NT4,
+ Terminal Server and Windows 2000.
+ But on WinME it always returns zero. These two functions are simply
+ skipped by Millenium Edition!
+
+ Official explanation from Microsoft:
+ Intentionally disabled.
+ It didn't work all that well on some newer hardware, and worked less
+ well with the passage of time, so it was fully disabled in ME.
+ */
+ if (m_seperateLeftRight && m_seperateLeftRightInitialized) {
+ bool down = HIBYTE(::GetKeyState(VK_LSHIFT)) != 0;
+ keys.set(GHOST_kModifierKeyLeftShift, down);
+ down = HIBYTE(::GetKeyState(VK_RSHIFT)) != 0;
+ keys.set(GHOST_kModifierKeyRightShift, down);
+ down = HIBYTE(::GetKeyState(VK_LMENU)) != 0;
+ keys.set(GHOST_kModifierKeyLeftAlt, down);
+ down = HIBYTE(::GetKeyState(VK_RMENU)) != 0;
+ keys.set(GHOST_kModifierKeyRightAlt, down);
+ down = HIBYTE(::GetKeyState(VK_LCONTROL)) != 0;
+ keys.set(GHOST_kModifierKeyLeftControl, down);
+ down = HIBYTE(::GetKeyState(VK_RCONTROL)) != 0;
+ keys.set(GHOST_kModifierKeyRightControl, down);
+ }
+ else {
+ bool down = HIBYTE(::GetKeyState(VK_SHIFT)) != 0;
+ keys.set(GHOST_kModifierKeyLeftShift, down);
+ keys.set(GHOST_kModifierKeyRightShift, down);
+ down = HIBYTE(::GetKeyState(VK_MENU)) != 0;
+ keys.set(GHOST_kModifierKeyLeftAlt, down);
+ keys.set(GHOST_kModifierKeyRightAlt, down);
+ down = HIBYTE(::GetKeyState(VK_CONTROL)) != 0;
+ keys.set(GHOST_kModifierKeyLeftControl, down);
+ keys.set(GHOST_kModifierKeyRightControl, down);
+ }
+ return GHOST_kSuccess;
+}
+
+
+GHOST_TSuccess GHOST_SystemWin32::getButtons(GHOST_Buttons& buttons) const
+{
+ /* Check for swapped buttons (left-handed mouse buttons)
+ * GetAsyncKeyState() will give back the state of the physical mouse buttons.
+ */
+ bool swapped = ::GetSystemMetrics(SM_SWAPBUTTON) == TRUE;
+
+ bool down = HIBYTE(::GetKeyState(VK_LBUTTON)) != 0;
+ buttons.set(swapped ? GHOST_kButtonMaskRight : GHOST_kButtonMaskLeft, down);
+
+ down = HIBYTE(::GetKeyState(VK_MBUTTON)) != 0;
+ buttons.set(GHOST_kButtonMaskMiddle, down);
+
+ down = HIBYTE(::GetKeyState(VK_RBUTTON)) != 0;
+ buttons.set(swapped ? GHOST_kButtonMaskLeft : GHOST_kButtonMaskRight, down);
+ return GHOST_kSuccess;
+}
+
+
+GHOST_TSuccess GHOST_SystemWin32::init()
+{
+ GHOST_TSuccess success = GHOST_System::init();
+
+ // Determine whether this system has a high frequency performance counter. */
+ m_hasPerformanceCounter = ::QueryPerformanceFrequency((LARGE_INTEGER*)&m_freq) == TRUE;
+ if (m_hasPerformanceCounter) {
+ GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer available\n")
+ ::QueryPerformanceCounter((LARGE_INTEGER*)&m_start);
+ }
+ else {
+ GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer not available\n")
+ }
+
+ if (success) {
+ WNDCLASS wc;
+ wc.style= CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc= s_wndProc;
+ wc.cbClsExtra= 0;
+ wc.cbWndExtra= 0;
+ wc.hInstance= ::GetModuleHandle(0);
+ wc.hIcon = ::LoadIcon(wc.hInstance, "APPICON");
+ if (!wc.hIcon) {
+ ::LoadIcon(NULL, IDI_APPLICATION);
+ }
+ wc.hCursor = ::LoadCursor(0, IDC_ARROW);
+ wc.hbrBackground= (HBRUSH)::GetStockObject(BLACK_BRUSH);
+ wc.lpszMenuName = 0;
+ wc.lpszClassName= GHOST_WindowWin32::getWindowClassName();
+
+ // Use RegisterClassEx for setting small icon
+ if (::RegisterClass(&wc) == 0) {
+ success = GHOST_kFailure;
+ }
+ }
+ return success;
+}
+
+
+GHOST_TSuccess GHOST_SystemWin32::exit()
+{
+ return GHOST_System::exit();
+}
+
+
+GHOST_TKey GHOST_SystemWin32::convertKey(WPARAM wParam, LPARAM lParam) const
+{
+ GHOST_TKey key;
+ bool isExtended = (lParam&(1<<24))?true:false;
+
+ if ((wParam >= '0') && (wParam <= '9')) {
+ // VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39)
+ key = (GHOST_TKey)(wParam - '0' + GHOST_kKey0);
+ }
+ else if ((wParam >= 'A') && (wParam <= 'Z')) {
+ // VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A)
+ key = (GHOST_TKey)(wParam - 'A' + GHOST_kKeyA);
+ }
+ else if ((wParam >= VK_F1) && (wParam <= VK_F24)) {
+ key = (GHOST_TKey)(wParam - VK_F1 + GHOST_kKeyF1);
+ }
+ else {
+ switch (wParam) {
+ case VK_RETURN:
+ key = isExtended?GHOST_kKeyNumpadEnter:GHOST_kKeyEnter;
+ break;
+
+ case VK_BACK: key = GHOST_kKeyBackSpace; break;
+ case VK_TAB: key = GHOST_kKeyTab; break;
+ case VK_ESCAPE: key = GHOST_kKeyEsc; break;
+ case VK_SPACE: key = GHOST_kKeySpace; break;
+ case VK_PRIOR: key = GHOST_kKeyUpPage; break;
+ case VK_NEXT: key = GHOST_kKeyDownPage; break;
+ case VK_END: key = GHOST_kKeyEnd; break;
+ case VK_HOME: key = GHOST_kKeyHome; break;
+ case VK_INSERT: key = GHOST_kKeyInsert; break;
+ case VK_DELETE: key = GHOST_kKeyDelete; break;
+ case VK_LEFT: key = GHOST_kKeyLeftArrow; break;
+ case VK_RIGHT: key = GHOST_kKeyRightArrow; break;
+ case VK_UP: key = GHOST_kKeyUpArrow; break;
+ case VK_DOWN: key = GHOST_kKeyDownArrow; break;
+ case VK_NUMPAD0: key = GHOST_kKeyNumpad0; break;
+ case VK_NUMPAD1: key = GHOST_kKeyNumpad1; break;
+ case VK_NUMPAD2: key = GHOST_kKeyNumpad2; break;
+ case VK_NUMPAD3: key = GHOST_kKeyNumpad3; break;
+ case VK_NUMPAD4: key = GHOST_kKeyNumpad4; break;
+ case VK_NUMPAD5: key = GHOST_kKeyNumpad5; break;
+ case VK_NUMPAD6: key = GHOST_kKeyNumpad6; break;
+ case VK_NUMPAD7: key = GHOST_kKeyNumpad7; break;
+ case VK_NUMPAD8: key = GHOST_kKeyNumpad8; break;
+ case VK_NUMPAD9: key = GHOST_kKeyNumpad9; break;
+ case VK_SNAPSHOT: key = GHOST_kKeyPrintScreen; break;
+ case VK_PAUSE: key = GHOST_kKeyPause; break;
+ case VK_MULTIPLY: key = GHOST_kKeyNumpadAsterisk; break;
+ case VK_SUBTRACT: key = GHOST_kKeyNumpadMinus; break;
+ case VK_DECIMAL: key = GHOST_kKeyNumpadPeriod; break;
+ case VK_DIVIDE: key = GHOST_kKeyNumpadSlash; break;
+ case VK_ADD: key = GHOST_kKeyNumpadPlus; break;
+
+ case VK_SEMICOLON: key = GHOST_kKeySemicolon; break;
+ case VK_EQUALS: key = GHOST_kKeyEqual; break;
+ case VK_COMMA: key = GHOST_kKeyComma; break;
+ case VK_MINUS: key = GHOST_kKeyMinus; break;
+ case VK_PERIOD: key = GHOST_kKeyPeriod; break;
+ case VK_SLASH: key = GHOST_kKeySlash; break;
+ case VK_BACK_QUOTE: key = GHOST_kKeyAccentGrave; break;
+ case VK_OPEN_BRACKET: key = GHOST_kKeyLeftBracket; break;
+ case VK_BACK_SLASH: key = GHOST_kKeyBackslash; break;
+ case VK_CLOSE_BRACKET: key = GHOST_kKeyRightBracket; break;
+ case VK_QUOTE: key = GHOST_kKeyQuote; break;
+
+ // Process these keys separately because we need to distinguish right from left modifier keys
+ case VK_SHIFT:
+ case VK_CONTROL:
+ case VK_MENU:
+
+ // Ignore these keys
+ case VK_NUMLOCK:
+ case VK_SCROLL:
+ case VK_CAPITAL:
+ default:
+ key = GHOST_kKeyUnknown;
+ break;
+ }
+ }
+ return key;
+}
+
+
+void GHOST_SystemWin32::processModifierKeys(GHOST_IWindow *window)
+{
+ GHOST_ModifierKeys oldModifiers, newModifiers;
+ // Retrieve old state of the modifier keys
+ ((GHOST_SystemWin32*)getSystem())->retrieveModifierKeys(oldModifiers);
+ // Retrieve current state of the modifier keys
+ ((GHOST_SystemWin32*)getSystem())->getModifierKeys(newModifiers);
+
+ // Compare the old and the new
+ if (!newModifiers.equals(oldModifiers)) {
+ // Create events for the masks that changed
+ for (int i = 0; i < GHOST_kModifierKeyNumMasks; i++) {
+ if (newModifiers.get((GHOST_TModifierKeyMask)i) != oldModifiers.get((GHOST_TModifierKeyMask)i)) {
+ // Convert the mask to a key code
+ GHOST_TKey key = GHOST_ModifierKeys::getModifierKeyCode((GHOST_TModifierKeyMask)i);
+ bool keyDown = newModifiers.get((GHOST_TModifierKeyMask)i);
+ GHOST_EventKey* event;
+ if (key != GHOST_kKeyUnknown) {
+ // Create an event
+ event = new GHOST_EventKey(getSystem()->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key);
+ pushEvent(event);
+ }
+ }
+ }
+ }
+
+ // Store new modifier keys state
+ ((GHOST_SystemWin32*)getSystem())->storeModifierKeys(newModifiers);
+}
+
+
+GHOST_EventButton* GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, GHOST_IWindow *window, GHOST_TButtonMask mask)
+{
+ return new GHOST_EventButton (getSystem()->getMilliSeconds(), type, window, mask);
+}
+
+
+GHOST_EventCursor* GHOST_SystemWin32::processCursorEvent(GHOST_TEventType type, GHOST_IWindow *window)
+{
+ GHOST_TInt32 x, y;
+ getSystem()->getCursorPosition(x, y);
+ return new GHOST_EventCursor (getSystem()->getMilliSeconds(), type, window, x, y);
+}
+
+
+GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, bool keyDown, WPARAM wParam, LPARAM lParam)
+{
+ GHOST_TKey key = ((GHOST_SystemWin32*)getSystem())->convertKey(wParam, lParam);
+ GHOST_EventKey* event;
+ if (key != GHOST_kKeyUnknown) {
+ MSG keyMsg;
+ char ascii = '\0';
+
+ /* Eat any character related messages */
+ if (::PeekMessage(&keyMsg, NULL, WM_CHAR, WM_SYSDEADCHAR, PM_REMOVE)) {
+ ascii = (char) keyMsg.wParam;
+ }
+
+ event = new GHOST_EventKey(getSystem()->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key, ascii);
+ }
+ else {
+ event = 0;
+ }
+ return event;
+}
+
+
+GHOST_Event* GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type, GHOST_IWindow* window)
+{
+ return new GHOST_Event(getSystem()->getMilliSeconds(), type, window);
+}
+
+
+LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ GHOST_Event* event = 0;
+ LRESULT lResult;
+ GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem());
+ GHOST_ASSERT(system, "GHOST_SystemWin32::s_wndProc(): system not initialized")
+
+ if (hwnd) {
+ GHOST_WindowWin32* window = (GHOST_WindowWin32*)::GetWindowLong(hwnd, GWL_USERDATA);
+ if (window) {
+ switch (msg) {
+ ////////////////////////////////////////////////////////////////////////
+ // Keyboard events, processed
+ ////////////////////////////////////////////////////////////////////////
+ case WM_KEYDOWN:
+ /* The WM_KEYDOWN message is posted to the window with the keyboard focus when a
+ * nonsystem key is pressed. A nonsystem key is a key that is pressed when the alt
+ * key is not pressed.
+ */
+ case WM_SYSKEYDOWN:
+ /* The WM_SYSKEYDOWN message is posted to the window with the keyboard focus when
+ * the user presses the F10 key (which activates the menu bar) or holds down the
+ * alt key and then presses another key. It also occurs when no window currently
+ * has the keyboard focus; in this case, the WM_SYSKEYDOWN message is sent to the
+ * active window. The window that receives the message can distinguish between these
+ * two contexts by checking the context code in the lKeyData parameter.
+ */
+ switch (wParam) {
+ case VK_SHIFT:
+ case VK_CONTROL:
+ case VK_MENU:
+ if (!system->m_seperateLeftRightInitialized) {
+ // Check whether this system supports seperate left and right keys
+ switch (wParam) {
+ case VK_SHIFT:
+ system->m_seperateLeftRight =
+ (HIBYTE(::GetKeyState(VK_LSHIFT)) != 0) ||
+ (HIBYTE(::GetKeyState(VK_RSHIFT)) != 0) ?
+ true : false;
+ break;
+ case VK_CONTROL:
+ system->m_seperateLeftRight =
+ (HIBYTE(::GetKeyState(VK_LCONTROL)) != 0) ||
+ (HIBYTE(::GetKeyState(VK_RCONTROL)) != 0) ?
+ true : false;
+ break;
+ case VK_MENU:
+ system->m_seperateLeftRight =
+ (HIBYTE(::GetKeyState(VK_LMENU)) != 0) ||
+ (HIBYTE(::GetKeyState(VK_RMENU)) != 0) ?
+ true : false;
+ break;
+ }
+ system->m_seperateLeftRightInitialized = true;
+ }
+ system->processModifierKeys(window);
+ // Bypass call to DefWindowProc
+ return 0;
+ default:
+ event = processKeyEvent(window, true, wParam, lParam);
+ if (!event) {
+ GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
+ GHOST_PRINT(msg)
+ GHOST_PRINT(" key ignored\n")
+ }
+ break;
+ }
+ break;
+
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ switch (wParam) {
+ case VK_SHIFT:
+ case VK_CONTROL:
+ case VK_MENU:
+ system->processModifierKeys(window);
+ // Bypass call to DefWindowProc
+ return 0;
+ default:
+ event = processKeyEvent(window, false, wParam, lParam);
+ if (!event) {
+ GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
+ GHOST_PRINT(msg)
+ GHOST_PRINT(" key ignored\n")
+ }
+ break;
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////
+ // Keyboard events, ignored
+ ////////////////////////////////////////////////////////////////////////
+ case WM_CHAR:
+ /* The WM_CHAR message is posted to the window with the keyboard focus when
+ * a WM_KEYDOWN message is translated by the TranslateMessage function. WM_CHAR
+ * contains the character code of the key that was pressed.
+ */
+ case WM_DEADCHAR:
+ /* The WM_DEADCHAR message is posted to the window with the keyboard focus when a
+ * WM_KEYUP message is translated by the TranslateMessage function. WM_DEADCHAR
+ * specifies a character code generated by a dead key. A dead key is a key that
+ * generates a character, such as the umlaut (double-dot), that is combined with
+ * another character to form a composite character. For example, the umlaut-O
+ * character (Ö) is generated by typing the dead key for the umlaut character, and
+ * then typing the O key.
+ */
+ case WM_SYSDEADCHAR:
+ /* The WM_SYSDEADCHAR message is sent to the window with the keyboard focus when
+ * a WM_SYSKEYDOWN message is translated by the TranslateMessage function.
+ * WM_SYSDEADCHAR specifies the character code of a system dead key - that is,
+ * a dead key that is pressed while holding down the alt key.
+ */
+ break;
+
+ ////////////////////////////////////////////////////////////////////////
+ // Mouse events, processed
+ ////////////////////////////////////////////////////////////////////////
+ case WM_LBUTTONDOWN:
+ window->registerMouseClickEvent(true);
+ event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft);
+ break;
+ case WM_MBUTTONDOWN:
+ window->registerMouseClickEvent(true);
+ event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskMiddle);
+ break;
+ case WM_RBUTTONDOWN:
+ window->registerMouseClickEvent(true);
+ event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight);
+ break;
+ case WM_LBUTTONUP:
+ window->registerMouseClickEvent(false);
+ event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft);
+ break;
+ case WM_MBUTTONUP:
+ window->registerMouseClickEvent(false);
+ event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskMiddle);
+ break;
+ case WM_RBUTTONUP:
+ window->registerMouseClickEvent(false);
+ event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight);
+ break;
+ case WM_MOUSEMOVE:
+ event = processCursorEvent(GHOST_kEventCursorMove, window);
+ break;
+ case WM_SETCURSOR:
+ /* The WM_SETCURSOR message is sent to a window if the mouse causes the cursor
+ * to move within a window and mouse input is not captured.
+ * This means we have to set the cursor shape every time the mouse moves!
+ * The DefWindowProc function uses this message to set the cursor to an
+ * arrow if it is not in the client area.
+ */
+ if (LOWORD(lParam) == HTCLIENT) {
+ // Load the current cursor
+ window->loadCursor(window->getCursorVisibility(), window->getCursorShape());
+ // Bypass call to DefWindowProc
+ return 0;
+ }
+ else {
+ // Outside of client area show standard cursor
+ window->loadCursor(true, GHOST_kStandardCursorDefault);
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////
+ // Mouse events, ignored
+ ////////////////////////////////////////////////////////////////////////
+ case WM_NCMOUSEMOVE:
+ /* The WM_NCMOUSEMOVE message is posted to a window when the cursor is moved
+ * within the nonclient area of the window. This message is posted to the window
+ * that contains the cursor. If a window has captured the mouse, this message is not posted.
+ */
+ case WM_NCHITTEST:
+ /* The WM_NCHITTEST message is sent to a window when the cursor moves, or
+ * when a mouse button is pressed or released. If the mouse is not captured,
+ * the message is sent to the window beneath the cursor. Otherwise, the message
+ * is sent to the window that has captured the mouse.
+ */
+ break;
+
+ ////////////////////////////////////////////////////////////////////////
+ // Window events, processed
+ ////////////////////////////////////////////////////////////////////////
+ case WM_CLOSE:
+ /* The WM_CLOSE message is sent as a signal that a window or an application should terminate. */
+ event = processWindowEvent(GHOST_kEventWindowClose, window);
+ break;
+ case WM_ACTIVATE:
+ /* The WM_ACTIVATE message is sent to both the window being activated and the window being
+ * deactivated. If the windows use the same input queue, the message is sent synchronously,
+ * first to the window procedure of the top-level window being deactivated, then to the window
+ * procedure of the top-level window being activated. If the windows use different input queues,
+ * the message is sent asynchronously, so the window is activated immediately.
+ */
+ event = processWindowEvent(LOWORD(wParam) ? GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate, window);
+ break;
+ case WM_PAINT:
+ /* An application sends the WM_PAINT message when the system or another application
+ * makes a request to paint a portion of an application's window. The message is sent
+ * when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage
+ * function when the application obtains a WM_PAINT message by using the GetMessage or
+ * PeekMessage function.
+ */
+ event = processWindowEvent(GHOST_kEventWindowUpdate, window);
+ ::ValidateRect(hwnd, NULL);
+ break;
+ case WM_SIZE:
+ /* The WM_SIZE message is sent to a window after its size has changed.
+ * The WM_SIZE and WM_MOVE messages are not sent if an application handles the
+ * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
+ * to perform any move or size change processing during the WM_WINDOWPOSCHANGED
+ * message without calling DefWindowProc.
+ */
+ event = processWindowEvent(GHOST_kEventWindowSize, window);
+ case WM_CAPTURECHANGED:
+ window->lostMouseCapture();
+ break;
+
+ ////////////////////////////////////////////////////////////////////////
+ // Window events, ignored
+ ////////////////////////////////////////////////////////////////////////
+ case WM_WINDOWPOSCHANGED:
+ /* The WM_WINDOWPOSCHANGED message is sent to a window whose size, position, or place
+ * in the Z order has changed as a result of a call to the SetWindowPos function or
+ * another window-management function.
+ * The WM_SIZE and WM_MOVE messages are not sent if an application handles the
+ * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
+ * to perform any move or size change processing during the WM_WINDOWPOSCHANGED
+ * message without calling DefWindowProc.
+ */
+ case WM_MOVE:
+ /* The WM_SIZE and WM_MOVE messages are not sent if an application handles the
+ * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
+ * to perform any move or size change processing during the WM_WINDOWPOSCHANGED
+ * message without calling DefWindowProc.
+ */
+ case WM_ERASEBKGND:
+ /* An application sends the WM_ERASEBKGND message when the window background must be
+ * erased (for example, when a window is resized). The message is sent to prepare an
+ * invalidated portion of a window for painting.
+ */
+ case WM_NCPAINT:
+ /* An application sends the WM_NCPAINT message to a window when its frame must be painted. */
+ case WM_NCACTIVATE:
+ /* The WM_NCACTIVATE message is sent to a window when its nonclient area needs to be changed
+ * to indicate an active or inactive state.
+ */
+ case WM_DESTROY:
+ /* The WM_DESTROY message is sent when a window is being destroyed. It is sent to the window
+ * procedure of the window being destroyed after the window is removed from the screen.
+ * This message is sent first to the window being destroyed and then to the child windows
+ * (if any) as they are destroyed. During the processing of the message, it can be assumed
+ * that all child windows still exist.
+ */
+ case WM_NCDESTROY:
+ /* The WM_NCDESTROY message informs a window that its nonclient area is being destroyed. The
+ * DestroyWindow function sends the WM_NCDESTROY message to the window following the WM_DESTROY
+ * message. WM_DESTROY is used to free the allocated memory object associated with the window.
+ */
+ case WM_KILLFOCUS:
+ /* The WM_KILLFOCUS message is sent to a window immediately before it loses the keyboard focus. */
+ case WM_SHOWWINDOW:
+ /* The WM_SHOWWINDOW message is sent to a window when the window is about to be hidden or shown. */
+ case WM_WINDOWPOSCHANGING:
+ /* The WM_WINDOWPOSCHANGING message is sent to a window whose size, position, or place in
+ * the Z order is about to change as a result of a call to the SetWindowPos function or
+ * another window-management function.
+ */
+ case WM_SETFOCUS:
+ /* The WM_SETFOCUS message is sent to a window after it has gained the keyboard focus. */
+ case WM_MOVING:
+ /* The WM_MOVING message is sent to a window that the user is moving. By processing
+ * this message, an application can monitor the size and position of the drag rectangle
+ * and, if needed, change its size or position.
+ */
+ case WM_ENTERSIZEMOVE:
+ /* The WM_ENTERSIZEMOVE message is sent one time to a window after it enters the moving
+ * or sizing modal loop. The window enters the moving or sizing modal loop when the user
+ * clicks the window's title bar or sizing border, or when the window passes the
+ * WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the
+ * message specifies the SC_MOVE or SC_SIZE value. The operation is complete when
+ * DefWindowProc returns.
+ */
+ break;
+
+ ////////////////////////////////////////////////////////////////////////
+ // Other events
+ ////////////////////////////////////////////////////////////////////////
+ case WM_GETTEXT:
+ /* An application sends a WM_GETTEXT message to copy the text that
+ * corresponds to a window into a buffer provided by the caller.
+ */
+ case WM_ACTIVATEAPP:
+ /* The WM_ACTIVATEAPP message is sent when a window belonging to a
+ * different application than the active window is about to be activated.
+ * The message is sent to the application whose window is being activated
+ * and to the application whose window is being deactivated.
+ */
+ case WM_TIMER:
+ /* The WIN32 docs say:
+ * The WM_TIMER message is posted to the installing thread's message queue
+ * when a timer expires. You can process the message by providing a WM_TIMER
+ * case in the window procedure. Otherwise, the default window procedure will
+ * call the TimerProc callback function specified in the call to the SetTimer
+ * function used to install the timer.
+ *
+ * In GHOST, we let DefWindowProc call the timer callback.
+ */
+ break;
+ }
+ }
+ else {
+ // Event found for a window before the pointer to the class has been set.
+ GHOST_PRINT("GHOST_SystemWin32::wndProc: GHOST window event before creation\n")
+ /* These are events we typically miss at this point:
+ WM_GETMINMAXINFO 0x24
+ WM_NCCREATE 0x81
+ WM_NCCALCSIZE 0x83
+ WM_CREATE 0x01
+ We let DefWindowProc do the work.
+ */
+ }
+ }
+ else {
+ // Events without valid hwnd
+ GHOST_PRINT("GHOST_SystemWin32::wndProc: event without window\n")
+ }
+
+ if (event) {
+ system->pushEvent(event);
+ lResult = 0;
+ }
+ else {
+ lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+ return lResult;
+}