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