more preliminary NDOF handling stuff (untested)
[blender.git] / intern / ghost / intern / GHOST_SystemWin32.cpp
1 /**
2  * $Id$
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22  * The Original Code is: all of this file.
23  *
24  * Contributor(s): none yet.
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 /**
30
31  * $Id$
32  * Copyright (C) 2001 NaN Technologies B.V.
33  * @author      Maarten Gribnau
34  * @date        May 7, 2001
35  */
36
37 #include "GHOST_SystemWin32.h"
38 #include "GHOST_EventDragnDrop.h"
39
40 #include <stdio.h> // for debug [mce]
41
42 // win64 doesn't define GWL_USERDATA
43 #ifdef WIN32
44 #ifndef GWL_USERDATA
45 #define GWL_USERDATA GWLP_USERDATA
46 #define GWL_WNDPROC GWLP_WNDPROC
47 #endif
48 #endif
49
50 /*
51  * According to the docs the mouse wheel message is supported from windows 98 
52  * upwards. Leaving WINVER at default value, the WM_MOUSEWHEEL message and the 
53  * wheel detent value are undefined.
54
55  [mce] able to remove this too?
56
57 #ifndef WM_MOUSEWHEEL
58 #define WM_MOUSEWHEEL 0x020A
59 #endif // WM_MOUSEWHEEL
60 #ifndef WHEEL_DELTA
61 #define WHEEL_DELTA 120 // Value for rolling one detent, (old convention! MS changed it)
62 #endif // WHEEL_DELTA
63  */
64
65 #include "GHOST_Debug.h"
66 #include "GHOST_DisplayManagerWin32.h"
67 #include "GHOST_EventButton.h"
68 #include "GHOST_EventCursor.h"
69 #include "GHOST_EventKey.h"
70 #include "GHOST_EventWheel.h"
71 #include "GHOST_EventNDOF.h"
72 #include "GHOST_TimerTask.h"
73 #include "GHOST_TimerManager.h"
74 #include "GHOST_WindowManager.h"
75 #include "GHOST_WindowWin32.h"
76 #include "GHOST_NDOFManagerWin32.h"
77
78 // Key code values not found in winuser.h
79 #ifndef VK_MINUS
80 #define VK_MINUS 0xBD
81 #endif // VK_MINUS
82 #ifndef VK_SEMICOLON
83 #define VK_SEMICOLON 0xBA
84 #endif // VK_SEMICOLON
85 #ifndef VK_PERIOD
86 #define VK_PERIOD 0xBE
87 #endif // VK_PERIOD
88 #ifndef VK_COMMA
89 #define VK_COMMA 0xBC
90 #endif // VK_COMMA
91 #ifndef VK_QUOTE
92 #define VK_QUOTE 0xDE
93 #endif // VK_QUOTE
94 #ifndef VK_BACK_QUOTE
95 #define VK_BACK_QUOTE 0xC0
96 #endif // VK_BACK_QUOTE
97 #ifndef VK_SLASH
98 #define VK_SLASH 0xBF
99 #endif // VK_SLASH
100 #ifndef VK_BACK_SLASH
101 #define VK_BACK_SLASH 0xDC
102 #endif // VK_BACK_SLASH
103 #ifndef VK_EQUALS
104 #define VK_EQUALS 0xBB
105 #endif // VK_EQUALS
106 #ifndef VK_OPEN_BRACKET
107 #define VK_OPEN_BRACKET 0xDB
108 #endif // VK_OPEN_BRACKET
109 #ifndef VK_CLOSE_BRACKET
110 #define VK_CLOSE_BRACKET 0xDD
111 #endif // VK_CLOSE_BRACKET
112 #ifndef VK_GR_LESS
113 #define VK_GR_LESS 0xE2
114 #endif // VK_GR_LESS
115
116
117 GHOST_SystemWin32::GHOST_SystemWin32()
118 : m_hasPerformanceCounter(false), m_freq(0), m_start(0),
119   m_separateLeftRight(false),
120   m_separateLeftRightInitialized(false)
121 {
122         m_displayManager = new GHOST_DisplayManagerWin32 ();
123         GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::GHOST_SystemWin32(): m_displayManager==0\n");
124         m_displayManager->initialize();
125
126         // Require COM for GHOST_DropTargetWin32 created in GHOST_WindowWin32.
127         OleInitialize(0);
128
129         m_input_fidelity_hint = HI_FI; // just for testing...
130
131         // register for RawInput devices
132         RAWINPUTDEVICE devices[1];
133 /*
134         // standard HID mouse
135         devices[0].usUsagePage = 0x01;
136         devices[0].usUsage = 0x02;
137         devices[0].dwFlags = 0; // RIDEV_NOLEGACY; // ignore legacy mouse messages
138         devices[0].hwndTarget = NULL;
139 */
140         // multi-axis mouse (SpaceNavigator)
141         devices[0].usUsagePage = 0x01;
142         devices[0].usUsage = 0x08;
143         devices[0].dwFlags = 0;
144         devices[0].hwndTarget = NULL;
145
146         if (RegisterRawInputDevices(devices, 1, sizeof(RAWINPUTDEVICE)))
147                 puts("registered for multi-axis input");
148 }
149
150 GHOST_SystemWin32::~GHOST_SystemWin32()
151 {
152         // Shutdown COM
153         OleUninitialize();
154 }
155
156
157 GHOST_TUns64 GHOST_SystemWin32::getMilliSeconds() const
158 {
159         // Hardware does not support high resolution timers. We will use GetTickCount instead then.
160         if (!m_hasPerformanceCounter) {
161                 return ::GetTickCount();
162         }
163
164         // Retrieve current count
165         __int64 count = 0;
166         ::QueryPerformanceCounter((LARGE_INTEGER*)&count);
167
168         // Calculate the time passed since system initialization.
169         __int64 delta = 1000*(count-m_start);
170
171         GHOST_TUns64 t = (GHOST_TUns64)(delta/m_freq);
172         return t; 
173 }
174
175
176 GHOST_TUns8 GHOST_SystemWin32::getNumDisplays() const
177 {
178         GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::getNumDisplays(): m_displayManager==0\n");
179         GHOST_TUns8 numDisplays;
180         m_displayManager->getNumDisplays(numDisplays);
181         return numDisplays;
182 }
183
184
185 void GHOST_SystemWin32::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const
186 {
187         width = ::GetSystemMetrics(SM_CXSCREEN);
188         height= ::GetSystemMetrics(SM_CYSCREEN);
189 }
190
191
192 GHOST_IWindow* GHOST_SystemWin32::createWindow(
193         const STR_String& title, 
194         GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height,
195         GHOST_TWindowState state, GHOST_TDrawingContextType type,
196         bool stereoVisual, const GHOST_TUns16 numOfAASamples, const GHOST_TEmbedderWindowID parentWindow )
197 {
198         GHOST_Window* window = 0;
199         window = new GHOST_WindowWin32 (this, title, left, top, width, height, state, type, stereoVisual, numOfAASamples);
200         if (window) {
201                 if (window->getValid()) {
202                         // Store the pointer to the window
203 //                      if (state != GHOST_kWindowStateFullScreen) {
204                                 m_windowManager->addWindow(window);
205 //                      }
206                 }
207                 else {
208                         // An invalid window could be one that was used to test for AA
209                         GHOST_Window *other_window = ((GHOST_WindowWin32*)window)->getNextWindow();
210
211                         delete window;
212                         window = 0;
213                         
214                         // If another window is found, let the wm know about that one, but not the old one
215                         if (other_window)
216                         {
217                                 m_windowManager->addWindow(other_window);
218                                 window = other_window;
219                         }
220                 }
221         }
222         return window;
223 }
224
225
226 bool GHOST_SystemWin32::processEvents(bool waitForEvent)
227 {
228         MSG msg;
229         bool anyProcessed = false;
230
231         do {
232                 GHOST_TimerManager* timerMgr = getTimerManager();
233
234                 if (waitForEvent && !::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE)) {
235 #if 1
236                         ::Sleep(1);
237 #else
238                         GHOST_TUns64 next = timerMgr->nextFireTime();
239                         GHOST_TInt64 maxSleep = next - getMilliSeconds();
240                         
241                         if (next == GHOST_kFireTimeNever) {
242                                 ::WaitMessage();
243                         } else if(maxSleep >= 0.0) {
244                                 ::SetTimer(NULL, 0, maxSleep, NULL);
245                                 ::WaitMessage();
246                                 ::KillTimer(NULL, 0);
247                         }
248 #endif
249                 }
250
251                 if (timerMgr->fireTimers(getMilliSeconds())) {
252                         anyProcessed = true;
253                 }
254
255                 // Process all the events waiting for us
256                 while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE) != 0) {
257                         ::TranslateMessage(&msg);
258                         ::DispatchMessage(&msg);
259                         anyProcessed = true;
260                 }
261         } while (waitForEvent && !anyProcessed);
262
263         return anyProcessed;
264 }
265
266
267 GHOST_TSuccess GHOST_SystemWin32::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const
268 {
269         POINT point;
270         if(::GetCursorPos(&point)){
271                 x = point.x;
272                 y = point.y;
273                 return GHOST_kSuccess;
274         }
275         return GHOST_kFailure;
276 }
277
278
279 GHOST_TSuccess GHOST_SystemWin32::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y)
280 {
281         return ::SetCursorPos(x, y) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
282 }
283
284
285 GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys& keys) const
286 {
287         /*
288         GetKeyState and GetAsyncKeyState only work with Win95, Win98, NT4,
289         Terminal Server and Windows 2000.
290         But on WinME it always returns zero. These two functions are simply
291         skipped by Millenium Edition!
292
293         Official explanation from Microsoft:
294         Intentionally disabled.
295         It didn't work all that well on some newer hardware, and worked less 
296         well with the passage of time, so it was fully disabled in ME.
297         */
298         if (m_separateLeftRight && m_separateLeftRightInitialized) {
299                 bool down = HIBYTE(::GetKeyState(VK_LSHIFT)) != 0;
300                 keys.set(GHOST_kModifierKeyLeftShift, down);
301                 down = HIBYTE(::GetKeyState(VK_RSHIFT)) != 0;
302                 keys.set(GHOST_kModifierKeyRightShift, down);
303                 down = HIBYTE(::GetKeyState(VK_LMENU)) != 0;
304                 keys.set(GHOST_kModifierKeyLeftAlt, down);
305                 down = HIBYTE(::GetKeyState(VK_RMENU)) != 0;
306                 keys.set(GHOST_kModifierKeyRightAlt, down);
307                 down = HIBYTE(::GetKeyState(VK_LCONTROL)) != 0;
308                 keys.set(GHOST_kModifierKeyLeftControl, down);
309                 down = HIBYTE(::GetKeyState(VK_RCONTROL)) != 0;
310                 keys.set(GHOST_kModifierKeyRightControl, down);
311         }
312         else {
313                 bool down = HIBYTE(::GetKeyState(VK_SHIFT)) != 0;
314                 keys.set(GHOST_kModifierKeyLeftShift, down);
315                 keys.set(GHOST_kModifierKeyRightShift, down);
316                 down = HIBYTE(::GetKeyState(VK_MENU)) != 0;
317                 keys.set(GHOST_kModifierKeyLeftAlt, down);
318                 keys.set(GHOST_kModifierKeyRightAlt, down);
319                 down = HIBYTE(::GetKeyState(VK_CONTROL)) != 0;
320                 keys.set(GHOST_kModifierKeyLeftControl, down);
321                 keys.set(GHOST_kModifierKeyRightControl, down);
322         }
323         return GHOST_kSuccess;
324 }
325
326
327 GHOST_TSuccess GHOST_SystemWin32::getButtons(GHOST_Buttons& buttons) const
328 {
329         /* Check for swapped buttons (left-handed mouse buttons)
330          * GetAsyncKeyState() will give back the state of the physical mouse buttons.
331          */
332         bool swapped = ::GetSystemMetrics(SM_SWAPBUTTON) == TRUE;
333
334         bool down = HIBYTE(::GetKeyState(VK_LBUTTON)) != 0;
335         buttons.set(swapped ? GHOST_kButtonMaskRight : GHOST_kButtonMaskLeft, down);
336
337         down = HIBYTE(::GetKeyState(VK_MBUTTON)) != 0;
338         buttons.set(GHOST_kButtonMaskMiddle, down);
339
340         down = HIBYTE(::GetKeyState(VK_RBUTTON)) != 0;
341         buttons.set(swapped ? GHOST_kButtonMaskLeft : GHOST_kButtonMaskRight, down);
342         return GHOST_kSuccess;
343 }
344
345
346 GHOST_TSuccess GHOST_SystemWin32::init()
347 {
348         GHOST_TSuccess success = GHOST_System::init();
349
350         m_ndofManager = new GHOST_NDOFManagerWin32(*this);
351
352         /* Disable scaling on high DPI displays on Vista */
353         HMODULE user32 = ::LoadLibraryA("user32.dll");
354         typedef BOOL (WINAPI * LPFNSETPROCESSDPIAWARE)();
355         LPFNSETPROCESSDPIAWARE SetProcessDPIAware =
356                 (LPFNSETPROCESSDPIAWARE)GetProcAddress(user32, "SetProcessDPIAware");
357         if (SetProcessDPIAware)
358                 SetProcessDPIAware();
359         FreeLibrary(user32);
360
361         // Determine whether this system has a high frequency performance counter. */
362         m_hasPerformanceCounter = ::QueryPerformanceFrequency((LARGE_INTEGER*)&m_freq) == TRUE;
363         if (m_hasPerformanceCounter) {
364                 GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer available\n")
365                 ::QueryPerformanceCounter((LARGE_INTEGER*)&m_start);
366         }
367         else {
368                 GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer not available\n")
369         }
370
371         if (success) {
372                 WNDCLASS wc;
373                 wc.style= CS_HREDRAW | CS_VREDRAW;
374                 wc.lpfnWndProc= s_wndProc;
375                 wc.cbClsExtra= 0;
376                 wc.cbWndExtra= 0;
377                 wc.hInstance= ::GetModuleHandle(0);
378                 wc.hIcon = ::LoadIcon(wc.hInstance, "APPICON");
379                 
380                 if (!wc.hIcon) {
381                         ::LoadIcon(NULL, IDI_APPLICATION);
382                 }
383                 wc.hCursor = ::LoadCursor(0, IDC_ARROW);
384                 wc.hbrBackground= (HBRUSH)::GetStockObject(BLACK_BRUSH);
385                 wc.lpszMenuName = 0;
386                 wc.lpszClassName= GHOST_WindowWin32::getWindowClassName();
387     
388                 // Use RegisterClassEx for setting small icon
389                 if (::RegisterClass(&wc) == 0) {
390                         success = GHOST_kFailure;
391                 }
392         }
393         return success;
394 }
395
396
397 GHOST_TSuccess GHOST_SystemWin32::exit()
398 {
399         return GHOST_System::exit();
400 }
401
402
403 GHOST_TKey GHOST_SystemWin32::convertKey(WPARAM wParam, LPARAM lParam) const
404 {
405         GHOST_TKey key;
406         bool isExtended = (lParam&(1<<24))?true:false;
407
408         if ((wParam >= '0') && (wParam <= '9')) {
409                 // VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39)
410                 key = (GHOST_TKey)(wParam - '0' + GHOST_kKey0);
411         }
412         else if ((wParam >= 'A') && (wParam <= 'Z')) {
413                 // VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A)
414                 key = (GHOST_TKey)(wParam - 'A' + GHOST_kKeyA);
415         }
416         else if ((wParam >= VK_F1) && (wParam <= VK_F24)) {
417                 key = (GHOST_TKey)(wParam - VK_F1 + GHOST_kKeyF1);
418         }
419         else {
420                 switch (wParam) {
421                 case VK_RETURN:
422                         key = isExtended?GHOST_kKeyNumpadEnter:GHOST_kKeyEnter;
423                         break;
424
425                 case VK_BACK:     key = GHOST_kKeyBackSpace;            break;
426                 case VK_TAB:      key = GHOST_kKeyTab;                          break;
427                 case VK_ESCAPE:   key = GHOST_kKeyEsc;                          break;
428                 case VK_SPACE:    key = GHOST_kKeySpace;                        break;
429                 case VK_PRIOR:    key = GHOST_kKeyUpPage;                       break;
430                 case VK_NEXT:     key = GHOST_kKeyDownPage;                     break;
431                 case VK_END:      key = GHOST_kKeyEnd;                          break;
432                 case VK_HOME:     key = GHOST_kKeyHome;                         break;
433                 case VK_INSERT:   key = GHOST_kKeyInsert;                       break;
434                 case VK_DELETE:   key = GHOST_kKeyDelete;                       break;
435                 case VK_LEFT:     key = GHOST_kKeyLeftArrow;            break;
436                 case VK_RIGHT:    key = GHOST_kKeyRightArrow;           break;
437                 case VK_UP:       key = GHOST_kKeyUpArrow;                      break;
438                 case VK_DOWN:     key = GHOST_kKeyDownArrow;            break;
439                 case VK_NUMPAD0:  key = GHOST_kKeyNumpad0;                      break;
440                 case VK_NUMPAD1:  key = GHOST_kKeyNumpad1;                      break;
441                 case VK_NUMPAD2:  key = GHOST_kKeyNumpad2;                      break;
442                 case VK_NUMPAD3:  key = GHOST_kKeyNumpad3;                      break;
443                 case VK_NUMPAD4:  key = GHOST_kKeyNumpad4;                      break;
444                 case VK_NUMPAD5:  key = GHOST_kKeyNumpad5;                      break;
445                 case VK_NUMPAD6:  key = GHOST_kKeyNumpad6;                      break;
446                 case VK_NUMPAD7:  key = GHOST_kKeyNumpad7;                      break;
447                 case VK_NUMPAD8:  key = GHOST_kKeyNumpad8;                      break;
448                 case VK_NUMPAD9:  key = GHOST_kKeyNumpad9;                      break;
449                 case VK_SNAPSHOT: key = GHOST_kKeyPrintScreen;          break;
450                 case VK_PAUSE:    key = GHOST_kKeyPause;                        break;
451                 case VK_MULTIPLY: key = GHOST_kKeyNumpadAsterisk;        break;
452                 case VK_SUBTRACT: key = GHOST_kKeyNumpadMinus;          break;
453                 case VK_DECIMAL:  key = GHOST_kKeyNumpadPeriod;         break;
454                 case VK_DIVIDE:   key = GHOST_kKeyNumpadSlash;          break;
455                 case VK_ADD:      key = GHOST_kKeyNumpadPlus;           break;
456
457                 case VK_SEMICOLON:              key = GHOST_kKeySemicolon;              break;
458                 case VK_EQUALS:                 key = GHOST_kKeyEqual;                  break;
459                 case VK_COMMA:                  key = GHOST_kKeyComma;                  break;
460                 case VK_MINUS:                  key = GHOST_kKeyMinus;                  break;
461                 case VK_PERIOD:                 key = GHOST_kKeyPeriod;                 break;
462                 case VK_SLASH:                  key = GHOST_kKeySlash;                  break;
463                 case VK_BACK_QUOTE:             key = GHOST_kKeyAccentGrave;    break;
464                 case VK_OPEN_BRACKET:   key = GHOST_kKeyLeftBracket;    break;
465                 case VK_BACK_SLASH:             key = GHOST_kKeyBackslash;              break;
466                 case VK_CLOSE_BRACKET:  key = GHOST_kKeyRightBracket;   break;
467                 case VK_QUOTE:                  key = GHOST_kKeyQuote;                  break;
468                 case VK_GR_LESS:                key = GHOST_kKeyGrLess;                 break;
469
470                 // Process these keys separately because we need to distinguish right from left modifier keys
471                 case VK_SHIFT:
472                 case VK_CONTROL:
473                 case VK_MENU:
474
475                 // Ignore these keys
476                 case VK_NUMLOCK:
477                 case VK_SCROLL:
478                 case VK_CAPITAL:
479                 default:
480                         key = GHOST_kKeyUnknown;
481                         break;
482                 }
483         }
484         return key;
485 }
486
487
488 void GHOST_SystemWin32::processModifierKeys(GHOST_IWindow *window)
489 {
490         GHOST_ModifierKeys oldModifiers, newModifiers;
491         // Retrieve old state of the modifier keys
492         ((GHOST_SystemWin32*)getSystem())->retrieveModifierKeys(oldModifiers);
493         // Retrieve current state of the modifier keys
494         ((GHOST_SystemWin32*)getSystem())->getModifierKeys(newModifiers);
495
496         // Compare the old and the new
497         if (!newModifiers.equals(oldModifiers)) {
498                 // Create events for the masks that changed
499                 for (int i = 0; i < GHOST_kModifierKeyNumMasks; i++) {
500                         if (newModifiers.get((GHOST_TModifierKeyMask)i) != oldModifiers.get((GHOST_TModifierKeyMask)i)) {
501                                 // Convert the mask to a key code
502                                 GHOST_TKey key = GHOST_ModifierKeys::getModifierKeyCode((GHOST_TModifierKeyMask)i);
503                                 bool keyDown = newModifiers.get((GHOST_TModifierKeyMask)i);
504                                 GHOST_EventKey* event;
505                                 if (key != GHOST_kKeyUnknown) {
506                                         // Create an event
507                                         event = new GHOST_EventKey(getSystem()->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key);
508                                         pushEvent(event);
509                                 }
510                         }
511                 }
512         }
513
514         // Store new modifier keys state
515         ((GHOST_SystemWin32*)getSystem())->storeModifierKeys(newModifiers);
516 }
517
518
519 GHOST_EventButton* GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, GHOST_IWindow *window, GHOST_TButtonMask mask)
520 {
521         return new GHOST_EventButton (getSystem()->getMilliSeconds(), type, window, mask);
522 }
523
524
525 GHOST_EventCursor* GHOST_SystemWin32::processCursorEvent(GHOST_TEventType type, GHOST_IWindow *Iwindow, int x, int y)
526 {
527         GHOST_TInt32 x_screen, y_screen;
528         GHOST_SystemWin32 * system = ((GHOST_SystemWin32 * ) getSystem());
529         GHOST_WindowWin32 * window = ( GHOST_WindowWin32 * ) Iwindow;
530         
531 //      system->getCursorPosition(x_screen, y_screen);
532         x_screen = x;
533         y_screen = y;
534
535         if(window->getCursorGrabMode() != GHOST_kGrabDisable && window->getCursorGrabMode() != GHOST_kGrabNormal)
536         {
537                 GHOST_TInt32 x_new= x_screen;
538                 GHOST_TInt32 y_new= y_screen;
539                 GHOST_TInt32 x_accum, y_accum;
540                 GHOST_Rect bounds;
541
542                 /* fallback to window bounds */
543                 if(window->getCursorGrabBounds(bounds)==GHOST_kFailure){
544                         window->getClientBounds(bounds);
545                 }
546
547                 /* could also clamp to screen bounds
548                  * wrap with a window outside the view will fail atm  */
549
550                 bounds.wrapPoint(x_new, y_new, 2); /* offset of one incase blender is at screen bounds */
551
552                 window->getCursorGrabAccum(x_accum, y_accum);
553                 if(x_new != x_screen|| y_new != y_screen) {
554                         /* when wrapping we don't need to add an event because the
555                          * setCursorPosition call will cause a new event after */
556                         system->setCursorPosition(x_new, y_new); /* wrap */
557                         window->setCursorGrabAccum(x_accum + (x_screen - x_new), y_accum + (y_screen - y_new));
558                 }else{
559                         return new GHOST_EventCursor(system->getMilliSeconds(),
560                                                                                  type,
561                                                                                  window,
562                                                                                  x_screen + x_accum,
563                                                                                  y_screen + y_accum
564                         );
565                 }
566
567         }
568         else {
569                 return new GHOST_EventCursor(system->getMilliSeconds(),
570                                                                          type,
571                                                                          window,
572                                                                          x_screen,
573                                                                          y_screen
574                 );
575         }
576         return NULL;
577 }
578
579
580 GHOST_EventWheel* GHOST_SystemWin32::processWheelEvent(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam)
581 {
582         // short fwKeys = LOWORD(wParam);                       // key flags
583         int zDelta = (short) HIWORD(wParam);    // wheel rotation
584         
585         // zDelta /= WHEEL_DELTA;
586         // temporary fix below: microsoft now has added more precision, making the above division not work
587         if (zDelta <= 0 ) zDelta= -1; else zDelta= 1;   
588         
589         // short xPos = (short) LOWORD(lParam); // horizontal position of pointer
590         // short yPos = (short) HIWORD(lParam); // vertical position of pointer
591         return new GHOST_EventWheel (getSystem()->getMilliSeconds(), window, zDelta);
592 }
593
594
595 GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, bool keyDown, WPARAM wParam, LPARAM lParam)
596 {
597         GHOST_TKey key = ((GHOST_SystemWin32*)getSystem())->convertKey(wParam, lParam);
598         GHOST_EventKey* event;
599         if (key != GHOST_kKeyUnknown) {
600                 MSG keyMsg;
601                 char ascii = '\0';
602
603                         /* Eat any character related messages */
604                 if (::PeekMessage(&keyMsg, NULL, WM_CHAR, WM_SYSDEADCHAR, PM_REMOVE)) {
605                         ascii = (char) keyMsg.wParam;
606                 }
607
608                 event = new GHOST_EventKey(getSystem()->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key, ascii);
609         }
610         else {
611                 event = 0;
612         }
613         return event;
614 }
615
616
617 GHOST_Event* GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type, GHOST_IWindow* window)
618 {
619         return new GHOST_Event(getSystem()->getMilliSeconds(), type, window);
620 }
621
622 GHOST_TSuccess GHOST_SystemWin32::pushDragDropEvent(GHOST_TEventType eventType, 
623                                                                                                         GHOST_TDragnDropTypes draggedObjectType,
624                                                                                                         GHOST_IWindow* window,
625                                                                                                         int mouseX, int mouseY,
626                                                                                                         void* data)
627 {
628         GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem());
629         return system->pushEvent(new GHOST_EventDragnDrop(system->getMilliSeconds(),
630                                                                                                           eventType,
631                                                                                                           draggedObjectType,
632                                                                                                           window,mouseX,mouseY,data)
633                         );
634 }
635
636 void GHOST_SystemWin32::processMinMaxInfo(MINMAXINFO * minmax)
637 {
638         minmax->ptMinTrackSize.x=320;
639         minmax->ptMinTrackSize.y=240;
640 }
641
642 bool GHOST_SystemWin32::processRawInput(RAWINPUT const& raw, GHOST_WindowWin32* window /*, int& x, int& y */ )
643 {
644         GHOST_IEvent* event = NULL;
645         bool eventSent = false;
646
647         puts("BEGIN");
648
649 #if 0 // now using the existing mouse button handlers, improved movement handler
650                                 if (raw.header.dwType == RIM_TYPEMOUSE)
651                                         {
652                                         USHORT const& buttonFlags = raw.data.mouse.usButtonFlags;
653                                         if (buttonFlags)
654                                                 {
655                                                 printf("button flags: %04X\n", buttonFlags);
656
657                                                 if (buttonFlags & RI_MOUSE_LEFT_BUTTON_DOWN)
658                                                         {
659                                                         puts("left button down");
660                                                         window->registerMouseClickEvent(true);
661                                                         event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft);
662                                                         }
663                                                 else if (buttonFlags & RI_MOUSE_LEFT_BUTTON_UP)
664                                                         {
665                                                         puts("left button up");
666                                                         window->registerMouseClickEvent(false);
667                                                         event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft);
668                                                         }
669
670                                                 if (buttonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN)
671                                                         {
672                                                         puts("right button down");
673                                                         window->registerMouseClickEvent(true);
674                                                         event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight);
675                                                         }
676                                                 else if (buttonFlags & RI_MOUSE_RIGHT_BUTTON_UP)
677                                                         {
678                                                         puts("right button up");
679                                                         window->registerMouseClickEvent(false);
680                                                         event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight);
681                                                         }
682
683                                                 if (buttonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN)
684                                                         {
685                                                         puts("middle button down");
686                                                         window->registerMouseClickEvent(true);
687                                                         event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskMiddle);
688                                                         }
689                                                 else if (buttonFlags & RI_MOUSE_MIDDLE_BUTTON_UP)
690                                                         {
691                                                         puts("middle button up");
692                                                         window->registerMouseClickEvent(false);
693                                                         event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskMiddle);
694                                                         }
695
696                                                 // similar for BUTTON_4 and BUTTON_5
697
698                                                 if (buttonFlags & RI_MOUSE_WHEEL)
699                                                         {
700                                                         signed short wheelDelta = raw.data.mouse.usButtonData;
701                                                         printf("wheel moved %+d\n", wheelDelta);
702                                                         }
703                                                 }
704
705                                         int dx = raw.data.mouse.lLastX; // These might be in Mickeys, not pixels.
706                                         int dy = raw.data.mouse.lLastY;
707                                         if (dx || dy)
708                                                 {
709                                                 printf("mouse moved <%+d,%+d>\n", dx, dy);
710                                                 x += dx;
711                                                 x += dy;
712                                                 event = processCursorEvent(GHOST_kEventCursorMove, window, x, y);
713                                                 }
714                                         }
715 #endif // unused experimental mouse code
716
717         if (raw.header.dwType == RIM_TYPEHID)
718                 {
719 //              RID_DEVICE_INFO info;
720 //              DWORD infoSize = sizeof(RID_DEVICE_INFO);
721 //              int n = GetRawInputDeviceInfo(raw.header.hDevice, RIDI_DEVICEINFO, &info, &infoSize);
722                 // ... and so on
723                 // I'll finish this device checking code later. Since we ask for only multi-axis input
724                 // in the constructor, that's all we should get here.
725
726 /*
727 Here's some handy info from http://www.linux-usb.org/usb.ids
728
729 vendor ID
730 046d  Logitech, Inc.
731
732         device IDs
733         c623  3Dconnexion Space Traveller 3D Mouse
734         c625  3Dconnexion Space Pilot 3D Mouse
735         c626  3Dconnexion Space Navigator 3D Mouse
736         c627  3Dconnexion Space Explorer 3D Mouse
737
738 No other registered devices use the c62_ space, so a simple mask will work!
739 */
740
741                 // multiple events per RAWHID? MSDN hints at this.
742                 printf("%d events\n", raw.data.hid.dwCount);
743
744                 BYTE const* data = &raw.data.hid.bRawData;
745 // MinGW's definition (below) doesn't agree with MSDN reference for bRawData:
746 // typedef struct tagRAWHID {
747 //      DWORD dwSizeHid;
748 //      DWORD dwCount;
749 //      BYTE bRawData;
750 // } RAWHID,*PRAWHID,*LPRAWHID;
751
752                 BYTE packetType = data[0];
753                 switch (packetType)
754                         {
755                         case 1: // translation
756                                 {
757                                 short t[3];
758                                 memcpy(t, data + 1, sizeof(t));
759                                 printf("T: %+5d %+5d %+5d\n", t[0], t[1], t[2]);
760                                 m_ndofManager->updateTranslation(t, getMilliseconds());
761                                 break;
762                                 }
763                         case 2: // rotation
764                                 {
765                                 short r[3];
766                                 memcpy(r, data + 1, sizeof(r));
767                                 printf("R: %+5d %+5d %+5d\n", r[0], r[1], r[2]);
768                                 m_ndofManager->updateRotation(r, getMilliseconds());
769                                 break;
770                                 }
771                         case 3: // buttons
772                                 {
773                                 unsigned short buttons;
774                                 memcpy(&buttons, data + 1, sizeof(buttons));
775                                 printf("buttons:");
776                                 if (buttons)
777                                         {
778                                         // work our way through the bit mask
779                                         for (int i = 0; i < 16; ++i)
780                                                 if (buttons & (1 << i))
781                                                         printf(" %d", i + 1);
782                                         printf("\n");
783                                         }
784                                 else
785                                         printf(" none\n");
786                                 m_ndofManager->updateButtons(buttons, getMilliseconds());
787                                 break;
788                                 }
789                         }
790                 }
791
792         // assume only one event will come from this RawInput report
793         // test and adjust assumptions as needed!
794
795         if (event)
796                 {
797                 pushEvent(event);
798                 event = NULL;
799                 eventSent = true;
800                 }
801
802         puts("END");
803
804         return eventSent;
805 }
806
807 int GHOST_SystemWin32::getMoreMousePoints(int xLatest, int yLatest, int xPrev, int yPrev, GHOST_WindowWin32* window)
808         {
809         MOUSEMOVEPOINT point = {
810                 xLatest & 0x0000FFFF, // confine to low word to make GetMouseMovePointsEx happy
811                 yLatest & 0x0000FFFF,
812                 0, // time stamp unknown
813                 NULL // no extra info
814                 };
815
816         MOUSEMOVEPOINT morePoints[64];
817
818         int n = GetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &point, morePoints, 64, GMMP_USE_DISPLAY_POINTS);
819         if (n == -1)
820                 {
821                 printf("<!> can't get more mouse points (error %d)\n", (int) GetLastError());
822                 return 0;
823                 }
824
825         // search for 'prev' point (we want only newer points)
826         for (int i = 1; i < n; ++i)
827                 if (morePoints[i].x == xPrev && morePoints[i].y == yPrev)
828                         {
829                         n = i; // don't include found point (or more ancient points)
830                         break;
831                         }
832
833         for (int i = n - 1; i > 0; --i)
834                 {
835                 signed short x = morePoints[i].x;
836                 signed short y = morePoints[i].y;
837
838                 printf("> (%d,%d)\n", x, y);
839                 
840                 pushEvent(processCursorEvent(GHOST_kEventCursorMove, window, x, y));
841                 }
842
843         return n;
844         } // END getMoreMousePoints
845
846 LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
847 {
848         LRESULT lResult = 0;
849         GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem());
850         GHOST_ASSERT(system, "GHOST_SystemWin32::s_wndProc(): system not initialized")
851         // [mce] then why not register this function at the end of SystemWin32 constructor?
852
853         bool handled = false;
854
855         if (hwnd) {
856                 GHOST_WindowWin32* window = (GHOST_WindowWin32*)::GetWindowLong(hwnd, GWL_USERDATA);
857                 if (window) {
858                         handled = system->handleEvent(window, msg, wParam, lParam);
859
860                         // take care of misc. cases that need hwnd
861                         if (msg == WM_ACTIVATE)
862                                 /* WARNING: Let DefWindowProc handle WM_ACTIVATE, otherwise WM_MOUSEWHEEL
863                                 will not be dispatched to OUR active window if we minimize one of OUR windows. */
864                                 lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
865                         else if (msg == WM_PAINT)
866                                 /* An application sends the WM_PAINT message when the system or another application
867                                 * makes a request to paint a portion of an application's window. The message is sent
868                                 * when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage
869                                 * function when the application obtains a WM_PAINT message by using the GetMessage or
870                                 * PeekMessage function. */
871                                 ::ValidateRect(hwnd, NULL);
872                 }
873                 else {
874                         // Event found for a window before the pointer to the class has been set.
875                         GHOST_PRINT("GHOST_SystemWin32::wndProc: GHOST window event before creation\n")
876
877                         /* These are events we typically miss at this point:
878                            WM_GETMINMAXINFO     0x24
879                            WM_NCCREATE                  0x81
880                            WM_NCCALCSIZE                0x83
881                            WM_CREATE                    0x01
882                            We let DefWindowProc do the work.
883                         */
884                 }
885         }
886         else {
887                 // Events without valid hwnd
888                 GHOST_PRINT("GHOST_SystemWin32::wndProc: event without window\n")
889         }
890
891         if (!handled)
892                 lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
893
894         return lResult;
895 }
896
897 bool GHOST_SystemWin32::handleEvent(GHOST_WindowWin32* window, UINT msg, WPARAM wParam, LPARAM lParam)
898         {
899         GHOST_Event* event = NULL;
900         bool eventSent = false;
901
902         static int mousePosX = 0, mousePosY = 0; // track mouse position between calls
903
904                         switch (msg) {
905                                 ////////////////////////////////////////////////////////////////////////
906                                 // Keyboard events, processed
907                                 ////////////////////////////////////////////////////////////////////////
908                                 case WM_KEYDOWN:
909                                         /* The WM_KEYDOWN message is posted to the window with the keyboard focus when a
910                                          * nonsystem key is pressed. A nonsystem key is a key that is pressed when the alt
911                                          * key is not pressed. 
912                                          */
913                                 case WM_SYSKEYDOWN:
914                                         /* The WM_SYSKEYDOWN message is posted to the window with the keyboard focus when 
915                                          * the user presses the F10 key (which activates the menu bar) or holds down the 
916                                          * alt key and then presses another key. It also occurs when no window currently 
917                                          * has the keyboard focus; in this case, the WM_SYSKEYDOWN message is sent to the 
918                                          * active window. The window that receives the message can distinguish between these 
919                                          * two contexts by checking the context code in the lKeyData parameter. 
920                                          */
921                                         switch (wParam) {
922                                                 case VK_SHIFT:
923                                                 case VK_CONTROL:
924                                                 case VK_MENU:
925                                                         if (!m_separateLeftRightInitialized) {
926                                                                 // Check whether this system supports separate left and right keys
927                                                                 switch (wParam) {
928                                                                         case VK_SHIFT:
929                                                                                 m_separateLeftRight =
930                                                                                         (HIBYTE(::GetKeyState(VK_LSHIFT)) != 0) ||
931                                                                                         (HIBYTE(::GetKeyState(VK_RSHIFT)) != 0) ?
932                                                                                         true : false;
933                                                                                 break;
934                                                                         case VK_CONTROL:
935                                                                                 m_separateLeftRight =
936                                                                                         (HIBYTE(::GetKeyState(VK_LCONTROL)) != 0) ||
937                                                                                         (HIBYTE(::GetKeyState(VK_RCONTROL)) != 0) ?
938                                                                                         true : false;
939                                                                                 break;
940                                                                         case VK_MENU:
941                                                                                 m_separateLeftRight =
942                                                                                         (HIBYTE(::GetKeyState(VK_LMENU)) != 0) ||
943                                                                                         (HIBYTE(::GetKeyState(VK_RMENU)) != 0) ?
944                                                                                         true : false;
945                                                                                 break;
946                                                                 }
947                                                                 m_separateLeftRightInitialized = true;
948                                                         }
949                                                         processModifierKeys(window);
950                                                         // Bypass call to DefWindowProc
951                                                         return true;
952                                                 default:
953                                                         event = processKeyEvent(window, true, wParam, lParam);
954                                                         if (!event) {
955                                                                 GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
956                                                                 GHOST_PRINT(msg)
957                                                                 GHOST_PRINT(" key ignored\n")
958                                                         }
959                                                         break;
960                                                 }
961                                         break;
962
963                                 case WM_KEYUP:
964                                 case WM_SYSKEYUP:
965                                         switch (wParam) {
966                                                 case VK_SHIFT:
967                                                 case VK_CONTROL:
968                                                 case VK_MENU:
969                                                         processModifierKeys(window);
970                                                         // Bypass call to DefWindowProc
971                                                         return true;
972                                                 default:
973                                                         event = processKeyEvent(window, false, wParam, lParam);
974                                                         if (!event) {
975                                                                 GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
976                                                                 GHOST_PRINT(msg)
977                                                                 GHOST_PRINT(" key ignored\n")
978                                                         }
979                                                         break;
980                                         }
981                                         break;
982
983 #if 0 // this code is illustrative; no need to compile
984                                 ////////////////////////////////////////////////////////////////////////
985                                 // Keyboard events, ignored
986                                 ////////////////////////////////////////////////////////////////////////
987                                 case WM_CHAR:
988                                         /* The WM_CHAR message is posted to the window with the keyboard focus when 
989                                          * a WM_KEYDOWN message is translated by the TranslateMessage function. WM_CHAR 
990                                          * contains the character code of the key that was pressed. 
991                                          */
992                                 case WM_DEADCHAR:
993                                         /* The WM_DEADCHAR message is posted to the window with the keyboard focus when a
994                                          * WM_KEYUP message is translated by the TranslateMessage function. WM_DEADCHAR 
995                                          * specifies a character code generated by a dead key. A dead key is a key that 
996                                          * generates a character, such as the umlaut (double-dot), that is combined with 
997                                          * another character to form a composite character. For example, the umlaut-O 
998                                          * character (Ù) is generated by typing the dead key for the umlaut character, and 
999                                          * then typing the O key.
1000                                          */
1001                                 case WM_SYSDEADCHAR:
1002                                         /* The WM_SYSDEADCHAR message is sent to the window with the keyboard focus when 
1003                                          * a WM_SYSKEYDOWN message is translated by the TranslateMessage function. 
1004                                          * WM_SYSDEADCHAR specifies the character code of a system dead key - that is, 
1005                                          * a dead key that is pressed while holding down the alt key. 
1006                                          */
1007                                         break;
1008 #endif // illustrative code
1009
1010                                 ////////////////////////////////////////////////////////////////////////
1011                                 // Tablet events, processed
1012                                 ////////////////////////////////////////////////////////////////////////
1013                                 case WT_PACKET:
1014                                         puts("WT_PACKET");
1015                                         window->processWin32TabletEvent(wParam, lParam);
1016                                         break;
1017                                 case WT_CSRCHANGE:
1018                                 case WT_PROXIMITY:
1019                                         window->processWin32TabletInitEvent();
1020                                         break;
1021
1022                                 ////////////////////////////////////////////////////////////////////////
1023                                 // Mouse events, processed
1024                                 ////////////////////////////////////////////////////////////////////////
1025                                 case WM_LBUTTONDOWN:
1026                                         window->registerMouseClickEvent(true);
1027                                         event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft);
1028                                         break;
1029                                 case WM_MBUTTONDOWN:
1030                                         window->registerMouseClickEvent(true);
1031                                         event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskMiddle);
1032                                         break;
1033                                 case WM_RBUTTONDOWN:
1034                                         window->registerMouseClickEvent(true);
1035                                         event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight);
1036                                         break;
1037                                 case WM_XBUTTONDOWN:
1038                                         window->registerMouseClickEvent(true);
1039                                         if ((short) HIWORD(wParam) == XBUTTON1){
1040                                                 event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton4);
1041                                         }else if((short) HIWORD(wParam) == XBUTTON2){
1042                                                 event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton5);
1043                                         }
1044                                         break;
1045                                 case WM_LBUTTONUP:
1046                                         window->registerMouseClickEvent(false);
1047                                         event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft);
1048                                         break;
1049                                 case WM_MBUTTONUP:
1050                                         window->registerMouseClickEvent(false);
1051                                         event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskMiddle);
1052                                         break;
1053                                 case WM_RBUTTONUP:
1054                                         window->registerMouseClickEvent(false);
1055                                         event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight);
1056                                         break;
1057                                 case WM_XBUTTONUP:
1058                                         window->registerMouseClickEvent(false);
1059                                         if ((short) HIWORD(wParam) == XBUTTON1){
1060                                                 event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton4);
1061                                         }else if((short) HIWORD(wParam) == XBUTTON2){
1062                                                 event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton5);
1063                                         }
1064                                         break;
1065 //#endif // replaced mouse code
1066
1067                                 case WM_MOUSEMOVE:
1068                                         {
1069 //                                      puts("WM_MOUSEMOVE");
1070
1071 //                                      bool IsFromPen = ((GetMessageExtraInfo() & 0xFF515700) == 0xFF515700); // this only works on TabletPCs
1072                                         int tabletTool = GetMessageExtraInfo() & 0x7f; // true for tablet mouse, not just pen
1073                                         if (tabletTool)
1074                                                 puts("(from tablet)");
1075                                         else
1076                                                 {
1077                                                 // these give window coords, we need view coords
1078 //                                              mousePosX = LOWORD(lParam);
1079 //                                              mousePosY = HIWORD(lParam);
1080 //                                              window->clientToScreen(mousePosX, mousePosY, mousePosX, mousePosY);
1081
1082                                                 int xPrev = mousePosX;
1083                                                 int yPrev = mousePosY;
1084                                                 window->clientToScreen(LOWORD(lParam), HIWORD(lParam), mousePosX, mousePosY);
1085                                                 // if (m_input_fidelity_hint == HI_FI) // can't access hint from static function
1086                                                         
1087                                                 putchar('\n');
1088
1089                                                 if (m_input_fidelity_hint == HI_FI)
1090                                                         {
1091                                                         /* int n = */ getMoreMousePoints(mousePosX, mousePosY, xPrev, yPrev, window);
1092                                                         // printf("%d more mouse points found\n", n);
1093                                                         }
1094
1095                                                 printf("  (%d,%d)\n", mousePosX, mousePosY);
1096
1097                                                 event = processCursorEvent(GHOST_kEventCursorMove, window, mousePosX, mousePosY);
1098                                                 }
1099                                         break;
1100                                         }
1101
1102                                 case WM_INPUT:
1103                                         puts("WM_INPUT");
1104 {
1105 /*
1106     UINT dwSize;
1107     GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
1108     LPBYTE lpb = new BYTE[dwSize];
1109     GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER));
1110     RAWINPUT* raw = (RAWINPUT*)lpb;
1111 */
1112
1113         RAWINPUT raw;
1114         RAWINPUT* raw_ptr = &raw;
1115         UINT rawSize = sizeof(RAWINPUT);
1116 //      UINT bufferSize = rawSize;
1117
1118         puts("processing first event:");
1119         // I don't know if this is needed. Can we get by with just GetRawInputBuffer?
1120         // Thought some mouse events were missing, so I put this in to be cautious.
1121         // Test and remove if redundant. [mce]
1122         GetRawInputData((HRAWINPUT)lParam, RID_INPUT, raw_ptr, &rawSize, sizeof(RAWINPUTHEADER));
1123         eventSent |= processRawInput(raw, window /*, mousePosX, mousePosY*/ );
1124         DefRawInputProc(&raw_ptr, 1, sizeof(RAWINPUTHEADER));
1125
1126 //      GetRawInputBuffer(NULL, &bufferSize, sizeof(RAWINPUTHEADER));
1127 //      UINT n = bufferSize / rawSize;
1128 //      printf("allocating %d bytes (room for %d events)\n", bufferSize, n);
1129
1130         RAWINPUT rawBuffer[10];// = new RAWINPUT[n];
1131         rawSize *= 10;
1132         while (true)
1133                 {
1134                 int n = GetRawInputBuffer(rawBuffer, &rawSize, sizeof(RAWINPUTHEADER));
1135                 if (n == -1)
1136                         {
1137                         printf("<!> error %d\n", (int) GetLastError());
1138                         break;
1139                         }
1140                 else if (n == 0)
1141                         {
1142                         //puts("no more events");
1143                         putchar('\n');
1144                         break;
1145                         }
1146                 else
1147                         {
1148                         printf("processing %d more events:\n", n);
1149                         for (int i = 0; i < n; ++i)
1150                                 {
1151                                 RAWINPUT const& raw = rawBuffer[i];
1152                                 eventSent |= processRawInput(raw, window /*, mousePosX, mousePosY*/ );
1153                                 }
1154
1155                         // clear processed events from the queue
1156                         DefRawInputProc((RAWINPUT**)&rawBuffer, n, sizeof(RAWINPUTHEADER));
1157                         }
1158                 } // inf. loop
1159 }
1160                                         break;
1161                                 case WM_MOUSEWHEEL:
1162                                         puts("WM_MOUSEWHEEL");
1163                                         /* The WM_MOUSEWHEEL message is sent to the focus window
1164                                          * when the mouse wheel is rotated. The DefWindowProc
1165                                          * function propagates the message to the window's parent.
1166                                          * There should be no internal forwarding of the message,
1167                                          * since DefWindowProc propagates it up the parent chain 
1168                                          * until it finds a window that processes it.
1169                                          */
1170                                         event = processWheelEvent(window, wParam, lParam);
1171                                         break;
1172                                 case WM_SETCURSOR:
1173                                         /* The WM_SETCURSOR message is sent to a window if the mouse causes the cursor
1174                                          * to move within a window and mouse input is not captured.
1175                                          * This means we have to set the cursor shape every time the mouse moves!
1176                                          * The DefWindowProc function uses this message to set the cursor to an 
1177                                          * arrow if it is not in the client area.
1178                                          */
1179                                         if (LOWORD(lParam) == HTCLIENT) {
1180                                                 // Load the current cursor
1181                                                 window->loadCursor(window->getCursorVisibility(), window->getCursorShape());
1182                                                 // Bypass call to DefWindowProc
1183                                                 return 0;
1184                                         } 
1185                                         else {
1186                                                 // Outside of client area show standard cursor
1187                                                 window->loadCursor(true, GHOST_kStandardCursorDefault);
1188                                         }
1189                                         break;
1190
1191 #if 0 // this code is illustrative; no need to compile
1192                                 ////////////////////////////////////////////////////////////////////////
1193                                 // Mouse events, ignored
1194                                 ////////////////////////////////////////////////////////////////////////
1195                                 case WM_NCMOUSEMOVE:
1196                                         /* The WM_NCMOUSEMOVE message is posted to a window when the cursor is moved 
1197                                          * within the nonclient area of the window. This message is posted to the window 
1198                                          * that contains the cursor. If a window has captured the mouse, this message is not posted.
1199                                          */
1200                                 case WM_NCHITTEST:
1201                                         /* The WM_NCHITTEST message is sent to a window when the cursor moves, or 
1202                                          * when a mouse button is pressed or released. If the mouse is not captured, 
1203                                          * the message is sent to the window beneath the cursor. Otherwise, the message 
1204                                          * is sent to the window that has captured the mouse. 
1205                                          */
1206                                         break;
1207 #endif // illustrative code
1208
1209                                 ////////////////////////////////////////////////////////////////////////
1210                                 // Window events, processed
1211                                 ////////////////////////////////////////////////////////////////////////
1212                                 case WM_CLOSE:
1213                                         /* The WM_CLOSE message is sent as a signal that a window or an application should terminate. */
1214                                         event = processWindowEvent(GHOST_kEventWindowClose, window);
1215                                         break;
1216                                 case WM_ACTIVATE:
1217                                         /* The WM_ACTIVATE message is sent to both the window being activated and the window being 
1218                                          * deactivated. If the windows use the same input queue, the message is sent synchronously, 
1219                                          * first to the window procedure of the top-level window being deactivated, then to the window
1220                                          * procedure of the top-level window being activated. If the windows use different input queues,
1221                                          * the message is sent asynchronously, so the window is activated immediately. 
1222                                          */
1223                                         event = processWindowEvent(LOWORD(wParam) ? GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate, window);
1224                                         break;
1225                                 case WM_PAINT:
1226                                         /* An application sends the WM_PAINT message when the system or another application
1227                                          * makes a request to paint a portion of an application's window. The message is sent
1228                                          * when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage 
1229                                          * function when the application obtains a WM_PAINT message by using the GetMessage or 
1230                                          * PeekMessage function. 
1231                                          */
1232                                         event = processWindowEvent(GHOST_kEventWindowUpdate, window);
1233                                         break;
1234                                 case WM_GETMINMAXINFO:
1235                                         /* The WM_GETMINMAXINFO message is sent to a window when the size or 
1236                                          * position of the window is about to change. An application can use 
1237                                          * this message to override the window's default maximized size and 
1238                                          * position, or its default minimum or maximum tracking size. 
1239                                          */
1240                                         processMinMaxInfo((MINMAXINFO *) lParam);
1241                                         /* Let DefWindowProc handle it. */
1242                                         break;
1243                                 case WM_SIZE:
1244                                         /* The WM_SIZE message is sent to a window after its size has changed.
1245                                          * The WM_SIZE and WM_MOVE messages are not sent if an application handles the 
1246                                          * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
1247                                          * to perform any move or size change processing during the WM_WINDOWPOSCHANGED 
1248                                          * message without calling DefWindowProc.
1249                                          */
1250                                         event = processWindowEvent(GHOST_kEventWindowSize, window);
1251                                         break;
1252                                 case WM_CAPTURECHANGED:
1253                                         window->lostMouseCapture();
1254                                         break;
1255                                 case WM_MOVING:
1256                                         /* The WM_MOVING message is sent to a window that the user is moving. By processing 
1257                                          * this message, an application can monitor the size and position of the drag rectangle
1258                                          * and, if needed, change its size or position.
1259                                          */
1260                                 case WM_MOVE:
1261                                         /* The WM_SIZE and WM_MOVE messages are not sent if an application handles the 
1262                                          * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
1263                                          * to perform any move or size change processing during the WM_WINDOWPOSCHANGED 
1264                                          * message without calling DefWindowProc. 
1265                                          */
1266                                         event = processWindowEvent(GHOST_kEventWindowMove, window);
1267                                         break;
1268
1269 #if 0 // this code is illustrative; no need to compile
1270                                 ////////////////////////////////////////////////////////////////////////
1271                                 // Window events, ignored
1272                                 ////////////////////////////////////////////////////////////////////////
1273                                 case WM_WINDOWPOSCHANGED:
1274                                         /* The WM_WINDOWPOSCHANGED message is sent to a window whose size, position, or place
1275                                          * in the Z order has changed as a result of a call to the SetWindowPos function or 
1276                                          * another window-management function.
1277                                          * The WM_SIZE and WM_MOVE messages are not sent if an application handles the 
1278                                          * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
1279                                          * to perform any move or size change processing during the WM_WINDOWPOSCHANGED 
1280                                          * message without calling DefWindowProc.
1281                                          */
1282                                 case WM_ERASEBKGND:
1283                                         /* An application sends the WM_ERASEBKGND message when the window background must be 
1284                                          * erased (for example, when a window is resized). The message is sent to prepare an 
1285                                          * invalidated portion of a window for painting. 
1286                                          */
1287                                 case WM_NCPAINT:
1288                                         /* An application sends the WM_NCPAINT message to a window when its frame must be painted. */
1289                                 case WM_NCACTIVATE:
1290                                         /* The WM_NCACTIVATE message is sent to a window when its nonclient area needs to be changed 
1291                                          * to indicate an active or inactive state. 
1292                                          */
1293                                 case WM_DESTROY:
1294                                         /* The WM_DESTROY message is sent when a window is being destroyed. It is sent to the window 
1295                                          * procedure of the window being destroyed after the window is removed from the screen. 
1296                                          * This message is sent first to the window being destroyed and then to the child windows 
1297                                          * (if any) as they are destroyed. During the processing of the message, it can be assumed 
1298                                          * that all child windows still exist. 
1299                                          */
1300                                 case WM_NCDESTROY:
1301                                         /* The WM_NCDESTROY message informs a window that its nonclient area is being destroyed. The 
1302                                          * DestroyWindow function sends the WM_NCDESTROY message to the window following the WM_DESTROY
1303                                          * message. WM_DESTROY is used to free the allocated memory object associated with the window. 
1304                                          */
1305                                 case WM_KILLFOCUS:
1306                                         /* The WM_KILLFOCUS message is sent to a window immediately before it loses the keyboard focus. */
1307                                 case WM_SHOWWINDOW:
1308                                         /* The WM_SHOWWINDOW message is sent to a window when the window is about to be hidden or shown. */
1309                                 case WM_WINDOWPOSCHANGING:
1310                                         /* The WM_WINDOWPOSCHANGING message is sent to a window whose size, position, or place in 
1311                                          * the Z order is about to change as a result of a call to the SetWindowPos function or 
1312                                          * another window-management function. 
1313                                          */
1314                                 case WM_SETFOCUS:
1315                                         /* The WM_SETFOCUS message is sent to a window after it has gained the keyboard focus. */
1316                                 case WM_ENTERSIZEMOVE:
1317                                         /* The WM_ENTERSIZEMOVE message is sent one time to a window after it enters the moving 
1318                                          * or sizing modal loop. The window enters the moving or sizing modal loop when the user 
1319                                          * clicks the window's title bar or sizing border, or when the window passes the 
1320                                          * WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the 
1321                                          * message specifies the SC_MOVE or SC_SIZE value. The operation is complete when 
1322                                          * DefWindowProc returns. 
1323                                          */
1324                                         break;
1325                                         
1326                                 ////////////////////////////////////////////////////////////////////////
1327                                 // Other events
1328                                 ////////////////////////////////////////////////////////////////////////
1329                                 case WM_GETTEXT:
1330                                         /* An application sends a WM_GETTEXT message to copy the text that 
1331                                          * corresponds to a window into a buffer provided by the caller. 
1332                                          */
1333                                 case WM_ACTIVATEAPP:
1334                                         /* The WM_ACTIVATEAPP message is sent when a window belonging to a 
1335                                          * different application than the active window is about to be activated.
1336                                          * The message is sent to the application whose window is being activated
1337                                          * and to the application whose window is being deactivated. 
1338                                          */
1339                                 case WM_TIMER:
1340                                         /* The WIN32 docs say:
1341                                          * The WM_TIMER message is posted to the installing thread's message queue
1342                                          * when a timer expires. You can process the message by providing a WM_TIMER
1343                                          * case in the window procedure. Otherwise, the default window procedure will
1344                                          * call the TimerProc callback function specified in the call to the SetTimer
1345                                          * function used to install the timer. 
1346                                          *
1347                                          * In GHOST, we let DefWindowProc call the timer callback.
1348                                          */
1349                                         break;
1350 #endif // illustrative code
1351
1352 #if 0 // this is part of the 'old' NDOF system; new one coming soon!
1353                                 case WM_BLND_NDOF_AXIS:
1354                                         {
1355                                                 GHOST_TEventNDOFData ndofdata;
1356                                                 m_ndofManager->GHOST_NDOFGetDatas(ndofdata);
1357                                                 m_eventManager->
1358                                                         pushEvent(new GHOST_EventNDOF(
1359                                                                 getMilliSeconds(),
1360                                                                 GHOST_kEventNDOFMotion,
1361                                                                 window, ndofdata));
1362                                         }
1363                                         break;
1364                                 case WM_BLND_NDOF_BTN:
1365                                         {
1366                                                 GHOST_TEventNDOFData ndofdata;
1367                                                 m_ndofManager->GHOST_NDOFGetDatas(ndofdata);
1368                                                 m_eventManager->
1369                                                         pushEvent(new GHOST_EventNDOF(
1370                                                                 getMilliSeconds(),
1371                                                                 GHOST_kEventNDOFButton,
1372                                                                 window, ndofdata));
1373                                         }
1374                                         break;
1375 #endif // old NDOF
1376                         }
1377
1378         if (!eventSent)
1379                 if (event) {
1380                         pushEvent(event);
1381                         eventSent = true;
1382                 }
1383
1384         return eventSent;
1385 }
1386
1387 GHOST_TUns8* GHOST_SystemWin32::getClipboard(bool selection) const
1388 {
1389         char *buffer;
1390         char *temp_buff;
1391         
1392         if ( IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(NULL) ) {
1393                 HANDLE hData = GetClipboardData( CF_TEXT );
1394                 if (hData == NULL) {
1395                         CloseClipboard();
1396                         return NULL;
1397                 }
1398                 buffer = (char*)GlobalLock( hData );
1399                 
1400                 temp_buff = (char*) malloc(strlen(buffer)+1);
1401                 strcpy(temp_buff, buffer);
1402                 
1403                 GlobalUnlock( hData );
1404                 CloseClipboard();
1405                 
1406                 temp_buff[strlen(buffer)] = '\0';
1407                 if (buffer) {
1408                         return (GHOST_TUns8*)temp_buff;
1409                 } else {
1410                         return NULL;
1411                 }
1412         } else {
1413                 return NULL;
1414         }
1415 }
1416
1417 void GHOST_SystemWin32::putClipboard(GHOST_TInt8 *buffer, bool selection) const
1418 {
1419         if(selection) {return;} // for copying the selection, used on X11
1420
1421         if (OpenClipboard(NULL)) {
1422                 HLOCAL clipbuffer;
1423                 char *data;
1424                 
1425                 if (buffer) {
1426                         EmptyClipboard();
1427                         
1428                         clipbuffer = LocalAlloc(LMEM_FIXED,((strlen(buffer)+1)));
1429                         data = (char*)GlobalLock(clipbuffer);
1430
1431                         strcpy(data, (char*)buffer);
1432                         data[strlen(buffer)] = '\0';
1433                         LocalUnlock(clipbuffer);
1434                         SetClipboardData(CF_TEXT,clipbuffer);
1435                 }
1436                 CloseClipboard();
1437         } else {
1438                 return;
1439         }
1440 }
1441
1442 const GHOST_TUns8* GHOST_SystemWin32::getSystemDir() const
1443 {
1444         return NULL;
1445 }
1446
1447 const GHOST_TUns8* GHOST_SystemWin32::getUserDir() const
1448 {
1449         return NULL;
1450 }