64086200a99eb567fb94ac3441498e15141fd624
[occt.git] / src / WNT / WNT_Window.cxx
1 // Copyright (c) 1998-1999 Matra Datavision
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15 #if defined(_WIN32)
16   // include windows.h first to have all definitions available
17   #include <windows.h>
18 #endif
19
20 #include <WNT_Window.hxx>
21
22 #if defined(_WIN32) && !defined(OCCT_UWP)
23
24 #include <Aspect_Convert.hxx>
25 #include <Aspect_WindowDefinitionError.hxx>
26 #include <Aspect_WindowError.hxx>
27 #include <Message.hxx>
28 #include <Standard_Type.hxx>
29 #include <TCollection_ExtendedString.hxx>
30 #include <WNT_WClass.hxx>
31
32 IMPLEMENT_STANDARD_RTTIEXT(WNT_Window, Aspect_Window)
33
34 // =======================================================================
35 // function : WNT_Window
36 // purpose  :
37 // =======================================================================
38 WNT_Window::WNT_Window (const Standard_CString           theTitle,
39                         const Handle(WNT_WClass)&        theClass,
40                         const WNT_Dword&                 theStyle,
41                         const Standard_Integer           thePxLeft,
42                         const Standard_Integer           thePxTop,
43                         const Standard_Integer           thePxWidth,
44                         const Standard_Integer           thePxHeight,
45                         const Quantity_NameOfColor       theBackColor,
46                         const Aspect_Handle              theParent,
47                         const Aspect_Handle              theMenu,
48                         const Standard_Address           theClientStruct)
49 : Aspect_Window(),
50   aXLeft (thePxLeft),
51   aYTop (thePxTop),
52   aXRight (thePxLeft + thePxWidth),
53   aYBottom (thePxTop + thePxHeight),
54   myWClass (theClass),
55   myIsForeign (Standard_False)
56 {
57   if (thePxWidth <= 0 || thePxHeight <= 0)
58   {
59     throw Aspect_WindowDefinitionError("Coordinate(s) out of range");
60   }
61
62   DWORD aStyle = theStyle;
63   if (theParent && !(theStyle & WS_CHILD))
64   {
65     aStyle |= WS_CHILD | WS_CLIPSIBLINGS;
66   }
67   else if (!theParent && !(theStyle & WS_CLIPCHILDREN))
68   {
69     aStyle |= WS_CLIPCHILDREN;
70   }
71
72   // include decorations in the window dimensions to reproduce same behavior of Xw_Window
73   RECT aRect;
74   aRect.top    = aYTop;
75   aRect.bottom = aYBottom;
76   aRect.left   = aXLeft;
77   aRect.right  = aXRight;
78   AdjustWindowRect (&aRect, aStyle, theMenu != NULL ? TRUE : FALSE);
79   aXLeft   = aRect.left;
80   aYTop    = aRect.top;
81   aXRight  = aRect.right;
82   aYBottom = aRect.bottom;
83
84   const TCollection_ExtendedString aTitleW (theTitle);
85   const TCollection_ExtendedString aClassNameW (myWClass->Name());
86   myHWindow = CreateWindowW (aClassNameW.ToWideString(), aTitleW.ToWideString(),
87                              aStyle,
88                              aXLeft, aYTop,
89                              (aXRight - aXLeft), (aYBottom - aYTop),
90                              (HWND )theParent,
91                              (HMENU )theMenu,
92                              (HINSTANCE )myWClass->Instance(),
93                              theClientStruct);
94   if (!myHWindow)
95   {
96     throw Aspect_WindowDefinitionError("Unable to create window");
97   }
98
99   myHParentWindow = theParent;
100   SetBackground (theBackColor);
101 }
102
103 // =======================================================================
104 // function : WNT_Window
105 // purpose  :
106 // =======================================================================
107 WNT_Window::WNT_Window (const Aspect_Handle        theHandle,
108                         const Quantity_NameOfColor theBackColor)
109 : myIsForeign (Standard_True)
110 {
111   myHWindow        = theHandle;
112   myHParentWindow  = GetParent ((HWND )theHandle);
113
114   SetBackground (theBackColor);
115
116   WINDOWPLACEMENT aPlace;
117   aPlace.length = sizeof (WINDOWPLACEMENT);
118   ::GetWindowPlacement ((HWND )myHWindow, &aPlace);
119
120   aXLeft   = aPlace.rcNormalPosition.left;
121   aYTop    = aPlace.rcNormalPosition.top;
122   aXRight  = aPlace.rcNormalPosition.right;
123   aYBottom = aPlace.rcNormalPosition.bottom;
124 }
125
126 // =======================================================================
127 // function : ~WNT_Window
128 // purpose  :
129 // =======================================================================
130 WNT_Window::~WNT_Window()
131 {
132   if (myHWindow == NULL
133    || myIsForeign)
134   {
135     return;
136   }
137
138   DestroyWindow ((HWND )myHWindow);
139   myIsForeign = Standard_False;
140 }
141
142 // =======================================================================
143 // function : SetCursor
144 // purpose  :
145 // =======================================================================
146 void WNT_Window::SetCursor (const Aspect_Handle theCursor) const
147 {
148   ::SetClassLongPtrW ((HWND )myHWindow, GCLP_HCURSOR, (LONG_PTR )theCursor);
149 }
150
151 // =======================================================================
152 // function : IsMapped
153 // purpose  :
154 // =======================================================================
155 Standard_Boolean WNT_Window::IsMapped() const
156 {
157   if (IsVirtual())
158   {
159     return Standard_True;
160   }
161
162   WINDOWPLACEMENT aPlace;
163   aPlace.length = sizeof (WINDOWPLACEMENT);
164   ::GetWindowPlacement ((HWND )myHWindow, &aPlace);
165   return !(aPlace.showCmd == SW_HIDE
166         || aPlace.showCmd == SW_MINIMIZE);
167 }
168
169 // =======================================================================
170 // function : Map
171 // purpose  :
172 // =======================================================================
173 void WNT_Window::Map() const
174 {
175   if (!IsVirtual())
176   {
177     Map (SW_SHOW);
178   }
179 }
180
181 // =======================================================================
182 // function : Map
183 // purpose  :
184 // =======================================================================
185 void WNT_Window::Map (const Standard_Integer theMapMode) const
186 {
187   if (IsVirtual())
188   {
189     return;
190   }
191
192   ::ShowWindow   ((HWND )myHWindow, theMapMode);
193   ::UpdateWindow ((HWND )myHWindow);
194 }
195
196 // =======================================================================
197 // function : Unmap
198 // purpose  :
199 // =======================================================================
200 void WNT_Window::Unmap() const
201 {
202   Map (SW_HIDE);
203 }
204
205 // =======================================================================
206 // function : DoResize
207 // purpose  :
208 // =======================================================================
209 Aspect_TypeOfResize WNT_Window::DoResize()
210 {
211   if (IsVirtual())
212   {
213     return Aspect_TOR_UNKNOWN;
214   }
215
216   int                 mask = 0;
217   Aspect_TypeOfResize mode = Aspect_TOR_UNKNOWN;
218   WINDOWPLACEMENT     wp;
219
220   wp.length = sizeof ( WINDOWPLACEMENT );
221   GetWindowPlacement (  ( HWND )myHWindow, &wp  );
222
223   if (wp.showCmd != SW_SHOWMINIMIZED)
224   {
225     if (Abs ((int )wp.rcNormalPosition.left   - aXLeft  ) > 2) mask |= 1;
226     if (Abs ((int )wp.rcNormalPosition.right  - aXRight ) > 2) mask |= 2;
227     if (Abs ((int )wp.rcNormalPosition.top    - aYTop   ) > 2) mask |= 4;
228     if (Abs ((int )wp.rcNormalPosition.bottom - aYBottom) > 2) mask |= 8;
229
230     switch (mask)
231     {
232       case 0:
233         mode = Aspect_TOR_NO_BORDER;
234         break;
235       case 1:
236         mode = Aspect_TOR_LEFT_BORDER;
237         break;
238       case 2:
239         mode = Aspect_TOR_RIGHT_BORDER;
240         break;
241       case 4:
242         mode = Aspect_TOR_TOP_BORDER;
243         break;
244       case 5:
245         mode = Aspect_TOR_LEFT_AND_TOP_BORDER;
246         break;
247       case 6:
248         mode = Aspect_TOR_TOP_AND_RIGHT_BORDER;
249         break;
250       case 8:
251         mode = Aspect_TOR_BOTTOM_BORDER;
252         break;
253       case 9:
254         mode = Aspect_TOR_BOTTOM_AND_LEFT_BORDER;
255         break;
256       case 10:
257         mode = Aspect_TOR_RIGHT_AND_BOTTOM_BORDER;
258         break;
259       default:
260         break;
261     }  // end switch
262
263     aXLeft   = wp.rcNormalPosition.left;
264     aXRight  = wp.rcNormalPosition.right;
265     aYTop    = wp.rcNormalPosition.top;
266     aYBottom = wp.rcNormalPosition.bottom;
267   }
268
269   return mode;
270 }
271
272 // =======================================================================
273 // function : Ratio
274 // purpose  :
275 // =======================================================================
276 Standard_Real WNT_Window::Ratio() const
277 {
278   if (IsVirtual())
279   {
280     return Standard_Real(aXRight - aXLeft)/ Standard_Real(aYBottom - aYTop);
281   }
282
283   RECT aRect;
284   GetClientRect ((HWND )myHWindow, &aRect);
285   return Standard_Real(aRect.right - aRect.left) / Standard_Real(aRect.bottom - aRect.top);
286 }
287
288 // =======================================================================
289 // function : Position
290 // purpose  :
291 // =======================================================================
292 void WNT_Window::Position (Standard_Integer& theX1, Standard_Integer& theY1,
293                            Standard_Integer& theX2, Standard_Integer& theY2) const
294 {
295   if (IsVirtual())
296   {
297     theX1  = aXLeft;
298     theX2  = aXRight;
299     theY1  = aYTop;
300     theY2  = aYBottom;
301     return;
302   }
303
304   RECT  aRect;
305   ::GetClientRect ((HWND )myHWindow, &aRect);
306
307   POINT aPntLeft, aPntRight;
308   aPntLeft.x = aPntLeft.y = 0;
309   ::ClientToScreen ((HWND )myHWindow, &aPntLeft);
310   aPntRight.x = aRect.right;
311   aPntRight.y = aRect.bottom;
312   ::ClientToScreen ((HWND )myHWindow, &aPntRight);
313
314   if (myHParentWindow != NULL)
315   {
316     ::ScreenToClient ((HWND )myHParentWindow, &aPntLeft);
317     ::ScreenToClient ((HWND )myHParentWindow, &aPntRight);
318   }
319
320   theX1 = aPntLeft.x;
321   theX2 = aPntRight.x;
322   theY1 = aPntLeft.y;
323   theY2 = aPntRight.y;
324 }
325
326 // =======================================================================
327 // function : Size
328 // purpose  :
329 // =======================================================================
330 void WNT_Window::Size (Standard_Integer& theWidth,
331                        Standard_Integer& theHeight) const
332 {
333   if (IsVirtual())
334   {
335     theWidth  = aXRight - aXLeft;
336     theHeight = aYBottom - aYTop;
337     return;
338   }
339
340   RECT aRect;
341   ::GetClientRect ((HWND )myHWindow, &aRect);
342   theWidth  = aRect.right;
343   theHeight = aRect.bottom;
344 }
345
346 // =======================================================================
347 // function : SetPos
348 // purpose  :
349 // =======================================================================
350 void WNT_Window::SetPos (const Standard_Integer theX,  const Standard_Integer theY,
351                          const Standard_Integer theX1, const Standard_Integer theY1)
352 {
353   aXLeft   = theX;
354   aYTop    = theY;
355   aXRight  = theX1;
356   aYBottom = theY1;
357 }
358
359 // =======================================================================
360 // function : SetTitle
361 // purpose  :
362 // =======================================================================
363 void WNT_Window::SetTitle (const TCollection_AsciiString& theTitle)
364 {
365   const TCollection_ExtendedString aTitleW (theTitle);
366   SetWindowTextW ((HWND )myHWindow, aTitleW.ToWideString());
367 }
368
369 // =======================================================================
370 // function : InvalidateContent
371 // purpose  :
372 // =======================================================================
373 void WNT_Window::InvalidateContent (const Handle(Aspect_DisplayConnection)& )
374 {
375   if (myHWindow != NULL)
376   {
377     ::InvalidateRect ((HWND )myHWindow, NULL, TRUE);
378   }
379 }
380
381 // =======================================================================
382 // function : VirtualKeyFromNative
383 // purpose  :
384 // =======================================================================
385 Aspect_VKey WNT_Window::VirtualKeyFromNative (Standard_Integer theKey)
386 {
387   if (theKey >= Standard_Integer('0')
388    && theKey <= Standard_Integer('9'))
389   {
390     return Aspect_VKey((theKey - Standard_Integer('0')) + Aspect_VKey_0);
391   }
392   if (theKey >= Standard_Integer('A')
393    && theKey <= Standard_Integer('Z'))
394   {
395     // main latin alphabet keys
396     return Aspect_VKey((theKey - Standard_Integer('A')) + Aspect_VKey_A);
397   }
398   if (theKey >= VK_F1
399    && theKey <= VK_F24)
400   {
401     // special keys
402     if (theKey <= VK_F12)
403     {
404       return Aspect_VKey((theKey - VK_F1) + Aspect_VKey_F1);
405     }
406     return Aspect_VKey_UNKNOWN;
407   }
408   if (theKey >= VK_NUMPAD0
409    && theKey <= VK_NUMPAD9)
410   {
411     // numpad keys
412     return Aspect_VKey((theKey - VK_NUMPAD0) + Aspect_VKey_Numpad0);
413   }
414
415   switch (theKey)
416   {
417     case VK_LBUTTON:
418     case VK_RBUTTON:
419     case VK_CANCEL:
420     case VK_MBUTTON:
421     case VK_XBUTTON1:
422     case VK_XBUTTON2:
423       return Aspect_VKey_UNKNOWN;
424     case VK_BACK:
425       return Aspect_VKey_Backspace;
426     case VK_TAB:
427       return Aspect_VKey_Tab;
428     case VK_CLEAR:
429       return Aspect_VKey_UNKNOWN;
430     case VK_RETURN:
431       return Aspect_VKey_Enter;
432     case VK_SHIFT:
433       return Aspect_VKey_Shift;
434     case VK_CONTROL:
435       return Aspect_VKey_Control;
436     case VK_MENU:
437       return Aspect_VKey_Alt; //Aspect_VKey_Menu;
438     case VK_PAUSE:
439     case VK_CAPITAL:
440       return Aspect_VKey_UNKNOWN;
441     case VK_ESCAPE:
442       return Aspect_VKey_Escape;
443     case VK_CONVERT:
444     case VK_NONCONVERT:
445     case VK_ACCEPT:
446     case VK_MODECHANGE:
447       return Aspect_VKey_UNKNOWN;
448     case VK_SPACE:
449       return Aspect_VKey_Space;
450     case VK_PRIOR:
451       return Aspect_VKey_PageUp;
452     case VK_NEXT:
453       return Aspect_VKey_PageDown;
454     case VK_END:
455       return Aspect_VKey_End;
456     case VK_HOME:
457       return Aspect_VKey_Home;
458     case VK_LEFT:
459       return Aspect_VKey_Left;
460     case VK_UP:
461       return Aspect_VKey_Up;
462     case VK_DOWN:
463       return Aspect_VKey_Down;
464     case VK_RIGHT:
465       return Aspect_VKey_Right;
466     case VK_SELECT:
467     case VK_PRINT:
468     case VK_EXECUTE:
469     case VK_SNAPSHOT:
470       return Aspect_VKey_UNKNOWN;
471     case VK_INSERT:
472       return Aspect_VKey_UNKNOWN; // Aspect_VKey_Insert
473     case VK_DELETE:
474       return Aspect_VKey_Delete;
475     case VK_HELP:
476     case VK_LWIN:
477     case VK_RWIN:
478     case VK_APPS:
479     case VK_SLEEP:
480       return Aspect_VKey_UNKNOWN;
481     case VK_MULTIPLY:
482       return Aspect_VKey_NumpadMultiply;
483     case VK_ADD:
484       return Aspect_VKey_NumpadAdd;
485     case VK_SEPARATOR:
486     case VK_DECIMAL:
487       return Aspect_VKey_UNKNOWN;
488     case VK_SUBTRACT:
489       return Aspect_VKey_NumpadSubtract;
490     case VK_DIVIDE:
491       return Aspect_VKey_NumpadDivide;
492     case VK_NUMLOCK:
493       return Aspect_VKey_Numlock;
494     case VK_SCROLL:
495       return Aspect_VKey_Scroll;
496     case VK_LSHIFT:
497     case VK_RSHIFT:
498     case VK_LCONTROL:
499     case VK_RCONTROL:
500     case VK_LMENU:
501     case VK_RMENU:
502       return Aspect_VKey_UNKNOWN;
503     case VK_BROWSER_BACK:
504       return Aspect_VKey_BrowserBack;
505     case VK_BROWSER_FORWARD:
506       return Aspect_VKey_BrowserForward;
507     case VK_BROWSER_REFRESH:
508       return Aspect_VKey_BrowserRefresh;
509     case VK_BROWSER_STOP:
510       return Aspect_VKey_BrowserStop;
511     case VK_BROWSER_SEARCH:
512       return Aspect_VKey_BrowserSearch;
513     case VK_BROWSER_FAVORITES:
514       return Aspect_VKey_BrowserFavorites;
515     case VK_BROWSER_HOME:
516       return Aspect_VKey_BrowserHome;
517     case VK_VOLUME_MUTE:
518       return Aspect_VKey_VolumeMute;
519     case VK_VOLUME_DOWN:
520       return Aspect_VKey_VolumeDown;
521     case VK_VOLUME_UP:
522       return Aspect_VKey_VolumeUp;
523     case VK_MEDIA_NEXT_TRACK:
524       return Aspect_VKey_MediaNextTrack;
525     case VK_MEDIA_PREV_TRACK:
526       return Aspect_VKey_MediaPreviousTrack;
527     case VK_MEDIA_STOP:
528       return Aspect_VKey_MediaStop;
529     case VK_MEDIA_PLAY_PAUSE:
530       return Aspect_VKey_MediaPlayPause;
531     case VK_OEM_1:
532       return Aspect_VKey_Semicolon;
533     case VK_OEM_PLUS:
534       return Aspect_VKey_Plus;
535     case VK_OEM_COMMA:
536       return Aspect_VKey_Comma;
537     case VK_OEM_MINUS:
538       return Aspect_VKey_Minus;
539     case VK_OEM_PERIOD:
540       return Aspect_VKey_Period;
541     case VK_OEM_2:
542       return Aspect_VKey_Slash;
543     case VK_OEM_3:
544       return Aspect_VKey_Tilde;
545     case VK_OEM_4:
546       return Aspect_VKey_BracketLeft;
547     case VK_OEM_5:
548       return Aspect_VKey_Backslash;
549     case VK_OEM_6:
550       return Aspect_VKey_BracketRight;
551     case VK_OEM_7:
552       return Aspect_VKey_Apostrophe;
553   }
554   return Aspect_VKey_UNKNOWN;
555 }
556
557 // =======================================================================
558 // function : MouseKeyFlagsFromEvent
559 // purpose  :
560 // =======================================================================
561 Aspect_VKeyFlags WNT_Window::MouseKeyFlagsFromEvent (WPARAM theKeys)
562 {
563   Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE;
564   if ((theKeys & MK_CONTROL) != 0)
565   {
566     aFlags |= Aspect_VKeyFlags_CTRL;
567   }
568   if ((theKeys & MK_SHIFT) != 0)
569   {
570     aFlags |= Aspect_VKeyFlags_SHIFT;
571   }
572   if (GetKeyState (VK_MENU) < 0)
573   {
574     aFlags |= Aspect_VKeyFlags_ALT;
575   }
576   return aFlags;
577 }
578
579 // =======================================================================
580 // function : MouseKeyFlagsAsync
581 // purpose  :
582 // =======================================================================
583 Aspect_VKeyFlags WNT_Window::MouseKeyFlagsAsync()
584 {
585   Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE;
586   if ((GetAsyncKeyState (VK_CONTROL) & 0x8000) != 0)
587   {
588     aFlags |= Aspect_VKeyFlags_CTRL;
589   }
590   if ((GetAsyncKeyState (VK_SHIFT) & 0x8000) != 0)
591   {
592     aFlags |= Aspect_VKeyFlags_SHIFT;
593   }
594   if ((GetAsyncKeyState (VK_MENU) & 0x8000) != 0)
595   {
596     aFlags |= Aspect_VKeyFlags_ALT;
597   }
598   return aFlags;
599 }
600
601 // =======================================================================
602 // function : MouseButtonsFromEvent
603 // purpose  :
604 // =======================================================================
605 Aspect_VKeyMouse WNT_Window::MouseButtonsFromEvent (WPARAM theKeys)
606 {
607   Aspect_VKeyMouse aButtons = Aspect_VKeyMouse_NONE;
608   if ((theKeys & MK_LBUTTON) != 0)
609   {
610     aButtons |= Aspect_VKeyMouse_LeftButton;
611   }
612   if ((theKeys & MK_MBUTTON) != 0)
613   {
614     aButtons |= Aspect_VKeyMouse_MiddleButton;
615   }
616   if ((theKeys & MK_RBUTTON) != 0)
617   {
618     aButtons |= Aspect_VKeyMouse_RightButton;
619   }
620   return aButtons;
621 }
622
623 // =======================================================================
624 // function : MouseButtonsAsync
625 // purpose  :
626 // =======================================================================
627 Aspect_VKeyMouse WNT_Window::MouseButtonsAsync()
628 {
629   Aspect_VKeyMouse aButtons = Aspect_VKeyMouse_NONE;
630   const bool isSwapped = GetSystemMetrics (SM_SWAPBUTTON) != 0;
631
632   if ((GetAsyncKeyState (!isSwapped ? VK_LBUTTON : VK_RBUTTON) & 0x8000) != 0)
633   {
634     aButtons |= Aspect_VKeyMouse_LeftButton;
635   }
636   if ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) != 0)
637   {
638     aButtons |= Aspect_VKeyMouse_MiddleButton;
639   }
640   if ((GetAsyncKeyState (!isSwapped ? VK_RBUTTON : VK_LBUTTON) & 0x8000) != 0)
641   {
642     aButtons |= Aspect_VKeyMouse_RightButton;
643   }
644   return aButtons;
645 }
646
647 // =======================================================================
648 // function : RegisterRawInputDevices
649 // purpose  :
650 // =======================================================================
651 int WNT_Window::RegisterRawInputDevices (unsigned int theRawDeviceMask)
652 {
653   if (IsVirtual()
654    || myHWindow == NULL)
655   {
656     return 0;
657   }
658
659   // hidusage.h
660   enum HidUsagePage { THE_HID_USAGE_PAGE_GENERIC = 0x01 }; // HID_USAGE_PAGE_GENERIC
661   enum HidUsage
662   {
663     THE_HID_USAGE_GENERIC_MOUSE                 = 0x02, // HID_USAGE_GENERIC_MOUSE
664     THE_HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER = 0x08, // HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER
665   };
666
667   int aNbDevices = 0;
668   RAWINPUTDEVICE aRawInDevList[2];
669   if ((theRawDeviceMask & RawInputMask_Mouse) != 0)
670   {
671     // mouse
672     RAWINPUTDEVICE& aRawMouse = aRawInDevList[aNbDevices++];
673     aRawMouse.usUsagePage = THE_HID_USAGE_PAGE_GENERIC;
674     aRawMouse.usUsage     = THE_HID_USAGE_GENERIC_MOUSE;
675     aRawMouse.dwFlags     = RIDEV_INPUTSINK;
676     aRawMouse.hwndTarget  = (HWND )myHWindow;
677   }
678   if ((theRawDeviceMask & RawInputMask_SpaceMouse) != 0)
679   {
680     // space mouse
681     RAWINPUTDEVICE& aRawSpace = aRawInDevList[aNbDevices++];
682     aRawSpace.usUsagePage = THE_HID_USAGE_PAGE_GENERIC;
683     aRawSpace.usUsage     = THE_HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER;
684     aRawSpace.dwFlags     = 0; // RIDEV_DEVNOTIFY
685     aRawSpace.hwndTarget  = (HWND )myHWindow;
686   }
687
688   for (int aTryIter = aNbDevices; aTryIter > 0; --aTryIter)
689   {
690     if (::RegisterRawInputDevices (aRawInDevList, aTryIter, sizeof(aRawInDevList[0])))
691     {
692       return aTryIter;
693     }
694
695     Message::SendTrace (aRawInDevList[aTryIter - 1].usUsage == THE_HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER
696                       ? "Warning: RegisterRawInputDevices() failed to register RAW multi-axis controller input"
697                       : "Warning: RegisterRawInputDevices() failed to register RAW mouse input");
698   }
699   return 0;
700 }
701
702 #endif // _WIN32