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