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