Adding support for the "media" play/pause/stop/next/prev buttons
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 #include <iostream>
38
39 #include "GHOST_SystemWin32.h"
40 #include "GHOST_EventDragnDrop.h"
41
42 #define WIN32_LEAN_AND_MEAN
43 #ifdef _WIN32_IE
44 #undef _WIN32_IE
45 #endif
46 #define _WIN32_IE 0x0501
47 #include <windows.h>
48 #include <shlobj.h>
49
50 // win64 doesn't define GWL_USERDATA
51 #ifdef WIN32
52 #ifndef GWL_USERDATA
53 #define GWL_USERDATA GWLP_USERDATA
54 #define GWL_WNDPROC GWLP_WNDPROC
55 #endif
56 #endif
57
58 /*
59  * According to the docs the mouse wheel message is supported from windows 98 
60  * upwards. Leaving WINVER at default value, the WM_MOUSEWHEEL message and the 
61  * wheel detent value are undefined.
62  */
63 #ifndef WM_MOUSEWHEEL
64 #define WM_MOUSEWHEEL 0x020A
65 #endif // WM_MOUSEWHEEL
66 #ifndef WHEEL_DELTA
67 #define WHEEL_DELTA 120 /* Value for rolling one detent, (old convention! MS changed it) */
68 #endif // WHEEL_DELTA
69
70 /* 
71  * Defines for mouse buttons 4 and 5 aka xbutton1 and xbutton2.
72  * MSDN: Declared in Winuser.h, include Windows.h 
73  * This does not seem to work with MinGW so we define our own here.
74  */
75 #ifndef XBUTTON1
76 #define XBUTTON1 0x0001
77 #endif // XBUTTON1
78 #ifndef XBUTTON2
79 #define XBUTTON2 0x0002
80 #endif // XBUTTON2
81 #ifndef WM_XBUTTONUP
82 #define WM_XBUTTONUP 524
83 #endif // WM_XBUTTONUP
84 #ifndef WM_XBUTTONDOWN
85 #define WM_XBUTTONDOWN 523
86 #endif // WM_XBUTTONDOWN
87
88 #include "GHOST_Debug.h"
89 #include "GHOST_DisplayManagerWin32.h"
90 #include "GHOST_EventButton.h"
91 #include "GHOST_EventCursor.h"
92 #include "GHOST_EventKey.h"
93 #include "GHOST_EventWheel.h"
94 #include "GHOST_EventNDOF.h"
95 #include "GHOST_TimerTask.h"
96 #include "GHOST_TimerManager.h"
97 #include "GHOST_WindowManager.h"
98 #include "GHOST_WindowWin32.h"
99 #include "GHOST_NDOFManager.h"
100
101 // Key code values not found in winuser.h
102 #ifndef VK_MINUS
103 #define VK_MINUS 0xBD
104 #endif // VK_MINUS
105 #ifndef VK_SEMICOLON
106 #define VK_SEMICOLON 0xBA
107 #endif // VK_SEMICOLON
108 #ifndef VK_PERIOD
109 #define VK_PERIOD 0xBE
110 #endif // VK_PERIOD
111 #ifndef VK_COMMA
112 #define VK_COMMA 0xBC
113 #endif // VK_COMMA
114 #ifndef VK_QUOTE
115 #define VK_QUOTE 0xDE
116 #endif // VK_QUOTE
117 #ifndef VK_BACK_QUOTE
118 #define VK_BACK_QUOTE 0xC0
119 #endif // VK_BACK_QUOTE
120 #ifndef VK_SLASH
121 #define VK_SLASH 0xBF
122 #endif // VK_SLASH
123 #ifndef VK_BACK_SLASH
124 #define VK_BACK_SLASH 0xDC
125 #endif // VK_BACK_SLASH
126 #ifndef VK_EQUALS
127 #define VK_EQUALS 0xBB
128 #endif // VK_EQUALS
129 #ifndef VK_OPEN_BRACKET
130 #define VK_OPEN_BRACKET 0xDB
131 #endif // VK_OPEN_BRACKET
132 #ifndef VK_CLOSE_BRACKET
133 #define VK_CLOSE_BRACKET 0xDD
134 #endif // VK_CLOSE_BRACKET
135 #ifndef VK_GR_LESS
136 #define VK_GR_LESS 0xE2
137 #endif // VK_GR_LESS
138
139 #ifndef VK_MEDIA_NEXT_TRACK
140 #define VK_MEDIA_NEXT_TRACK     0xB0
141 #endif // VK_MEDIA_NEXT_TRACK
142 #ifndef VK_MEDIA_PREV_TRACK
143 #define VK_MEDIA_PREV_TRACK     0xB1
144 #endif // VK_MEDIA_PREV_TRACK
145 #ifndef VK_MEDIA_STOP
146 #define VK_MEDIA_STOP   0xB2
147 #endif // VK_MEDIA_STOP
148 #ifndef VK_MEDIA_PLAY_PAUSE
149 #define VK_MEDIA_PLAY_PAUSE     0xB3
150 #endif // VK_MEDIA_PLAY_PAUSE
151
152
153 GHOST_SystemWin32::GHOST_SystemWin32()
154 : m_hasPerformanceCounter(false), m_freq(0), m_start(0)
155 {
156         m_displayManager = new GHOST_DisplayManagerWin32 ();
157         GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::GHOST_SystemWin32(): m_displayManager==0\n");
158         m_displayManager->initialize();
159         
160         // Check if current keyboard layout uses AltGr and save keylayout ID for
161         // specialized handling if keys like VK_OEM_*. I.e. french keylayout
162         // generates VK_OEM_8 for their exclamation key (key left of right shift)
163         this->handleKeyboardChange();
164         // Require COM for GHOST_DropTargetWin32 created in GHOST_WindowWin32.
165         OleInitialize(0);
166 }
167
168 GHOST_SystemWin32::~GHOST_SystemWin32()
169 {
170         // Shutdown COM
171         OleUninitialize();
172 }
173
174
175 GHOST_TUns64 GHOST_SystemWin32::getMilliSeconds() const
176 {
177         // Hardware does not support high resolution timers. We will use GetTickCount instead then.
178         if (!m_hasPerformanceCounter) {
179                 return ::GetTickCount();
180         }
181
182         // Retrieve current count
183         __int64 count = 0;
184         ::QueryPerformanceCounter((LARGE_INTEGER*)&count);
185
186         // Calculate the time passed since system initialization.
187         __int64 delta = 1000*(count-m_start);
188
189         GHOST_TUns64 t = (GHOST_TUns64)(delta/m_freq);
190         return t; 
191 }
192
193
194 GHOST_TUns8 GHOST_SystemWin32::getNumDisplays() const
195 {
196         GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::getNumDisplays(): m_displayManager==0\n");
197         GHOST_TUns8 numDisplays;
198         m_displayManager->getNumDisplays(numDisplays);
199         return numDisplays;
200 }
201
202
203 void GHOST_SystemWin32::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const
204 {
205         width = ::GetSystemMetrics(SM_CXSCREEN);
206         height= ::GetSystemMetrics(SM_CYSCREEN);
207 }
208
209
210 GHOST_IWindow* GHOST_SystemWin32::createWindow(
211         const STR_String& title, 
212         GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height,
213         GHOST_TWindowState state, GHOST_TDrawingContextType type,
214         bool stereoVisual, const GHOST_TUns16 numOfAASamples, const GHOST_TEmbedderWindowID parentWindow )
215 {
216         GHOST_Window* window = 0;
217         window = new GHOST_WindowWin32 (this, title, left, top, width, height, state, type, stereoVisual, numOfAASamples);
218         if (window) {
219                 if (window->getValid()) {
220                         // Store the pointer to the window
221 //                      if (state != GHOST_kWindowStateFullScreen) {
222                                 m_windowManager->addWindow(window);
223 //                      }
224                 }
225                 else {
226                         // An invalid window could be one that was used to test for AA
227                         window = ((GHOST_WindowWin32*)window)->getNextWindow();
228                         
229                         // If another window is found, let the wm know about that one, but not the old one
230                         if (window->getValid()) {
231                                 m_windowManager->addWindow(window);
232                         }
233                         else {
234                                 delete window;
235                                 window = 0;
236                         }
237
238                 }
239         }
240         return window;
241 }
242
243
244 bool GHOST_SystemWin32::processEvents(bool waitForEvent)
245 {
246         MSG msg;
247         bool anyProcessed = false;
248
249         do {
250                 GHOST_TimerManager* timerMgr = getTimerManager();
251
252                 if (waitForEvent && !::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE)) {
253 #if 1
254                         ::Sleep(1);
255 #else
256                         GHOST_TUns64 next = timerMgr->nextFireTime();
257                         GHOST_TInt64 maxSleep = next - getMilliSeconds();
258                         
259                         if (next == GHOST_kFireTimeNever) {
260                                 ::WaitMessage();
261                         } else if(maxSleep >= 0.0) {
262                                 ::SetTimer(NULL, 0, maxSleep, NULL);
263                                 ::WaitMessage();
264                                 ::KillTimer(NULL, 0);
265                         }
266 #endif
267                 }
268
269                 if (timerMgr->fireTimers(getMilliSeconds())) {
270                         anyProcessed = true;
271                 }
272
273                 // Process all the events waiting for us
274                 while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE) != 0) {
275                         ::TranslateMessage(&msg);
276                         ::DispatchMessage(&msg);
277                         anyProcessed = true;
278                 }
279         } while (waitForEvent && !anyProcessed);
280
281         return anyProcessed;
282 }
283
284
285 GHOST_TSuccess GHOST_SystemWin32::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const
286 {
287         POINT point;
288         if(::GetCursorPos(&point)){
289                 x = point.x;
290                 y = point.y;
291                 return GHOST_kSuccess;
292         }
293         return GHOST_kFailure;
294 }
295
296
297 GHOST_TSuccess GHOST_SystemWin32::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y)
298 {
299         if (!GetActiveWindow())
300                 return GHOST_kFailure;
301         return ::SetCursorPos(x, y) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
302 }
303
304
305 GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys& keys) const
306 {
307         bool down = HIBYTE(::GetKeyState(VK_LSHIFT)) != 0;
308         keys.set(GHOST_kModifierKeyLeftShift, down);
309         down = HIBYTE(::GetKeyState(VK_RSHIFT)) != 0;
310         keys.set(GHOST_kModifierKeyRightShift, down);
311         
312         down = HIBYTE(::GetKeyState(VK_LMENU)) != 0;
313         keys.set(GHOST_kModifierKeyLeftAlt, down);
314         down = HIBYTE(::GetKeyState(VK_RMENU)) != 0;
315         keys.set(GHOST_kModifierKeyRightAlt, down);
316         
317         down = HIBYTE(::GetKeyState(VK_LCONTROL)) != 0;
318         keys.set(GHOST_kModifierKeyLeftControl, down);
319         down = HIBYTE(::GetKeyState(VK_RCONTROL)) != 0;
320         keys.set(GHOST_kModifierKeyRightControl, down);
321         
322         bool lwindown = HIBYTE(::GetKeyState(VK_LWIN)) != 0;
323         bool rwindown = HIBYTE(::GetKeyState(VK_RWIN)) != 0;
324         if(lwindown || rwindown)
325                 keys.set(GHOST_kModifierKeyOS, true);
326         else
327                 keys.set(GHOST_kModifierKeyOS, false);
328         return GHOST_kSuccess;
329 }
330
331
332 GHOST_TSuccess GHOST_SystemWin32::getButtons(GHOST_Buttons& buttons) const
333 {
334         /* Check for swapped buttons (left-handed mouse buttons)
335          * GetAsyncKeyState() will give back the state of the physical mouse buttons.
336          */
337         bool swapped = ::GetSystemMetrics(SM_SWAPBUTTON) == TRUE;
338
339         bool down = HIBYTE(::GetKeyState(VK_LBUTTON)) != 0;
340         buttons.set(swapped ? GHOST_kButtonMaskRight : GHOST_kButtonMaskLeft, down);
341
342         down = HIBYTE(::GetKeyState(VK_MBUTTON)) != 0;
343         buttons.set(GHOST_kButtonMaskMiddle, down);
344
345         down = HIBYTE(::GetKeyState(VK_RBUTTON)) != 0;
346         buttons.set(swapped ? GHOST_kButtonMaskLeft : GHOST_kButtonMaskRight, down);
347         return GHOST_kSuccess;
348 }
349
350
351 GHOST_TSuccess GHOST_SystemWin32::init()
352 {
353         GHOST_TSuccess success = GHOST_System::init();
354         
355         for(int i = 0; i < 255; i++) {
356                 m_prevKeyStatus[i] = false;
357                 m_curKeyStatus[i] = false;
358         }
359
360         /* Disable scaling on high DPI displays on Vista */
361         HMODULE user32 = ::LoadLibraryA("user32.dll");
362         typedef BOOL (WINAPI * LPFNSETPROCESSDPIAWARE)();
363         LPFNSETPROCESSDPIAWARE SetProcessDPIAware =
364                 (LPFNSETPROCESSDPIAWARE)GetProcAddress(user32, "SetProcessDPIAware");
365         if (SetProcessDPIAware)
366                 SetProcessDPIAware();
367         FreeLibrary(user32);
368
369         // Determine whether this system has a high frequency performance counter. */
370         m_hasPerformanceCounter = ::QueryPerformanceFrequency((LARGE_INTEGER*)&m_freq) == TRUE;
371         if (m_hasPerformanceCounter) {
372                 GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer available\n")
373                 ::QueryPerformanceCounter((LARGE_INTEGER*)&m_start);
374         }
375         else {
376                 GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer not available\n")
377         }
378
379         if (success) {
380                 WNDCLASS wc;
381                 wc.style= CS_HREDRAW | CS_VREDRAW;
382                 wc.lpfnWndProc= s_wndProc;
383                 wc.cbClsExtra= 0;
384                 wc.cbWndExtra= 0;
385                 wc.hInstance= ::GetModuleHandle(0);
386                 wc.hIcon = ::LoadIcon(wc.hInstance, "APPICON");
387                 
388                 if (!wc.hIcon) {
389                         ::LoadIcon(NULL, IDI_APPLICATION);
390                 }
391                 wc.hCursor = ::LoadCursor(0, IDC_ARROW);
392                 wc.hbrBackground= (HBRUSH)::GetStockObject(BLACK_BRUSH);
393                 wc.lpszMenuName = 0;
394                 wc.lpszClassName= GHOST_WindowWin32::getWindowClassName();
395
396                 // Use RegisterClassEx for setting small icon
397                 if (::RegisterClass(&wc) == 0) {
398                         success = GHOST_kFailure;
399                 }
400                 
401                 // Add low-level keyboard hook for our process.
402                 m_llKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, s_llKeyboardProc, wc.hInstance, 0);
403         }
404         
405         return success;
406 }
407
408
409 GHOST_TSuccess GHOST_SystemWin32::exit()
410 {
411         // remove our low-level keyboard hook.
412         UnhookWindowsHookEx(m_llKeyboardHook);
413         
414         return GHOST_System::exit();
415 }
416
417 void GHOST_SystemWin32::triggerKey(GHOST_IWindow *window, bool down, GHOST_TKey key)
418 {
419         GHOST_Event *extra = new GHOST_EventKey(getSystem()->getMilliSeconds(), down ? GHOST_kEventKeyDown : GHOST_kEventKeyUp, window, key, '\0');
420         ((GHOST_SystemWin32*)getSystem())->pushEvent(extra);
421 }
422 void GHOST_SystemWin32::handleModifierKeys(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam, GHOST_ModifierKeys &oldModifiers, GHOST_ModifierKeys &newModifiers) const
423 {
424         switch(wParam) {
425                 case VK_SHIFT:
426                         {
427                                 bool lchanged = oldModifiers.get(GHOST_kModifierKeyLeftAlt) != newModifiers.get(GHOST_kModifierKeyLeftAlt);
428                                 if(lchanged) {
429                                         ((GHOST_SystemWin32*)getSystem())->triggerKey(window, newModifiers.get(GHOST_kModifierKeyLeftAlt), GHOST_kKeyLeftAlt);
430                                 } else {
431                                         bool rchanged = oldModifiers.get(GHOST_kModifierKeyRightAlt) != newModifiers.get(GHOST_kModifierKeyRightAlt);
432                                         if (rchanged) {
433                                                 ((GHOST_SystemWin32*)getSystem())->triggerKey(window, newModifiers.get(GHOST_kModifierKeyRightAlt), GHOST_kKeyRightAlt);
434                                         }
435                                 }
436                                 lchanged = oldModifiers.get(GHOST_kModifierKeyLeftControl) != newModifiers.get(GHOST_kModifierKeyLeftControl);
437                                 if(lchanged) {
438                                         ((GHOST_SystemWin32*)getSystem())->triggerKey(window, newModifiers.get(GHOST_kModifierKeyLeftControl), GHOST_kKeyLeftControl);
439                                 } else {
440                                         bool rchanged = oldModifiers.get(GHOST_kModifierKeyRightControl) != newModifiers.get(GHOST_kModifierKeyRightControl);
441                                         if (rchanged) {
442                                                 ((GHOST_SystemWin32*)getSystem())->triggerKey(window, newModifiers.get(GHOST_kModifierKeyRightControl), GHOST_kKeyRightControl);
443                                         }
444                                 }
445                         }
446                         break;
447                 case VK_CONTROL:
448                         {
449                                 bool lchanged = oldModifiers.get(GHOST_kModifierKeyLeftAlt) != newModifiers.get(GHOST_kModifierKeyLeftAlt);
450                                 if(lchanged) {
451                                         ((GHOST_SystemWin32*)getSystem())->triggerKey(window, newModifiers.get(GHOST_kModifierKeyLeftAlt), GHOST_kKeyLeftAlt);
452                                 } else {
453                                         bool rchanged = oldModifiers.get(GHOST_kModifierKeyRightAlt) != newModifiers.get(GHOST_kModifierKeyRightAlt);
454                                         if (rchanged) {
455                                                 ((GHOST_SystemWin32*)getSystem())->triggerKey(window, newModifiers.get(GHOST_kModifierKeyRightAlt), GHOST_kKeyRightAlt);
456                                         }
457                                 }
458                                 lchanged = oldModifiers.get(GHOST_kModifierKeyLeftShift) != newModifiers.get(GHOST_kModifierKeyLeftShift);
459                                 if(lchanged) {
460                                         ((GHOST_SystemWin32*)getSystem())->triggerKey(window, newModifiers.get(GHOST_kModifierKeyLeftShift), GHOST_kKeyLeftShift);
461                                 } else {
462                                         bool rchanged = oldModifiers.get(GHOST_kModifierKeyRightShift) != newModifiers.get(GHOST_kModifierKeyRightShift);
463                                         if (rchanged) {
464                                                 ((GHOST_SystemWin32*)getSystem())->triggerKey(window, newModifiers.get(GHOST_kModifierKeyRightShift), GHOST_kKeyRightShift);
465                                         }
466                                 }
467                         }
468                         break;
469                 case VK_MENU:
470                         {
471                                 bool lchanged = oldModifiers.get(GHOST_kModifierKeyLeftShift) != newModifiers.get(GHOST_kModifierKeyLeftShift);
472                                 if(lchanged) {
473                                         ((GHOST_SystemWin32*)getSystem())->triggerKey(window, newModifiers.get(GHOST_kModifierKeyLeftShift), GHOST_kKeyLeftShift);
474                                 } else {
475                                         bool rchanged = oldModifiers.get(GHOST_kModifierKeyRightShift) != newModifiers.get(GHOST_kModifierKeyRightShift);
476                                         if (rchanged) {
477                                                 ((GHOST_SystemWin32*)getSystem())->triggerKey(window, newModifiers.get(GHOST_kModifierKeyRightShift), GHOST_kKeyRightShift);
478                                         }
479                                 }
480                                 lchanged = oldModifiers.get(GHOST_kModifierKeyLeftControl) != newModifiers.get(GHOST_kModifierKeyLeftControl);
481                                 if(lchanged) {
482                                         ((GHOST_SystemWin32*)getSystem())->triggerKey(window, newModifiers.get(GHOST_kModifierKeyLeftControl), GHOST_kKeyLeftControl);
483                                 } else {
484                                         bool rchanged = oldModifiers.get(GHOST_kModifierKeyRightControl) != newModifiers.get(GHOST_kModifierKeyRightControl);
485                                         if (rchanged) {
486                                                 ((GHOST_SystemWin32*)getSystem())->triggerKey(window, newModifiers.get(GHOST_kModifierKeyRightControl), GHOST_kKeyRightControl);
487                                         }
488                                 }
489                         }
490                         break;
491                 default:
492                         break;
493         }
494 }
495
496 //! note: this function can be extended to include other exotic cases as they arise.
497 // This function was added in response to bug [#25715]
498 GHOST_TKey GHOST_SystemWin32::processSpecialKey(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam) const
499 {
500         GHOST_TKey key = GHOST_kKeyUnknown;
501         switch(PRIMARYLANGID(m_langId)) {
502                 case LANG_FRENCH:
503                         if(wParam==VK_OEM_8) key = GHOST_kKey1; // on 'normal' shift + 1 to create '!' we also get GHOST_kKey1. ASCII will be '!'.
504                         break;
505         }
506
507         return key;
508 }
509
510 GHOST_TKey GHOST_SystemWin32::convertKey(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam) const
511 {
512         GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
513         bool isExtended = (lParam&(1<<24))?true:false;
514         
515         GHOST_TKey key;
516         GHOST_ModifierKeys oldModifiers, newModifiers;
517         system->retrieveModifierKeys(oldModifiers);
518         system->getModifierKeys(newModifiers);
519
520         //std::cout << wParam << " " << system->m_curKeyStatus[wParam] << " shift pressed: " << system->shiftPressed() << std::endl;
521
522         if ((wParam >= '0') && (wParam <= '9')) {
523                 // VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39)
524                 key = (GHOST_TKey)(wParam - '0' + GHOST_kKey0);
525         }
526         else if ((wParam >= 'A') && (wParam <= 'Z')) {
527                 // VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A)
528                 key = (GHOST_TKey)(wParam - 'A' + GHOST_kKeyA);
529         }
530         else if ((wParam >= VK_F1) && (wParam <= VK_F24)) {
531                 key = (GHOST_TKey)(wParam - VK_F1 + GHOST_kKeyF1);
532         }
533         else {
534                 switch (wParam) {
535                 case VK_RETURN:
536                         key = isExtended?GHOST_kKeyNumpadEnter:GHOST_kKeyEnter;
537                         break;
538
539                 case VK_BACK:     key = GHOST_kKeyBackSpace;            break;
540                 case VK_TAB:      key = GHOST_kKeyTab;                          break;
541                 case VK_ESCAPE:   key = GHOST_kKeyEsc;                          break;
542                 case VK_SPACE:    key = GHOST_kKeySpace;                        break;
543                 case VK_PRIOR:    key = GHOST_kKeyUpPage;                       break;
544                 case VK_NEXT:     key = GHOST_kKeyDownPage;                     break;
545                 case VK_END:      key = GHOST_kKeyEnd;                          break;
546                 case VK_HOME:
547                         {
548                                 if(system->m_curKeyStatus[VK_NUMPAD7] && system->shiftPressed())
549                                         key = GHOST_kKeyNumpad7;
550                                 else
551                                         key = GHOST_kKeyHome;
552                         }
553                         break;
554                 case VK_INSERT:   key = GHOST_kKeyInsert;                       break;
555                 case VK_DELETE:   key = GHOST_kKeyDelete;                       break;
556                 case VK_LEFT:     key = GHOST_kKeyLeftArrow;            break;
557                 case VK_RIGHT:    key = GHOST_kKeyRightArrow;           break;
558                 case VK_UP:       key = GHOST_kKeyUpArrow;                      break;
559                 case VK_DOWN:     key = GHOST_kKeyDownArrow;            break;
560                 case VK_NUMPAD0:  key = GHOST_kKeyNumpad0;                      break;
561                 case VK_NUMPAD1:  key = GHOST_kKeyNumpad1;                      break;
562                 case VK_NUMPAD2:  key = GHOST_kKeyNumpad2;                      break;
563                 case VK_NUMPAD3:  key = GHOST_kKeyNumpad3;                      break;
564                 case VK_NUMPAD4:  key = GHOST_kKeyNumpad4;                      break;
565                 case VK_NUMPAD5:  key = GHOST_kKeyNumpad5;                      break;
566                 case VK_NUMPAD6:  key = GHOST_kKeyNumpad6;                      break;
567                 case VK_NUMPAD7:  key = GHOST_kKeyNumpad7;                      break;
568                 case VK_NUMPAD8:  key = GHOST_kKeyNumpad8;                      break;
569                 case VK_NUMPAD9:  key = GHOST_kKeyNumpad9;                      break;
570                 case VK_SNAPSHOT: key = GHOST_kKeyPrintScreen;          break;
571                 case VK_PAUSE:    key = GHOST_kKeyPause;                        break;
572                 case VK_MULTIPLY: key = GHOST_kKeyNumpadAsterisk;        break;
573                 case VK_SUBTRACT: key = GHOST_kKeyNumpadMinus;          break;
574                 case VK_DECIMAL:  key = GHOST_kKeyNumpadPeriod;         break;
575                 case VK_DIVIDE:   key = GHOST_kKeyNumpadSlash;          break;
576                 case VK_ADD:      key = GHOST_kKeyNumpadPlus;           break;
577
578                 case VK_SEMICOLON:              key = GHOST_kKeySemicolon;              break;
579                 case VK_EQUALS:                 key = GHOST_kKeyEqual;                  break;
580                 case VK_COMMA:                  key = GHOST_kKeyComma;                  break;
581                 case VK_MINUS:                  key = GHOST_kKeyMinus;                  break;
582                 case VK_PERIOD:                 key = GHOST_kKeyPeriod;                 break;
583                 case VK_SLASH:                  key = GHOST_kKeySlash;                  break;
584                 case VK_BACK_QUOTE:             key = GHOST_kKeyAccentGrave;    break;
585                 case VK_OPEN_BRACKET:   key = GHOST_kKeyLeftBracket;    break;
586                 case VK_BACK_SLASH:             key = GHOST_kKeyBackslash;              break;
587                 case VK_CLOSE_BRACKET:  key = GHOST_kKeyRightBracket;   break;
588                 case VK_QUOTE:                  key = GHOST_kKeyQuote;                  break;
589                 case VK_GR_LESS:                key = GHOST_kKeyGrLess;                 break;
590
591                 case VK_SHIFT:
592                         {
593                                 bool lchanged = oldModifiers.get(GHOST_kModifierKeyLeftShift) != newModifiers.get(GHOST_kModifierKeyLeftShift);
594                                 if(lchanged) {
595                                         key = GHOST_kKeyLeftShift;
596                                 } else {
597                                         bool rchanged = oldModifiers.get(GHOST_kModifierKeyRightShift) != newModifiers.get(GHOST_kModifierKeyRightShift);
598                                         if(rchanged) {
599                                                 key = GHOST_kKeyRightShift;
600                                         } else {
601                                                 key = GHOST_kKeyUnknown;
602                                         }
603                                 }
604                         }
605                         break;
606                 case VK_CONTROL:
607                         {
608                                 bool lchanged = oldModifiers.get(GHOST_kModifierKeyLeftControl) != newModifiers.get(GHOST_kModifierKeyLeftControl);
609                                 if(lchanged) {
610                                         key = GHOST_kKeyLeftControl;
611                                 } else {
612                                         bool rchanged = oldModifiers.get(GHOST_kModifierKeyRightControl) != newModifiers.get(GHOST_kModifierKeyRightControl);
613                                         if(rchanged) {
614                                                 key = GHOST_kKeyRightControl;
615                                         } else {
616                                                 key = GHOST_kKeyUnknown;
617                                         }
618                                 }
619                         }
620                         break;
621                 case VK_MENU:
622                         {
623                                 if(m_hasAltGr && isExtended) {
624                                         // We have here an extended RAlt, which is AltGr. The keyboard driver on Windows sends before this a LControl, so
625                                         // to be able to input characters created with AltGr (normal on German, French, Finnish and other keyboards) we
626                                         // push an extra LControl up event. This ensures we don't have a 'hanging' ctrl event in Blender windowmanager
627                                         // when typing in Text editor or Console.
628                                         GHOST_Event *extra = new GHOST_EventKey(getSystem()->getMilliSeconds(), GHOST_kEventKeyUp, window, GHOST_kKeyLeftControl, '\0');
629                                         ((GHOST_SystemWin32*)getSystem())->pushEvent(extra);
630                                         newModifiers.set(GHOST_kModifierKeyRightControl, false);
631                                         newModifiers.set(GHOST_kModifierKeyLeftControl, false);
632                                 }
633                                 bool lchanged = oldModifiers.get(GHOST_kModifierKeyLeftAlt) != newModifiers.get(GHOST_kModifierKeyLeftAlt);
634                                 if(lchanged) {
635                                         key = GHOST_kKeyLeftAlt;
636                                 } else {
637                                         bool rchanged = oldModifiers.get(GHOST_kModifierKeyRightAlt) != newModifiers.get(GHOST_kModifierKeyRightAlt);
638                                         if(rchanged) {
639                                                 key = GHOST_kKeyRightAlt;
640                                         } else {
641                                                 key = GHOST_kKeyUnknown;
642                                         }
643                                 }
644                         }
645                         break;
646                 case VK_LWIN:
647                 case VK_RWIN:
648                         key = GHOST_kKeyOS;
649                         break;
650                 case VK_NUMLOCK: key = GHOST_kKeyNumLock; break;
651                 case VK_SCROLL: key = GHOST_kKeyScrollLock; break;
652                 case VK_CAPITAL: key = GHOST_kKeyCapsLock; break;
653                 case VK_OEM_8:
654                         key = ((GHOST_SystemWin32*)getSystem())->processSpecialKey(window, wParam, lParam);
655                         break;
656                 case VK_MEDIA_PLAY_PAUSE: key = GHOST_kKeyMediaPlay; break;
657                 case VK_MEDIA_STOP: key = GHOST_kKeyMediaStop; break;
658                 case VK_MEDIA_PREV_TRACK: key = GHOST_kKeyMediaFirst; break;
659                 case VK_MEDIA_NEXT_TRACK: key = GHOST_kKeyMediaLast; break;
660                 default:
661                         key = GHOST_kKeyUnknown;
662                         break;
663                 }
664         }
665         ((GHOST_SystemWin32*)getSystem())->storeModifierKeys(newModifiers);
666         return key;
667 }
668
669 GHOST_EventButton* GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, GHOST_IWindow *window, GHOST_TButtonMask mask)
670 {
671         return new GHOST_EventButton (getSystem()->getMilliSeconds(), type, window, mask);
672 }
673
674
675 GHOST_EventCursor* GHOST_SystemWin32::processCursorEvent(GHOST_TEventType type, GHOST_IWindow *Iwindow)
676 {
677         GHOST_TInt32 x_screen, y_screen;
678         GHOST_SystemWin32 * system = ((GHOST_SystemWin32 * ) getSystem());
679         GHOST_WindowWin32 * window = ( GHOST_WindowWin32 * ) Iwindow;
680         
681         system->getCursorPosition(x_screen, y_screen);
682
683         if(window->getCursorGrabMode() != GHOST_kGrabDisable && window->getCursorGrabMode() != GHOST_kGrabNormal)
684         {
685                 GHOST_TInt32 x_new= x_screen;
686                 GHOST_TInt32 y_new= y_screen;
687                 GHOST_TInt32 x_accum, y_accum;
688                 GHOST_Rect bounds;
689
690                 /* fallback to window bounds */
691                 if(window->getCursorGrabBounds(bounds)==GHOST_kFailure){
692                         window->getClientBounds(bounds);
693                 }
694
695                 /* could also clamp to screen bounds
696                  * wrap with a window outside the view will fail atm  */
697
698                 bounds.wrapPoint(x_new, y_new, 2); /* offset of one incase blender is at screen bounds */
699
700                 window->getCursorGrabAccum(x_accum, y_accum);
701                 if(x_new != x_screen|| y_new != y_screen) {
702                         /* when wrapping we don't need to add an event because the
703                          * setCursorPosition call will cause a new event after */
704                         system->setCursorPosition(x_new, y_new); /* wrap */
705                         window->setCursorGrabAccum(x_accum + (x_screen - x_new), y_accum + (y_screen - y_new));
706                 }else{
707                         return new GHOST_EventCursor(system->getMilliSeconds(),
708                                                                                  GHOST_kEventCursorMove,
709                                                                                  window,
710                                                                                  x_screen + x_accum,
711                                                                                  y_screen + y_accum
712                         );
713                 }
714
715         }
716         else {
717                 return new GHOST_EventCursor(system->getMilliSeconds(),
718                                                                          GHOST_kEventCursorMove,
719                                                                          window,
720                                                                          x_screen,
721                                                                          y_screen
722                 );
723         }
724         return NULL;
725 }
726
727
728 GHOST_EventWheel* GHOST_SystemWin32::processWheelEvent(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam)
729 {
730         // short fwKeys = LOWORD(wParam);                       // key flags
731         int zDelta = (short) HIWORD(wParam);    // wheel rotation
732         
733         // zDelta /= WHEEL_DELTA;
734         // temporary fix below: microsoft now has added more precision, making the above division not work
735         if (zDelta <= 0 ) zDelta= -1; else zDelta= 1;   
736         
737         // short xPos = (short) LOWORD(lParam); // horizontal position of pointer
738         // short yPos = (short) HIWORD(lParam); // vertical position of pointer
739         return new GHOST_EventWheel (getSystem()->getMilliSeconds(), window, zDelta);
740 }
741
742
743 GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, bool keyDown, WPARAM wParam, LPARAM lParam)
744 {
745         GHOST_TKey key = ((GHOST_SystemWin32*)getSystem())->convertKey(window, wParam, lParam);
746         GHOST_EventKey* event;
747         if (key != GHOST_kKeyUnknown) {
748                 MSG keyMsg;
749                 char ascii = '\0';
750
751                         /* Eat any character related messages */
752                 if (::PeekMessage(&keyMsg, NULL, WM_CHAR, WM_SYSDEADCHAR, PM_REMOVE)) {
753                         ascii = (char) keyMsg.wParam;
754                         
755                 }
756
757                 event = new GHOST_EventKey(getSystem()->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key, ascii);
758                 
759 #ifdef BF_GHOST_DEBUG
760                 std::cout << ascii << std::endl;
761 #endif
762         }
763         else {
764                 event = 0;
765         }
766         return event;
767 }
768
769
770 GHOST_Event* GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type, GHOST_IWindow* window)
771 {
772         return new GHOST_Event(getSystem()->getMilliSeconds(), type, window);
773 }
774
775 GHOST_TSuccess GHOST_SystemWin32::pushDragDropEvent(GHOST_TEventType eventType, 
776                                                                                                         GHOST_TDragnDropTypes draggedObjectType,
777                                                                                                         GHOST_IWindow* window,
778                                                                                                         int mouseX, int mouseY,
779                                                                                                         void* data)
780 {
781         GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem());
782         return system->pushEvent(new GHOST_EventDragnDrop(system->getMilliSeconds(),
783                                                                                                           eventType,
784                                                                                                           draggedObjectType,
785                                                                                                           window,mouseX,mouseY,data)
786                         );
787 }
788
789 void GHOST_SystemWin32::processMinMaxInfo(MINMAXINFO * minmax)
790 {
791         minmax->ptMinTrackSize.x=320;
792         minmax->ptMinTrackSize.y=240;
793 }
794
795 /* Note that this function gets *all* key events from the entire system (all
796  * threads running in this desktop session. So when getting event here, don't assume
797  * it's for Blender. Thus we only do status bookkeeping, so we can check
798  * in s_wndProc and processKeyEvent what the real keyboard status is.
799  * This is needed for proper handling of shift+numpad keys for instance.
800  */
801 LRESULT CALLBACK GHOST_SystemWin32::s_llKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
802 {
803         GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem());
804         
805         bool down = false;
806         if(wParam==WM_KEYDOWN || wParam==WM_SYSKEYDOWN ){
807                 down = true;
808         }
809         
810         if(nCode!=HC_ACTION)
811                 return CallNextHookEx(system->m_llKeyboardHook, nCode, wParam, lParam);
812                 
813         KBDLLHOOKSTRUCT &keyb = *(PKBDLLHOOKSTRUCT)(lParam);
814         system->m_prevKeyStatus[keyb.vkCode] = system->m_curKeyStatus[keyb.vkCode];
815         //std::cout << "ll: " << keyb.vkCode << " " << down << " ||| ";
816         if(keyb.flags) {
817                 if((keyb.flags & LLKHF_EXTENDED) == LLKHF_EXTENDED) {
818                         //std::cout << "extended ";
819                 }
820                 if((keyb.flags & LLKHF_ALTDOWN) == LLKHF_ALTDOWN) {
821                         //std::cout << "alt ";
822                 }
823                 if((keyb.flags & LLKHF_INJECTED)== LLKHF_INJECTED) {
824                         //std::cout << "injected ";
825                 }
826                 if((keyb.flags & LLKHF_UP) == LLKHF_UP) {
827                         system->m_curKeyStatus[keyb.vkCode] = false;
828                         //std::cout << "up" << std::endl;
829                 } else {
830                         system->m_curKeyStatus[keyb.vkCode] = true;
831                         //std::cout << "down" << std::endl;
832                 }
833         }
834         else {
835                 system->m_curKeyStatus[keyb.vkCode] = true;
836                 //std::cout << "down" << std::endl;
837         }
838         
839         return CallNextHookEx(system->m_llKeyboardHook, nCode, wParam, lParam);
840 }
841
842 LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
843 {
844         GHOST_Event* event = 0;
845         LRESULT lResult = 0;
846         GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem());
847         GHOST_ASSERT(system, "GHOST_SystemWin32::s_wndProc(): system not initialized")
848
849         if (hwnd) {
850                 GHOST_WindowWin32* window = (GHOST_WindowWin32*)::GetWindowLong(hwnd, GWL_USERDATA);
851                 if (window) {
852                         switch (msg) {
853                                 // we need to check if new key layout has AltGr
854                                 case WM_INPUTLANGCHANGE:
855                                         system->handleKeyboardChange();
856                                         break;
857                                 ////////////////////////////////////////////////////////////////////////
858                                 // Keyboard events, processed
859                                 ////////////////////////////////////////////////////////////////////////
860                                 case WM_KEYDOWN:
861                                 case WM_SYSKEYDOWN:
862                                         event = processKeyEvent(window, true, wParam, lParam);
863                                         if (!event) {
864                                                 GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
865                                                 GHOST_PRINT(msg)
866                                                 GHOST_PRINT(" key ignored\n")
867                                         }
868                                         break;
869
870                                 case WM_KEYUP:
871                                 case WM_SYSKEYUP:
872                                         event = processKeyEvent(window, false, wParam, lParam);
873                                         if (!event) {
874                                                 GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
875                                                 GHOST_PRINT(msg)
876                                                 GHOST_PRINT(" key ignored\n")
877                                         }
878                                         break;
879
880                                 ////////////////////////////////////////////////////////////////////////
881                                 // Keyboard events, ignored
882                                 ////////////////////////////////////////////////////////////////////////
883                                 case WM_CHAR:
884                                         /* The WM_CHAR message is posted to the window with the keyboard focus when 
885                                          * a WM_KEYDOWN message is translated by the TranslateMessage function. WM_CHAR 
886                                          * contains the character code of the key that was pressed. 
887                                          */
888                                 case WM_DEADCHAR:
889                                         /* The WM_DEADCHAR message is posted to the window with the keyboard focus when a
890                                          * WM_KEYUP message is translated by the TranslateMessage function. WM_DEADCHAR 
891                                          * specifies a character code generated by a dead key. A dead key is a key that 
892                                          * generates a character, such as the umlaut (double-dot), that is combined with 
893                                          * another character to form a composite character. For example, the umlaut-O 
894                                          * character (Ö) is generated by typing the dead key for the umlaut character, and
895                                          * then typing the O key.
896                                          */
897                                 case WM_SYSDEADCHAR:
898                                         /* The WM_SYSDEADCHAR message is sent to the window with the keyboard focus when 
899                                          * a WM_SYSKEYDOWN message is translated by the TranslateMessage function. 
900                                          * WM_SYSDEADCHAR specifies the character code of a system dead key - that is, 
901                                          * a dead key that is pressed while holding down the alt key. 
902                                          */
903                                         break;
904                                 ////////////////////////////////////////////////////////////////////////
905                                 // Tablet events, processed
906                                 ////////////////////////////////////////////////////////////////////////
907                                 case WT_PACKET:
908                                         ((GHOST_WindowWin32*)window)->processWin32TabletEvent(wParam, lParam);
909                                         break;
910                                 case WT_CSRCHANGE:
911                                 case WT_PROXIMITY:
912                                         ((GHOST_WindowWin32*)window)->processWin32TabletInitEvent();
913                                         break;
914                                 ////////////////////////////////////////////////////////////////////////
915                                 // Mouse events, processed
916                                 ////////////////////////////////////////////////////////////////////////
917                                 case WM_LBUTTONDOWN:
918                                         window->registerMouseClickEvent(true);
919                                         event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft);
920                                         break;
921                                 case WM_MBUTTONDOWN:
922                                         window->registerMouseClickEvent(true);
923                                         event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskMiddle);
924                                         break;
925                                 case WM_RBUTTONDOWN:
926                                         window->registerMouseClickEvent(true);
927                                         event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight);
928                                         break;
929                                 case WM_XBUTTONDOWN:
930                                         window->registerMouseClickEvent(true);
931                                         if ((short) HIWORD(wParam) == XBUTTON1){
932                                                 event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton4);
933                                         }else if((short) HIWORD(wParam) == XBUTTON2){
934                                                 event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton5);
935                                         }
936                                         break;
937                                 case WM_LBUTTONUP:
938                                         window->registerMouseClickEvent(false);
939                                         event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft);
940                                         break;
941                                 case WM_MBUTTONUP:
942                                         window->registerMouseClickEvent(false);
943                                         event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskMiddle);
944                                         break;
945                                 case WM_RBUTTONUP:
946                                         window->registerMouseClickEvent(false);
947                                         event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight);
948                                         break;
949                                 case WM_XBUTTONUP:
950                                         window->registerMouseClickEvent(false);
951                                         if ((short) HIWORD(wParam) == XBUTTON1){
952                                                 event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton4);
953                                         }else if((short) HIWORD(wParam) == XBUTTON2){
954                                                 event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton5);
955                                         }
956                                         break;
957                                 case WM_MOUSEMOVE:
958                                         event = processCursorEvent(GHOST_kEventCursorMove, window);
959                                         break;
960                                 case WM_MOUSEWHEEL:
961                                         /* The WM_MOUSEWHEEL message is sent to the focus window 
962                                          * when the mouse wheel is rotated. The DefWindowProc 
963                                          * function propagates the message to the window's parent.
964                                          * There should be no internal forwarding of the message, 
965                                          * since DefWindowProc propagates it up the parent chain 
966                                          * until it finds a window that processes it.
967                                          */
968                                         event = processWheelEvent(window, wParam, lParam);
969                                         break;
970                                 case WM_SETCURSOR:
971                                         /* The WM_SETCURSOR message is sent to a window if the mouse causes the cursor
972                                          * to move within a window and mouse input is not captured.
973                                          * This means we have to set the cursor shape every time the mouse moves!
974                                          * The DefWindowProc function uses this message to set the cursor to an 
975                                          * arrow if it is not in the client area.
976                                          */
977                                         if (LOWORD(lParam) == HTCLIENT) {
978                                                 // Load the current cursor
979                                                 window->loadCursor(window->getCursorVisibility(), window->getCursorShape());
980                                                 // Bypass call to DefWindowProc
981                                                 return 0;
982                                         } 
983                                         else {
984                                                 // Outside of client area show standard cursor
985                                                 window->loadCursor(true, GHOST_kStandardCursorDefault);
986                                         }
987                                         break;
988
989                                 ////////////////////////////////////////////////////////////////////////
990                                 // Mouse events, ignored
991                                 ////////////////////////////////////////////////////////////////////////
992                                 case WM_NCMOUSEMOVE:
993                                         /* The WM_NCMOUSEMOVE message is posted to a window when the cursor is moved 
994                                          * within the nonclient area of the window. This message is posted to the window 
995                                          * that contains the cursor. If a window has captured the mouse, this message is not posted.
996                                          */
997                                 case WM_NCHITTEST:
998                                         /* The WM_NCHITTEST message is sent to a window when the cursor moves, or 
999                                          * when a mouse button is pressed or released. If the mouse is not captured, 
1000                                          * the message is sent to the window beneath the cursor. Otherwise, the message 
1001                                          * is sent to the window that has captured the mouse. 
1002                                          */
1003                                         break;
1004
1005                                 ////////////////////////////////////////////////////////////////////////
1006                                 // Window events, processed
1007                                 ////////////////////////////////////////////////////////////////////////
1008                                 case WM_CLOSE:
1009                                         /* The WM_CLOSE message is sent as a signal that a window or an application should terminate. */
1010                                         event = processWindowEvent(GHOST_kEventWindowClose, window);
1011                                         break;
1012                                 case WM_ACTIVATE:
1013                                         /* The WM_ACTIVATE message is sent to both the window being activated and the window being 
1014                                          * deactivated. If the windows use the same input queue, the message is sent synchronously, 
1015                                          * first to the window procedure of the top-level window being deactivated, then to the window
1016                                          * procedure of the top-level window being activated. If the windows use different input queues,
1017                                          * the message is sent asynchronously, so the window is activated immediately. 
1018                                          */
1019                                         event = processWindowEvent(LOWORD(wParam) ? GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate, window);
1020                                         /* WARNING: Let DefWindowProc handle WM_ACTIVATE, otherwise WM_MOUSEWHEEL
1021                                         will not be dispatched to OUR active window if we minimize one of OUR windows. */
1022                                         lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
1023                                         break;
1024                                 case WM_PAINT:
1025                                         /* An application sends the WM_PAINT message when the system or another application 
1026                                          * makes a request to paint a portion of an application's window. The message is sent
1027                                          * when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage 
1028                                          * function when the application obtains a WM_PAINT message by using the GetMessage or 
1029                                          * PeekMessage function. 
1030                                          */
1031                                         event = processWindowEvent(GHOST_kEventWindowUpdate, window);
1032                                         ::ValidateRect(hwnd, NULL);
1033                                         break;
1034                                 case WM_GETMINMAXINFO:
1035                                         /* The WM_GETMINMAXINFO message is sent to a window when the size or 
1036                                          * position of the window is about to change. An application can use 
1037                                          * this message to override the window's default maximized size and 
1038                                          * position, or its default minimum or maximum tracking size. 
1039                                          */
1040                                         processMinMaxInfo((MINMAXINFO *) lParam);
1041                                         /* Let DefWindowProc handle it. */
1042                                         break;
1043                                 case WM_SIZE:
1044                                         /* The WM_SIZE message is sent to a window after its size has changed.
1045                                          * The WM_SIZE and WM_MOVE messages are not sent if an application handles the 
1046                                          * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
1047                                          * to perform any move or size change processing during the WM_WINDOWPOSCHANGED 
1048                                          * message without calling DefWindowProc.
1049                                          */
1050                                         event = processWindowEvent(GHOST_kEventWindowSize, window);
1051                                         break;
1052                                 case WM_CAPTURECHANGED:
1053                                         window->lostMouseCapture();
1054                                         break;
1055                                 case WM_MOVING:
1056                                         /* The WM_MOVING message is sent to a window that the user is moving. By processing 
1057                                          * this message, an application can monitor the size and position of the drag rectangle
1058                                          * and, if needed, change its size or position.
1059                                          */
1060                                 case WM_MOVE:
1061                                         /* The WM_SIZE and WM_MOVE messages are not sent if an application handles the 
1062                                          * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
1063                                          * to perform any move or size change processing during the WM_WINDOWPOSCHANGED 
1064                                          * message without calling DefWindowProc. 
1065                                          */
1066                                         event = processWindowEvent(GHOST_kEventWindowMove, window);
1067                                         break;
1068                                 ////////////////////////////////////////////////////////////////////////
1069                                 // Window events, ignored
1070                                 ////////////////////////////////////////////////////////////////////////
1071                                 case WM_WINDOWPOSCHANGED:
1072                                         /* The WM_WINDOWPOSCHANGED message is sent to a window whose size, position, or place
1073                                          * in the Z order has changed as a result of a call to the SetWindowPos function or 
1074                                          * another window-management function.
1075                                          * The WM_SIZE and WM_MOVE messages are not sent if an application handles the 
1076                                          * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
1077                                          * to perform any move or size change processing during the WM_WINDOWPOSCHANGED 
1078                                          * message without calling DefWindowProc.
1079                                          */
1080                                 case WM_ERASEBKGND:
1081                                         /* An application sends the WM_ERASEBKGND message when the window background must be 
1082                                          * erased (for example, when a window is resized). The message is sent to prepare an 
1083                                          * invalidated portion of a window for painting. 
1084                                          */
1085                                 case WM_NCPAINT:
1086                                         /* An application sends the WM_NCPAINT message to a window when its frame must be painted. */
1087                                 case WM_NCACTIVATE:
1088                                         /* The WM_NCACTIVATE message is sent to a window when its nonclient area needs to be changed 
1089                                          * to indicate an active or inactive state. 
1090                                          */
1091                                 case WM_DESTROY:
1092                                         /* The WM_DESTROY message is sent when a window is being destroyed. It is sent to the window 
1093                                          * procedure of the window being destroyed after the window is removed from the screen. 
1094                                          * This message is sent first to the window being destroyed and then to the child windows 
1095                                          * (if any) as they are destroyed. During the processing of the message, it can be assumed 
1096                                          * that all child windows still exist. 
1097                                          */
1098                                 case WM_NCDESTROY:
1099                                         /* The WM_NCDESTROY message informs a window that its nonclient area is being destroyed. The 
1100                                          * DestroyWindow function sends the WM_NCDESTROY message to the window following the WM_DESTROY
1101                                          * message. WM_DESTROY is used to free the allocated memory object associated with the window. 
1102                                          */
1103                                 case WM_KILLFOCUS:
1104                                         /* The WM_KILLFOCUS message is sent to a window immediately before it loses the keyboard focus. */
1105                                 case WM_SHOWWINDOW:
1106                                         /* The WM_SHOWWINDOW message is sent to a window when the window is about to be hidden or shown. */
1107                                 case WM_WINDOWPOSCHANGING:
1108                                         /* The WM_WINDOWPOSCHANGING message is sent to a window whose size, position, or place in 
1109                                          * the Z order is about to change as a result of a call to the SetWindowPos function or 
1110                                          * another window-management function. 
1111                                          */
1112                                 case WM_SETFOCUS:
1113                                         /* The WM_SETFOCUS message is sent to a window after it has gained the keyboard focus. */
1114                                 case WM_ENTERSIZEMOVE:
1115                                         /* The WM_ENTERSIZEMOVE message is sent one time to a window after it enters the moving 
1116                                          * or sizing modal loop. The window enters the moving or sizing modal loop when the user 
1117                                          * clicks the window's title bar or sizing border, or when the window passes the 
1118                                          * WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the 
1119                                          * message specifies the SC_MOVE or SC_SIZE value. The operation is complete when 
1120                                          * DefWindowProc returns. 
1121                                          */
1122                                         break;
1123                                         
1124                                 ////////////////////////////////////////////////////////////////////////
1125                                 // Other events
1126                                 ////////////////////////////////////////////////////////////////////////
1127                                 case WM_GETTEXT:
1128                                         /* An application sends a WM_GETTEXT message to copy the text that 
1129                                          * corresponds to a window into a buffer provided by the caller. 
1130                                          */
1131                                 case WM_ACTIVATEAPP:
1132                                         /* The WM_ACTIVATEAPP message is sent when a window belonging to a 
1133                                          * different application than the active window is about to be activated.
1134                                          * The message is sent to the application whose window is being activated
1135                                          * and to the application whose window is being deactivated. 
1136                                          */
1137                                 case WM_TIMER:
1138                                         /* The WIN32 docs say:
1139                                          * The WM_TIMER message is posted to the installing thread's message queue
1140                                          * when a timer expires. You can process the message by providing a WM_TIMER
1141                                          * case in the window procedure. Otherwise, the default window procedure will
1142                                          * call the TimerProc callback function specified in the call to the SetTimer
1143                                          * function used to install the timer. 
1144                                          *
1145                                          * In GHOST, we let DefWindowProc call the timer callback.
1146                                          */
1147                                         break;
1148                                 case WM_BLND_NDOF_AXIS:
1149                                         {
1150                                                 GHOST_TEventNDOFData ndofdata;
1151                                                 system->m_ndofManager->GHOST_NDOFGetDatas(ndofdata);
1152                                                 system->m_eventManager->
1153                                                         pushEvent(new GHOST_EventNDOF(
1154                                                                 system->getMilliSeconds(), 
1155                                                                 GHOST_kEventNDOFMotion, 
1156                                                                 window, ndofdata));
1157                                         }
1158                                         break;
1159                                 case WM_BLND_NDOF_BTN:
1160                                         {
1161                                                 GHOST_TEventNDOFData ndofdata;
1162                                                 system->m_ndofManager->GHOST_NDOFGetDatas(ndofdata);
1163                                                 system->m_eventManager->
1164                                                         pushEvent(new GHOST_EventNDOF(
1165                                                                 system->getMilliSeconds(), 
1166                                                                 GHOST_kEventNDOFButton, 
1167                                                                 window, ndofdata));
1168                                         }
1169                                         break;
1170                         }
1171                 }
1172                 else {
1173                         // Event found for a window before the pointer to the class has been set.
1174                         GHOST_PRINT("GHOST_SystemWin32::wndProc: GHOST window event before creation\n")
1175                         /* These are events we typically miss at this point:
1176                            WM_GETMINMAXINFO     0x24
1177                            WM_NCCREATE                  0x81
1178                            WM_NCCALCSIZE                0x83
1179                            WM_CREATE                    0x01
1180                            We let DefWindowProc do the work.
1181                         */
1182                 }
1183         }
1184         else {
1185                 // Events without valid hwnd
1186                 GHOST_PRINT("GHOST_SystemWin32::wndProc: event without window\n")
1187         }
1188
1189         if (event) {
1190                 system->pushEvent(event);
1191         }
1192         else {
1193                 lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
1194         }
1195         return lResult;
1196 }
1197
1198 GHOST_TUns8* GHOST_SystemWin32::getClipboard(bool selection) const 
1199 {
1200         char *buffer;
1201         char *temp_buff;
1202         
1203         if ( IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(NULL) ) {
1204                 HANDLE hData = GetClipboardData( CF_TEXT );
1205                 if (hData == NULL) {
1206                         CloseClipboard();
1207                         return NULL;
1208                 }
1209                 buffer = (char*)GlobalLock( hData );
1210                 
1211                 temp_buff = (char*) malloc(strlen(buffer)+1);
1212                 strcpy(temp_buff, buffer);
1213                 
1214                 GlobalUnlock( hData );
1215                 CloseClipboard();
1216                 
1217                 temp_buff[strlen(buffer)] = '\0';
1218                 if (buffer) {
1219                         return (GHOST_TUns8*)temp_buff;
1220                 } else {
1221                         return NULL;
1222                 }
1223         } else {
1224                 return NULL;
1225         }
1226 }
1227
1228 void GHOST_SystemWin32::putClipboard(GHOST_TInt8 *buffer, bool selection) const
1229 {
1230         if(selection) {return;} // for copying the selection, used on X11
1231
1232         if (OpenClipboard(NULL)) {
1233                 HLOCAL clipbuffer;
1234                 char *data;
1235                 
1236                 if (buffer) {
1237                         EmptyClipboard();
1238                         
1239                         clipbuffer = LocalAlloc(LMEM_FIXED,((strlen(buffer)+1)));
1240                         data = (char*)GlobalLock(clipbuffer);
1241
1242                         strcpy(data, (char*)buffer);
1243                         data[strlen(buffer)] = '\0';
1244                         LocalUnlock(clipbuffer);
1245                         SetClipboardData(CF_TEXT,clipbuffer);
1246                 }
1247                 CloseClipboard();
1248         } else {
1249                 return;
1250         }
1251 }