commiting fixes from Ettore for building on linux & win 32
[blender.git] / intern / ghost / intern / GHOST_SystemWin32.cpp
1 /**
2  * $Id$
3  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
4  *
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
11  * about this.
12  *
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.
17  *
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.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL/BL DUAL LICENSE BLOCK *****
30  */
31
32 /**
33
34  * $Id$
35  * Copyright (C) 2001 NaN Technologies B.V.
36  * @author      Maarten Gribnau
37  * @date        May 7, 2001
38  */
39
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif
43
44 #pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning
45
46 #include "GHOST_SystemWin32.h"
47
48 /*
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.
52  */
53 #ifndef WM_MOUSEWHEEL
54 #define WM_MOUSEWHEEL 0x020A
55 #endif // WM_MOUSEWHEEL
56 #ifndef WHEEL_DELTA
57 #define WHEEL_DELTA 120 /* Value for rolling one detent */
58 #endif // WHEEL_DELTA
59
60
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_EventNDOF.h"
68 #include "GHOST_TimerTask.h"
69 #include "GHOST_TimerManager.h"
70 #include "GHOST_WindowManager.h"
71 #include "GHOST_WindowWin32.h"
72 #include "GHOST_NDOFManager.h"
73
74 // Key code values not found in winuser.h
75 #ifndef VK_MINUS
76 #define VK_MINUS 0xBD
77 #endif // VK_MINUS
78 #ifndef VK_SEMICOLON
79 #define VK_SEMICOLON 0xBA
80 #endif // VK_SEMICOLON
81 #ifndef VK_PERIOD
82 #define VK_PERIOD 0xBE
83 #endif // VK_PERIOD
84 #ifndef VK_COMMA
85 #define VK_COMMA 0xBC
86 #endif // VK_COMMA
87 #ifndef VK_QUOTE
88 #define VK_QUOTE 0xDE
89 #endif // VK_QUOTE
90 #ifndef VK_BACK_QUOTE
91 #define VK_BACK_QUOTE 0xC0
92 #endif // VK_BACK_QUOTE
93 #ifndef VK_SLASH
94 #define VK_SLASH 0xBF
95 #endif // VK_SLASH
96 #ifndef VK_BACK_SLASH
97 #define VK_BACK_SLASH 0xDC
98 #endif // VK_BACK_SLASH
99 #ifndef VK_EQUALS
100 #define VK_EQUALS 0xBB
101 #endif // VK_EQUALS
102 #ifndef VK_OPEN_BRACKET
103 #define VK_OPEN_BRACKET 0xDB
104 #endif // VK_OPEN_BRACKET
105 #ifndef VK_CLOSE_BRACKET
106 #define VK_CLOSE_BRACKET 0xDD
107 #endif // VK_CLOSE_BRACKET
108 #ifndef VK_GR_LESS
109 #define VK_GR_LESS 0xE2
110 #endif // VK_GR_LESS
111
112
113 GHOST_SystemWin32::GHOST_SystemWin32()
114 : m_hasPerformanceCounter(false), m_freq(0), m_start(0),
115   m_seperateLeftRight(false),
116   m_seperateLeftRightInitialized(false)
117 {
118         m_displayManager = new GHOST_DisplayManagerWin32 ();
119         GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::GHOST_SystemWin32(): m_displayManager==0\n");
120         m_displayManager->initialize();
121 }
122
123 GHOST_SystemWin32::~GHOST_SystemWin32()
124 {
125 }
126
127
128 GHOST_TUns64 GHOST_SystemWin32::getMilliSeconds() const
129 {
130         // Hardware does not support high resolution timers. We will use GetTickCount instead then.
131         if (!m_hasPerformanceCounter) {
132                 return ::GetTickCount();
133         }
134
135         // Retrieve current count
136         __int64 count = 0;
137         ::QueryPerformanceCounter((LARGE_INTEGER*)&count);
138
139         // Calculate the time passed since system initialization.
140         __int64 delta = 1000*(count-m_start);
141
142         GHOST_TUns64 t = (GHOST_TUns64)(delta/m_freq);
143         return t; 
144 }
145
146
147 GHOST_TUns8 GHOST_SystemWin32::getNumDisplays() const
148 {
149         GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::getNumDisplays(): m_displayManager==0\n");
150         GHOST_TUns8 numDisplays;
151         m_displayManager->getNumDisplays(numDisplays);
152         return numDisplays;
153 }
154
155
156 void GHOST_SystemWin32::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const
157 {
158         width = ::GetSystemMetrics(SM_CXSCREEN);
159         height= ::GetSystemMetrics(SM_CYSCREEN);
160 }
161
162
163 GHOST_IWindow* GHOST_SystemWin32::createWindow(
164         const STR_String& title, 
165         GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height,
166         GHOST_TWindowState state, GHOST_TDrawingContextType type,
167         bool stereoVisual)
168 {
169         GHOST_Window* window = 0;
170         window = new GHOST_WindowWin32 (title, left, top, width, height, state, type, stereoVisual);
171         if (window) {
172                 if (window->getValid()) {
173                         // Store the pointer to the window
174 //                      if (state != GHOST_kWindowStateFullScreen) {
175                                 m_windowManager->addWindow(window);
176 //                      }
177                 }
178                 else {
179                         delete window;
180                         window = 0;
181                 }
182         }
183         return window;
184 }
185
186
187 bool GHOST_SystemWin32::processEvents(bool waitForEvent)
188 {
189         MSG msg;
190         bool anyProcessed = false;
191
192         do {
193                 GHOST_TimerManager* timerMgr = getTimerManager();
194
195                 if (waitForEvent && !::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE)) {
196 #if 1
197                         ::Sleep(1);
198 #else
199                         GHOST_TUns64 next = timerMgr->nextFireTime();
200                         
201                         if (next == GHOST_kFireTimeNever) {
202                                 ::WaitMessage();
203                         } else {
204                                 ::SetTimer(NULL, 0, next - getMilliSeconds(), NULL);
205                                 ::WaitMessage();
206                                 ::KillTimer(NULL, 0);
207                         }
208 #endif
209                 }
210
211                 if (timerMgr->fireTimers(getMilliSeconds())) {
212                         anyProcessed = true;
213                 }
214
215                 // Process all the events waiting for us
216                 while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE) != 0) {
217                         ::TranslateMessage(&msg);
218                         ::DispatchMessage(&msg);
219                         anyProcessed = true;
220                 }
221         } while (waitForEvent && !anyProcessed);
222
223         return anyProcessed;
224 }
225
226
227 GHOST_TSuccess GHOST_SystemWin32::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const
228 {
229         POINT point;
230         bool success = ::GetCursorPos(&point) == TRUE;
231         x = point.x;
232         y = point.y;
233         return GHOST_kSuccess;
234 }
235
236
237 GHOST_TSuccess GHOST_SystemWin32::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) const
238 {
239         return ::SetCursorPos(x, y) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
240 }
241
242
243 GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys& keys) const
244 {
245         /*
246         GetKeyState and GetAsyncKeyState only work with Win95, Win98, NT4,
247         Terminal Server and Windows 2000.
248         But on WinME it always returns zero. These two functions are simply
249         skipped by Millenium Edition!
250
251         Official explanation from Microsoft:
252         Intentionally disabled.
253         It didn't work all that well on some newer hardware, and worked less 
254         well with the passage of time, so it was fully disabled in ME.
255         */
256         if (m_seperateLeftRight && m_seperateLeftRightInitialized) {
257                 bool down = HIBYTE(::GetKeyState(VK_LSHIFT)) != 0;
258                 keys.set(GHOST_kModifierKeyLeftShift, down);
259                 down = HIBYTE(::GetKeyState(VK_RSHIFT)) != 0;
260                 keys.set(GHOST_kModifierKeyRightShift, down);
261                 down = HIBYTE(::GetKeyState(VK_LMENU)) != 0;
262                 keys.set(GHOST_kModifierKeyLeftAlt, down);
263                 down = HIBYTE(::GetKeyState(VK_RMENU)) != 0;
264                 keys.set(GHOST_kModifierKeyRightAlt, down);
265                 down = HIBYTE(::GetKeyState(VK_LCONTROL)) != 0;
266                 keys.set(GHOST_kModifierKeyLeftControl, down);
267                 down = HIBYTE(::GetKeyState(VK_RCONTROL)) != 0;
268                 keys.set(GHOST_kModifierKeyRightControl, down);
269         }
270         else {
271                 bool down = HIBYTE(::GetKeyState(VK_SHIFT)) != 0;
272                 keys.set(GHOST_kModifierKeyLeftShift, down);
273                 keys.set(GHOST_kModifierKeyRightShift, down);
274                 down = HIBYTE(::GetKeyState(VK_MENU)) != 0;
275                 keys.set(GHOST_kModifierKeyLeftAlt, down);
276                 keys.set(GHOST_kModifierKeyRightAlt, down);
277                 down = HIBYTE(::GetKeyState(VK_CONTROL)) != 0;
278                 keys.set(GHOST_kModifierKeyLeftControl, down);
279                 keys.set(GHOST_kModifierKeyRightControl, down);
280         }
281         return GHOST_kSuccess;
282 }
283
284
285 GHOST_TSuccess GHOST_SystemWin32::getButtons(GHOST_Buttons& buttons) const
286 {
287         /* Check for swapped buttons (left-handed mouse buttons)
288          * GetAsyncKeyState() will give back the state of the physical mouse buttons.
289          */
290         bool swapped = ::GetSystemMetrics(SM_SWAPBUTTON) == TRUE;
291
292         bool down = HIBYTE(::GetKeyState(VK_LBUTTON)) != 0;
293         buttons.set(swapped ? GHOST_kButtonMaskRight : GHOST_kButtonMaskLeft, down);
294
295         down = HIBYTE(::GetKeyState(VK_MBUTTON)) != 0;
296         buttons.set(GHOST_kButtonMaskMiddle, down);
297
298         down = HIBYTE(::GetKeyState(VK_RBUTTON)) != 0;
299         buttons.set(swapped ? GHOST_kButtonMaskLeft : GHOST_kButtonMaskRight, down);
300         return GHOST_kSuccess;
301 }
302
303
304 GHOST_TSuccess GHOST_SystemWin32::init()
305 {
306         GHOST_TSuccess success = GHOST_System::init();
307
308         // Determine whether this system has a high frequency performance counter. */
309         m_hasPerformanceCounter = ::QueryPerformanceFrequency((LARGE_INTEGER*)&m_freq) == TRUE;
310         if (m_hasPerformanceCounter) {
311                 GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer available\n")
312                 ::QueryPerformanceCounter((LARGE_INTEGER*)&m_start);
313         }
314         else {
315                 GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer not available\n")
316         }
317
318         if (success) {
319                 WNDCLASS wc;
320                 wc.style= CS_HREDRAW | CS_VREDRAW;
321                 wc.lpfnWndProc= s_wndProc;
322                 wc.cbClsExtra= 0;
323                 wc.cbWndExtra= 0;
324                 wc.hInstance= ::GetModuleHandle(0);
325                 wc.hIcon = ::LoadIcon(wc.hInstance, "APPICON");
326                 
327                 if (!wc.hIcon) {
328                         ::LoadIcon(NULL, IDI_APPLICATION);
329                 }
330                 wc.hCursor = ::LoadCursor(0, IDC_ARROW);
331                 wc.hbrBackground= (HBRUSH)::GetStockObject(BLACK_BRUSH);
332                 wc.lpszMenuName = 0;
333                 wc.lpszClassName= GHOST_WindowWin32::getWindowClassName();
334     
335                 // Use RegisterClassEx for setting small icon
336                 if (::RegisterClass(&wc) == 0) {
337                         success = GHOST_kFailure;
338                 }
339         }
340         return success;
341 }
342
343
344 GHOST_TSuccess GHOST_SystemWin32::exit()
345 {
346         return GHOST_System::exit();
347 }
348
349
350 GHOST_TKey GHOST_SystemWin32::convertKey(WPARAM wParam, LPARAM lParam) const
351 {
352         GHOST_TKey key;
353         bool isExtended = (lParam&(1<<24))?true:false;
354
355         if ((wParam >= '0') && (wParam <= '9')) {
356                 // VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39)
357                 key = (GHOST_TKey)(wParam - '0' + GHOST_kKey0);
358         }
359         else if ((wParam >= 'A') && (wParam <= 'Z')) {
360                 // VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A)
361                 key = (GHOST_TKey)(wParam - 'A' + GHOST_kKeyA);
362         }
363         else if ((wParam >= VK_F1) && (wParam <= VK_F24)) {
364                 key = (GHOST_TKey)(wParam - VK_F1 + GHOST_kKeyF1);
365         }
366         else {
367                 switch (wParam) {
368                 case VK_RETURN:
369                         key = isExtended?GHOST_kKeyNumpadEnter:GHOST_kKeyEnter;
370                         break;
371
372                 case VK_BACK:     key = GHOST_kKeyBackSpace;            break;
373                 case VK_TAB:      key = GHOST_kKeyTab;                          break;
374                 case VK_ESCAPE:   key = GHOST_kKeyEsc;                          break;
375                 case VK_SPACE:    key = GHOST_kKeySpace;                        break;
376                 case VK_PRIOR:    key = GHOST_kKeyUpPage;                       break;
377                 case VK_NEXT:     key = GHOST_kKeyDownPage;                     break;
378                 case VK_END:      key = GHOST_kKeyEnd;                          break;
379                 case VK_HOME:     key = GHOST_kKeyHome;                         break;
380                 case VK_INSERT:   key = GHOST_kKeyInsert;                       break;
381                 case VK_DELETE:   key = GHOST_kKeyDelete;                       break;
382                 case VK_LEFT:     key = GHOST_kKeyLeftArrow;            break;
383                 case VK_RIGHT:    key = GHOST_kKeyRightArrow;           break;
384                 case VK_UP:       key = GHOST_kKeyUpArrow;                      break;
385                 case VK_DOWN:     key = GHOST_kKeyDownArrow;            break;
386                 case VK_NUMPAD0:  key = GHOST_kKeyNumpad0;                      break;
387                 case VK_NUMPAD1:  key = GHOST_kKeyNumpad1;                      break;
388                 case VK_NUMPAD2:  key = GHOST_kKeyNumpad2;                      break;
389                 case VK_NUMPAD3:  key = GHOST_kKeyNumpad3;                      break;
390                 case VK_NUMPAD4:  key = GHOST_kKeyNumpad4;                      break;
391                 case VK_NUMPAD5:  key = GHOST_kKeyNumpad5;                      break;
392                 case VK_NUMPAD6:  key = GHOST_kKeyNumpad6;                      break;
393                 case VK_NUMPAD7:  key = GHOST_kKeyNumpad7;                      break;
394                 case VK_NUMPAD8:  key = GHOST_kKeyNumpad8;                      break;
395                 case VK_NUMPAD9:  key = GHOST_kKeyNumpad9;                      break;
396                 case VK_SNAPSHOT: key = GHOST_kKeyPrintScreen;          break;
397                 case VK_PAUSE:    key = GHOST_kKeyPause;                        break;
398                 case VK_MULTIPLY: key = GHOST_kKeyNumpadAsterisk;        break;
399                 case VK_SUBTRACT: key = GHOST_kKeyNumpadMinus;          break;
400                 case VK_DECIMAL:  key = GHOST_kKeyNumpadPeriod;         break;
401                 case VK_DIVIDE:   key = GHOST_kKeyNumpadSlash;          break;
402                 case VK_ADD:      key = GHOST_kKeyNumpadPlus;           break;
403
404                 case VK_SEMICOLON:              key = GHOST_kKeySemicolon;              break;
405                 case VK_EQUALS:                 key = GHOST_kKeyEqual;                  break;
406                 case VK_COMMA:                  key = GHOST_kKeyComma;                  break;
407                 case VK_MINUS:                  key = GHOST_kKeyMinus;                  break;
408                 case VK_PERIOD:                 key = GHOST_kKeyPeriod;                 break;
409                 case VK_SLASH:                  key = GHOST_kKeySlash;                  break;
410                 case VK_BACK_QUOTE:             key = GHOST_kKeyAccentGrave;    break;
411                 case VK_OPEN_BRACKET:   key = GHOST_kKeyLeftBracket;    break;
412                 case VK_BACK_SLASH:             key = GHOST_kKeyBackslash;              break;
413                 case VK_CLOSE_BRACKET:  key = GHOST_kKeyRightBracket;   break;
414                 case VK_QUOTE:                  key = GHOST_kKeyQuote;                  break;
415                 case VK_GR_LESS:                key = GHOST_kKeyGrLess;                 break;
416
417                 // Process these keys separately because we need to distinguish right from left modifier keys
418                 case VK_SHIFT:
419                 case VK_CONTROL:
420                 case VK_MENU:
421
422                 // Ignore these keys
423                 case VK_NUMLOCK:
424                 case VK_SCROLL:
425                 case VK_CAPITAL:
426                 default:
427                         key = GHOST_kKeyUnknown;
428                         break;
429                 }
430         }
431         return key;
432 }
433
434
435 void GHOST_SystemWin32::processModifierKeys(GHOST_IWindow *window)
436 {
437         GHOST_ModifierKeys oldModifiers, newModifiers;
438         // Retrieve old state of the modifier keys
439         ((GHOST_SystemWin32*)getSystem())->retrieveModifierKeys(oldModifiers);
440         // Retrieve current state of the modifier keys
441         ((GHOST_SystemWin32*)getSystem())->getModifierKeys(newModifiers);
442
443         // Compare the old and the new
444         if (!newModifiers.equals(oldModifiers)) {
445                 // Create events for the masks that changed
446                 for (int i = 0; i < GHOST_kModifierKeyNumMasks; i++) {
447                         if (newModifiers.get((GHOST_TModifierKeyMask)i) != oldModifiers.get((GHOST_TModifierKeyMask)i)) {
448                                 // Convert the mask to a key code
449                                 GHOST_TKey key = GHOST_ModifierKeys::getModifierKeyCode((GHOST_TModifierKeyMask)i);
450                                 bool keyDown = newModifiers.get((GHOST_TModifierKeyMask)i);
451                                 GHOST_EventKey* event;
452                                 if (key != GHOST_kKeyUnknown) {
453                                         // Create an event
454                                         event = new GHOST_EventKey(getSystem()->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key);
455                                         pushEvent(event);
456                                 }
457                         }
458                 }
459         }
460
461         // Store new modifier keys state
462         ((GHOST_SystemWin32*)getSystem())->storeModifierKeys(newModifiers);
463 }
464
465
466 GHOST_EventButton* GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, GHOST_IWindow *window, GHOST_TButtonMask mask)
467 {
468         return new GHOST_EventButton (getSystem()->getMilliSeconds(), type, window, mask);
469 }
470
471
472 GHOST_EventCursor* GHOST_SystemWin32::processCursorEvent(GHOST_TEventType type, GHOST_IWindow *window)
473 {
474         GHOST_TInt32 x, y;
475         getSystem()->getCursorPosition(x, y);
476         return new GHOST_EventCursor (getSystem()->getMilliSeconds(), type, window, x, y);
477 }
478
479
480 GHOST_EventWheel* GHOST_SystemWin32::processWheelEvent(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam)
481 {
482         // short fwKeys = LOWORD(wParam);                       // key flags
483         int zDelta = (short) HIWORD(wParam);    // wheel rotation
484         zDelta /= WHEEL_DELTA;
485         // short xPos = (short) LOWORD(lParam); // horizontal position of pointer
486         // short yPos = (short) HIWORD(lParam); // vertical position of pointer
487         return new GHOST_EventWheel (getSystem()->getMilliSeconds(), window, zDelta);
488 }
489
490
491 GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, bool keyDown, WPARAM wParam, LPARAM lParam)
492 {
493         GHOST_TKey key = ((GHOST_SystemWin32*)getSystem())->convertKey(wParam, lParam);
494         GHOST_EventKey* event;
495         if (key != GHOST_kKeyUnknown) {
496                 MSG keyMsg;
497                 char ascii = '\0';
498
499                         /* Eat any character related messages */
500                 if (::PeekMessage(&keyMsg, NULL, WM_CHAR, WM_SYSDEADCHAR, PM_REMOVE)) {
501                         ascii = (char) keyMsg.wParam;
502                 }
503
504                 event = new GHOST_EventKey(getSystem()->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key, ascii);
505         }
506         else {
507                 event = 0;
508         }
509         return event;
510 }
511
512
513 GHOST_Event* GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type, GHOST_IWindow* window)
514 {
515         return new GHOST_Event(getSystem()->getMilliSeconds(), type, window);
516 }
517
518
519 LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
520 {
521         GHOST_Event* event = 0;
522         LRESULT lResult;
523         GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem());
524         GHOST_ASSERT(system, "GHOST_SystemWin32::s_wndProc(): system not initialized")
525
526         if (hwnd) {
527                 GHOST_WindowWin32* window = (GHOST_WindowWin32*)::GetWindowLong(hwnd, GWL_USERDATA);
528                 if (window) {
529                         switch (msg) {
530                                 ////////////////////////////////////////////////////////////////////////
531                                 // Keyboard events, processed
532                                 ////////////////////////////////////////////////////////////////////////
533                                 case WM_KEYDOWN:
534                                         /* The WM_KEYDOWN message is posted to the window with the keyboard focus when a 
535                                          * nonsystem key is pressed. A nonsystem key is a key that is pressed when the alt
536                                          * key is not pressed. 
537                                          */
538                                 case WM_SYSKEYDOWN:
539                                         /* The WM_SYSKEYDOWN message is posted to the window with the keyboard focus when 
540                                          * the user presses the F10 key (which activates the menu bar) or holds down the 
541                                          * alt key and then presses another key. It also occurs when no window currently 
542                                          * has the keyboard focus; in this case, the WM_SYSKEYDOWN message is sent to the 
543                                          * active window. The window that receives the message can distinguish between these 
544                                          * two contexts by checking the context code in the lKeyData parameter. 
545                                          */
546                                         switch (wParam) {
547                                                 case VK_SHIFT:
548                                                 case VK_CONTROL:
549                                                 case VK_MENU:
550                                                         if (!system->m_seperateLeftRightInitialized) {
551                                                                 // Check whether this system supports seperate left and right keys
552                                                                 switch (wParam) {
553                                                                         case VK_SHIFT:
554                                                                                 system->m_seperateLeftRight = 
555                                                                                         (HIBYTE(::GetKeyState(VK_LSHIFT)) != 0) ||
556                                                                                         (HIBYTE(::GetKeyState(VK_RSHIFT)) != 0) ?
557                                                                                         true : false;
558                                                                                 break;
559                                                                         case VK_CONTROL:
560                                                                                 system->m_seperateLeftRight = 
561                                                                                         (HIBYTE(::GetKeyState(VK_LCONTROL)) != 0) ||
562                                                                                         (HIBYTE(::GetKeyState(VK_RCONTROL)) != 0) ?
563                                                                                         true : false;
564                                                                                 break;
565                                                                         case VK_MENU:
566                                                                                 system->m_seperateLeftRight = 
567                                                                                         (HIBYTE(::GetKeyState(VK_LMENU)) != 0) ||
568                                                                                         (HIBYTE(::GetKeyState(VK_RMENU)) != 0) ?
569                                                                                         true : false;
570                                                                                 break;
571                                                                 }
572                                                                 system->m_seperateLeftRightInitialized = true;
573                                                         }
574                                                         system->processModifierKeys(window);
575                                                         // Bypass call to DefWindowProc
576                                                         return 0;
577                                                 default:
578                                                         event = processKeyEvent(window, true, wParam, lParam);
579                                                         if (!event) {
580                                                                 GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
581                                                                 GHOST_PRINT(msg)
582                                                                 GHOST_PRINT(" key ignored\n")
583                                                         }
584                                                         break;
585                                                 }
586                                         break;
587
588                                 case WM_KEYUP:
589                                 case WM_SYSKEYUP:
590                                         switch (wParam) {
591                                                 case VK_SHIFT:
592                                                 case VK_CONTROL:
593                                                 case VK_MENU:
594                                                         system->processModifierKeys(window);
595                                                         // Bypass call to DefWindowProc
596                                                         return 0;
597                                                 default:
598                                                         event = processKeyEvent(window, false, wParam, lParam);
599                                                         if (!event) {
600                                                                 GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
601                                                                 GHOST_PRINT(msg)
602                                                                 GHOST_PRINT(" key ignored\n")
603                                                         }
604                                                         break;
605                                         }
606                                         break;
607
608                                 ////////////////////////////////////////////////////////////////////////
609                                 // Keyboard events, ignored
610                                 ////////////////////////////////////////////////////////////////////////
611                                 case WM_CHAR:
612                                         /* The WM_CHAR message is posted to the window with the keyboard focus when 
613                                          * a WM_KEYDOWN message is translated by the TranslateMessage function. WM_CHAR 
614                                          * contains the character code of the key that was pressed. 
615                                          */
616                                 case WM_DEADCHAR:
617                                         /* The WM_DEADCHAR message is posted to the window with the keyboard focus when a
618                                          * WM_KEYUP message is translated by the TranslateMessage function. WM_DEADCHAR 
619                                          * specifies a character code generated by a dead key. A dead key is a key that 
620                                          * generates a character, such as the umlaut (double-dot), that is combined with 
621                                          * another character to form a composite character. For example, the umlaut-O 
622                                          * character (Ù) is generated by typing the dead key for the umlaut character, and 
623                                          * then typing the O key.
624                                          */
625                                 case WM_SYSDEADCHAR:
626                                         /* The WM_SYSDEADCHAR message is sent to the window with the keyboard focus when 
627                                          * a WM_SYSKEYDOWN message is translated by the TranslateMessage function. 
628                                          * WM_SYSDEADCHAR specifies the character code of a system dead key - that is, 
629                                          * a dead key that is pressed while holding down the alt key. 
630                                          */
631                                         break;
632                                 ////////////////////////////////////////////////////////////////////////
633                                 // Tablet events, processed
634                                 ////////////////////////////////////////////////////////////////////////
635                                 case WT_PACKET:
636                                         ((GHOST_WindowWin32*)window)->processWin32TabletEvent(wParam, lParam);
637                                         break;
638                                 case WT_CSRCHANGE:
639                                 case WT_PROXIMITY:
640                                         ((GHOST_WindowWin32*)window)->processWin32TabletInitEvent();
641                                         break;
642                                 ////////////////////////////////////////////////////////////////////////
643                                 // Mouse events, processed
644                                 ////////////////////////////////////////////////////////////////////////
645                                 case WM_LBUTTONDOWN:
646                                         window->registerMouseClickEvent(true);
647                                         event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft);
648                                         break;
649                                 case WM_MBUTTONDOWN:
650                                         window->registerMouseClickEvent(true);
651                                         event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskMiddle);
652                                         break;
653                                 case WM_RBUTTONDOWN:
654                                         window->registerMouseClickEvent(true);
655                                         event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight);
656                                         break;
657                                 case WM_LBUTTONUP:
658                                         window->registerMouseClickEvent(false);
659                                         event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft);
660                                         break;
661                                 case WM_MBUTTONUP:
662                                         window->registerMouseClickEvent(false);
663                                         event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskMiddle);
664                                         break;
665                                 case WM_RBUTTONUP:
666                                         window->registerMouseClickEvent(false);
667                                         event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight);
668                                         break;
669                                 case WM_MOUSEMOVE:
670                                         event = processCursorEvent(GHOST_kEventCursorMove, window);
671                                         break;
672                                 case WM_MOUSEWHEEL:
673                                         /* The WM_MOUSEWHEEL message is sent to the focus window 
674                                          * when the mouse wheel is rotated. The DefWindowProc 
675                                          * function propagates the message to the window's parent.
676                                          * There should be no internal forwarding of the message, 
677                                          * since DefWindowProc propagates it up the parent chain 
678                                          * until it finds a window that processes it.
679                                          */
680                                         event = processWheelEvent(window, wParam, lParam);
681                                         break;
682                                 case WM_SETCURSOR:
683                                         /* The WM_SETCURSOR message is sent to a window if the mouse causes the cursor
684                                          * to move within a window and mouse input is not captured.
685                                          * This means we have to set the cursor shape every time the mouse moves!
686                                          * The DefWindowProc function uses this message to set the cursor to an 
687                                          * arrow if it is not in the client area.
688                                          */
689                                         if (LOWORD(lParam) == HTCLIENT) {
690                                                 // Load the current cursor
691                                                 window->loadCursor(window->getCursorVisibility(), window->getCursorShape());
692                                                 // Bypass call to DefWindowProc
693                                                 return 0;
694                                         } 
695                                         else {
696                                                 // Outside of client area show standard cursor
697                                                 window->loadCursor(true, GHOST_kStandardCursorDefault);
698                                         }
699                                         break;
700
701                                 ////////////////////////////////////////////////////////////////////////
702                                 // Mouse events, ignored
703                                 ////////////////////////////////////////////////////////////////////////
704                                 case WM_NCMOUSEMOVE:
705                                         /* The WM_NCMOUSEMOVE message is posted to a window when the cursor is moved 
706                                          * within the nonclient area of the window. This message is posted to the window 
707                                          * that contains the cursor. If a window has captured the mouse, this message is not posted.
708                                          */
709                                 case WM_NCHITTEST:
710                                         /* The WM_NCHITTEST message is sent to a window when the cursor moves, or 
711                                          * when a mouse button is pressed or released. If the mouse is not captured, 
712                                          * the message is sent to the window beneath the cursor. Otherwise, the message 
713                                          * is sent to the window that has captured the mouse. 
714                                          */
715                                         break;
716
717                                 ////////////////////////////////////////////////////////////////////////
718                                 // Window events, processed
719                                 ////////////////////////////////////////////////////////////////////////
720                                 case WM_CLOSE:
721                                         /* The WM_CLOSE message is sent as a signal that a window or an application should terminate. */
722                                         event = processWindowEvent(GHOST_kEventWindowClose, window);
723                                         break;
724                                 case WM_ACTIVATE:
725                                         /* The WM_ACTIVATE message is sent to both the window being activated and the window being 
726                                          * deactivated. If the windows use the same input queue, the message is sent synchronously, 
727                                          * first to the window procedure of the top-level window being deactivated, then to the window
728                                          * procedure of the top-level window being activated. If the windows use different input queues,
729                                          * the message is sent asynchronously, so the window is activated immediately. 
730                                          */
731                                         event = processWindowEvent(LOWORD(wParam) ? GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate, window);
732                                         break;
733                                 case WM_PAINT:
734                                         /* An application sends the WM_PAINT message when the system or another application 
735                                          * makes a request to paint a portion of an application's window. The message is sent
736                                          * when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage 
737                                          * function when the application obtains a WM_PAINT message by using the GetMessage or 
738                                          * PeekMessage function. 
739                                          */
740                                         event = processWindowEvent(GHOST_kEventWindowUpdate, window);
741                                         ::ValidateRect(hwnd, NULL);
742                                         break;
743                                 case WM_SIZE:
744                                         /* The WM_SIZE message is sent to a window after its size has changed.
745                                          * The WM_SIZE and WM_MOVE messages are not sent if an application handles the 
746                                          * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
747                                          * to perform any move or size change processing during the WM_WINDOWPOSCHANGED 
748                                          * message without calling DefWindowProc.
749                                          */
750                                         event = processWindowEvent(GHOST_kEventWindowSize, window);
751                                 case WM_CAPTURECHANGED:
752                                         window->lostMouseCapture();
753                                         break;
754
755                                 ////////////////////////////////////////////////////////////////////////
756                                 // Window events, ignored
757                                 ////////////////////////////////////////////////////////////////////////
758                                 case WM_WINDOWPOSCHANGED:
759                                         /* The WM_WINDOWPOSCHANGED message is sent to a window whose size, position, or place
760                                          * in the Z order has changed as a result of a call to the SetWindowPos function or 
761                                          * another window-management function.
762                                          * The WM_SIZE and WM_MOVE messages are not sent if an application handles the 
763                                          * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
764                                          * to perform any move or size change processing during the WM_WINDOWPOSCHANGED 
765                                          * message without calling DefWindowProc.
766                                          */
767                                 case WM_MOVE:
768                                         /* The WM_SIZE and WM_MOVE messages are not sent if an application handles the 
769                                          * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
770                                          * to perform any move or size change processing during the WM_WINDOWPOSCHANGED 
771                                          * message without calling DefWindowProc. 
772                                          */
773                                 case WM_ERASEBKGND:
774                                         /* An application sends the WM_ERASEBKGND message when the window background must be 
775                                          * erased (for example, when a window is resized). The message is sent to prepare an 
776                                          * invalidated portion of a window for painting. 
777                                          */
778                                 case WM_NCPAINT:
779                                         /* An application sends the WM_NCPAINT message to a window when its frame must be painted. */
780                                 case WM_NCACTIVATE:
781                                         /* The WM_NCACTIVATE message is sent to a window when its nonclient area needs to be changed 
782                                          * to indicate an active or inactive state. 
783                                          */
784                                 case WM_DESTROY:
785                                         /* The WM_DESTROY message is sent when a window is being destroyed. It is sent to the window 
786                                          * procedure of the window being destroyed after the window is removed from the screen. 
787                                          * This message is sent first to the window being destroyed and then to the child windows 
788                                          * (if any) as they are destroyed. During the processing of the message, it can be assumed 
789                                          * that all child windows still exist. 
790                                          */
791                                 case WM_NCDESTROY:
792                                         /* The WM_NCDESTROY message informs a window that its nonclient area is being destroyed. The 
793                                          * DestroyWindow function sends the WM_NCDESTROY message to the window following the WM_DESTROY
794                                          * message. WM_DESTROY is used to free the allocated memory object associated with the window. 
795                                          */
796                                 case WM_KILLFOCUS:
797                                         /* The WM_KILLFOCUS message is sent to a window immediately before it loses the keyboard focus. */
798                                 case WM_SHOWWINDOW:
799                                         /* The WM_SHOWWINDOW message is sent to a window when the window is about to be hidden or shown. */
800                                 case WM_WINDOWPOSCHANGING:
801                                         /* The WM_WINDOWPOSCHANGING message is sent to a window whose size, position, or place in 
802                                          * the Z order is about to change as a result of a call to the SetWindowPos function or 
803                                          * another window-management function. 
804                                          */
805                                 case WM_SETFOCUS:
806                                         /* The WM_SETFOCUS message is sent to a window after it has gained the keyboard focus. */
807                                 case WM_MOVING:
808                                         /* The WM_MOVING message is sent to a window that the user is moving. By processing 
809                                          * this message, an application can monitor the size and position of the drag rectangle
810                                          * and, if needed, change its size or position.
811                                          */
812                                 case WM_ENTERSIZEMOVE:
813                                         /* The WM_ENTERSIZEMOVE message is sent one time to a window after it enters the moving 
814                                          * or sizing modal loop. The window enters the moving or sizing modal loop when the user 
815                                          * clicks the window's title bar or sizing border, or when the window passes the 
816                                          * WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the 
817                                          * message specifies the SC_MOVE or SC_SIZE value. The operation is complete when 
818                                          * DefWindowProc returns. 
819                                          */
820                                         break;
821                                         
822                                 ////////////////////////////////////////////////////////////////////////
823                                 // Other events
824                                 ////////////////////////////////////////////////////////////////////////
825                                 case WM_GETTEXT:
826                                         /* An application sends a WM_GETTEXT message to copy the text that 
827                                          * corresponds to a window into a buffer provided by the caller. 
828                                          */
829                                 case WM_ACTIVATEAPP:
830                                         /* The WM_ACTIVATEAPP message is sent when a window belonging to a 
831                                          * different application than the active window is about to be activated.
832                                          * The message is sent to the application whose window is being activated
833                                          * and to the application whose window is being deactivated. 
834                                          */
835                                 case WM_TIMER:
836                                         /* The WIN32 docs say:
837                                          * The WM_TIMER message is posted to the installing thread's message queue
838                                          * when a timer expires. You can process the message by providing a WM_TIMER
839                                          * case in the window procedure. Otherwise, the default window procedure will
840                                          * call the TimerProc callback function specified in the call to the SetTimer
841                                          * function used to install the timer. 
842                                          *
843                                          * In GHOST, we let DefWindowProc call the timer callback.
844                                          */
845                                         break;
846                                 case WM_BLND_3DX:
847                                         {
848                                                 GHOST_TEventNDOFData ndofdata;
849                                                 system->m_ndofManager->GHOST_NDOFGetDatas(ndofdata);
850                                                 system->m_eventManager->
851                                                         pushEvent(new GHOST_EventNDOF(
852                                                                 system->getMilliSeconds(), 
853                                                                 GHOST_kEventNDOFMotion, 
854                                                                 window, ndofdata));
855                                         }
856                                         break;
857                         }
858                 }
859                 else {
860                         // Event found for a window before the pointer to the class has been set.
861                         GHOST_PRINT("GHOST_SystemWin32::wndProc: GHOST window event before creation\n")
862                         /* These are events we typically miss at this point:
863                            WM_GETMINMAXINFO     0x24
864                            WM_NCCREATE                  0x81
865                            WM_NCCALCSIZE                0x83
866                            WM_CREATE                    0x01
867                            We let DefWindowProc do the work.
868                         */
869                 }
870         }
871         else {
872                 // Events without valid hwnd
873                 GHOST_PRINT("GHOST_SystemWin32::wndProc: event without window\n")
874         }
875
876         if (event) {
877                 system->pushEvent(event);
878                 lResult = 0;
879         }
880         else {
881                 lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
882         }
883         return lResult;
884 }