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