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