0032306: Draw Harness, ViewerTest - move window message processing to TKService
[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_ScrollDelta.hxx>
26 #include <Aspect_WindowDefinitionError.hxx>
27 #include <Aspect_WindowError.hxx>
28 #include <Aspect_WindowInputListener.hxx>
29 #include <Message.hxx>
30 #include <NCollection_LocalArray.hxx>
31 #include <TCollection_ExtendedString.hxx>
32 #include <WNT_WClass.hxx>
33 #include <WNT_HIDSpaceMouse.hxx>
34
35 IMPLEMENT_STANDARD_RTTIEXT(WNT_Window, Aspect_Window)
36
37 // =======================================================================
38 // function : WNT_Window
39 // purpose  :
40 // =======================================================================
41 WNT_Window::WNT_Window (const Standard_CString           theTitle,
42                         const Handle(WNT_WClass)&        theClass,
43                         const WNT_Dword&                 theStyle,
44                         const Standard_Integer           thePxLeft,
45                         const Standard_Integer           thePxTop,
46                         const Standard_Integer           thePxWidth,
47                         const Standard_Integer           thePxHeight,
48                         const Quantity_NameOfColor       theBackColor,
49                         const Aspect_Handle              theParent,
50                         const Aspect_Handle              theMenu,
51                         const Standard_Address           theClientStruct)
52 : Aspect_Window(),
53   myWClass (theClass),
54   myHWindow (NULL),
55   myHParentWindow (NULL),
56   myXLeft (thePxLeft),
57   myYTop  (thePxTop),
58   myXRight (thePxLeft + thePxWidth),
59   myYBottom (thePxTop + thePxHeight),
60   myIsForeign (Standard_False)
61 {
62   if (thePxWidth <= 0 || thePxHeight <= 0)
63   {
64     throw Aspect_WindowDefinitionError("Coordinate(s) out of range");
65   }
66
67   DWORD aStyle = theStyle;
68   if (theParent && !(theStyle & WS_CHILD))
69   {
70     aStyle |= WS_CHILD | WS_CLIPSIBLINGS;
71   }
72   else if (!theParent && !(theStyle & WS_CLIPCHILDREN))
73   {
74     aStyle |= WS_CLIPCHILDREN;
75   }
76
77   // include decorations in the window dimensions to reproduce same behavior of Xw_Window
78   RECT aRect;
79   aRect.top    = myYTop;
80   aRect.bottom = myYBottom;
81   aRect.left   = myXLeft;
82   aRect.right  = myXRight;
83   AdjustWindowRect (&aRect, aStyle, theMenu != NULL ? TRUE : FALSE);
84   myXLeft   = aRect.left;
85   myYTop    = aRect.top;
86   myXRight  = aRect.right;
87   myYBottom = aRect.bottom;
88
89   const TCollection_ExtendedString aTitleW (theTitle);
90   const TCollection_ExtendedString aClassNameW (myWClass->Name());
91   myHWindow = CreateWindowW (aClassNameW.ToWideString(), aTitleW.ToWideString(),
92                              aStyle,
93                              myXLeft, myYTop,
94                              (myXRight - myXLeft), (myYBottom - myYTop),
95                              (HWND )theParent,
96                              (HMENU )theMenu,
97                              (HINSTANCE )myWClass->Instance(),
98                              theClientStruct);
99   if (!myHWindow)
100   {
101     throw Aspect_WindowDefinitionError("Unable to create window");
102   }
103
104   myHParentWindow = theParent;
105   SetBackground (theBackColor);
106 }
107
108 // =======================================================================
109 // function : WNT_Window
110 // purpose  :
111 // =======================================================================
112 WNT_Window::WNT_Window (const Aspect_Handle        theHandle,
113                         const Quantity_NameOfColor theBackColor)
114 : myHWindow (theHandle),
115   myHParentWindow (GetParent ((HWND )theHandle)),
116   myXLeft (0),
117   myYTop  (0),
118   myXRight (0),
119   myYBottom (0),
120   myIsForeign (Standard_True)
121 {
122   SetBackground (theBackColor);
123
124   WINDOWPLACEMENT aPlace = {};
125   aPlace.length = sizeof(WINDOWPLACEMENT);
126   ::GetWindowPlacement ((HWND )myHWindow, &aPlace);
127
128   myXLeft   = aPlace.rcNormalPosition.left;
129   myYTop    = aPlace.rcNormalPosition.top;
130   myXRight  = aPlace.rcNormalPosition.right;
131   myYBottom = aPlace.rcNormalPosition.bottom;
132 }
133
134 // =======================================================================
135 // function : ~WNT_Window
136 // purpose  :
137 // =======================================================================
138 WNT_Window::~WNT_Window()
139 {
140   if (myHWindow == NULL
141    || myIsForeign)
142   {
143     return;
144   }
145
146   DestroyWindow ((HWND )myHWindow);
147   myIsForeign = Standard_False;
148 }
149
150 // =======================================================================
151 // function : SetCursor
152 // purpose  :
153 // =======================================================================
154 void WNT_Window::SetCursor (const Aspect_Handle theCursor) const
155 {
156   ::SetClassLongPtrW ((HWND )myHWindow, GCLP_HCURSOR, (LONG_PTR )theCursor);
157 }
158
159 // =======================================================================
160 // function : IsMapped
161 // purpose  :
162 // =======================================================================
163 Standard_Boolean WNT_Window::IsMapped() const
164 {
165   if (IsVirtual())
166   {
167     return Standard_True;
168   }
169
170   WINDOWPLACEMENT aPlace = {};
171   aPlace.length = sizeof(WINDOWPLACEMENT);
172   ::GetWindowPlacement ((HWND )myHWindow, &aPlace);
173   return !(aPlace.showCmd == SW_HIDE
174         || aPlace.showCmd == SW_MINIMIZE);
175 }
176
177 // =======================================================================
178 // function : Map
179 // purpose  :
180 // =======================================================================
181 void WNT_Window::Map() const
182 {
183   if (!IsVirtual())
184   {
185     Map (SW_SHOW);
186   }
187 }
188
189 // =======================================================================
190 // function : Map
191 // purpose  :
192 // =======================================================================
193 void WNT_Window::Map (const Standard_Integer theMapMode) const
194 {
195   if (IsVirtual())
196   {
197     return;
198   }
199
200   ::ShowWindow   ((HWND )myHWindow, theMapMode);
201   ::UpdateWindow ((HWND )myHWindow);
202 }
203
204 // =======================================================================
205 // function : Unmap
206 // purpose  :
207 // =======================================================================
208 void WNT_Window::Unmap() const
209 {
210   Map (SW_HIDE);
211 }
212
213 // =======================================================================
214 // function : DoResize
215 // purpose  :
216 // =======================================================================
217 Aspect_TypeOfResize WNT_Window::DoResize()
218 {
219   if (IsVirtual())
220   {
221     return Aspect_TOR_UNKNOWN;
222   }
223
224   WINDOWPLACEMENT aPlace = {};
225   aPlace.length = sizeof(WINDOWPLACEMENT);
226   GetWindowPlacement ((HWND )myHWindow, &aPlace);
227   if (aPlace.showCmd == SW_SHOWMINIMIZED)
228   {
229     return Aspect_TOR_UNKNOWN;
230   }
231
232   int aMask = 0;
233   if (Abs ((int )aPlace.rcNormalPosition.left   - myXLeft  ) > 2) { aMask |= 1; }
234   if (Abs ((int )aPlace.rcNormalPosition.right  - myXRight ) > 2) { aMask |= 2; }
235   if (Abs ((int )aPlace.rcNormalPosition.top    - myYTop   ) > 2) { aMask |= 4; }
236   if (Abs ((int )aPlace.rcNormalPosition.bottom - myYBottom) > 2) { aMask |= 8; }
237
238   myXLeft   = aPlace.rcNormalPosition.left;
239   myXRight  = aPlace.rcNormalPosition.right;
240   myYTop    = aPlace.rcNormalPosition.top;
241   myYBottom = aPlace.rcNormalPosition.bottom;
242   switch (aMask)
243   {
244     case 0:  return Aspect_TOR_NO_BORDER;
245     case 1:  return Aspect_TOR_LEFT_BORDER;
246     case 2:  return Aspect_TOR_RIGHT_BORDER;
247     case 4:  return Aspect_TOR_TOP_BORDER;
248     case 5:  return Aspect_TOR_LEFT_AND_TOP_BORDER;
249     case 6:  return Aspect_TOR_TOP_AND_RIGHT_BORDER;
250     case 8:  return Aspect_TOR_BOTTOM_BORDER;
251     case 9:  return Aspect_TOR_BOTTOM_AND_LEFT_BORDER;
252     case 10: return Aspect_TOR_RIGHT_AND_BOTTOM_BORDER;
253   }
254   return Aspect_TOR_UNKNOWN;
255 }
256
257 // =======================================================================
258 // function : Ratio
259 // purpose  :
260 // =======================================================================
261 Standard_Real WNT_Window::Ratio() const
262 {
263   if (IsVirtual())
264   {
265     return Standard_Real(myXRight - myXLeft)/ Standard_Real(myYBottom - myYTop);
266   }
267
268   RECT aRect = {};
269   GetClientRect ((HWND )myHWindow, &aRect);
270   return Standard_Real(aRect.right - aRect.left) / Standard_Real(aRect.bottom - aRect.top);
271 }
272
273 // =======================================================================
274 // function : Position
275 // purpose  :
276 // =======================================================================
277 void WNT_Window::Position (Standard_Integer& theX1, Standard_Integer& theY1,
278                            Standard_Integer& theX2, Standard_Integer& theY2) const
279 {
280   if (IsVirtual())
281   {
282     theX1  = myXLeft;
283     theX2  = myXRight;
284     theY1  = myYTop;
285     theY2  = myYBottom;
286     return;
287   }
288
289   RECT aRect = {};
290   ::GetClientRect ((HWND )myHWindow, &aRect);
291
292   POINT aPntLeft, aPntRight;
293   aPntLeft.x = aPntLeft.y = 0;
294   ::ClientToScreen ((HWND )myHWindow, &aPntLeft);
295   aPntRight.x = aRect.right;
296   aPntRight.y = aRect.bottom;
297   ::ClientToScreen ((HWND )myHWindow, &aPntRight);
298
299   if (myHParentWindow != NULL)
300   {
301     ::ScreenToClient ((HWND )myHParentWindow, &aPntLeft);
302     ::ScreenToClient ((HWND )myHParentWindow, &aPntRight);
303   }
304
305   theX1 = aPntLeft.x;
306   theX2 = aPntRight.x;
307   theY1 = aPntLeft.y;
308   theY2 = aPntRight.y;
309 }
310
311 // =======================================================================
312 // function : Size
313 // purpose  :
314 // =======================================================================
315 void WNT_Window::Size (Standard_Integer& theWidth,
316                        Standard_Integer& theHeight) const
317 {
318   if (IsVirtual())
319   {
320     theWidth  = myXRight - myXLeft;
321     theHeight = myYBottom - myYTop;
322     return;
323   }
324
325   RECT aRect = {};
326   ::GetClientRect ((HWND )myHWindow, &aRect);
327   theWidth  = aRect.right;
328   theHeight = aRect.bottom;
329 }
330
331 // =======================================================================
332 // function : SetPos
333 // purpose  :
334 // =======================================================================
335 void WNT_Window::SetPos (const Standard_Integer theX,  const Standard_Integer theY,
336                          const Standard_Integer theX1, const Standard_Integer theY1)
337 {
338   myXLeft   = theX;
339   myYTop    = theY;
340   myXRight  = theX1;
341   myYBottom = theY1;
342 }
343
344 // =======================================================================
345 // function : SetTitle
346 // purpose  :
347 // =======================================================================
348 void WNT_Window::SetTitle (const TCollection_AsciiString& theTitle)
349 {
350   const TCollection_ExtendedString aTitleW (theTitle);
351   SetWindowTextW ((HWND )myHWindow, aTitleW.ToWideString());
352 }
353
354 // =======================================================================
355 // function : InvalidateContent
356 // purpose  :
357 // =======================================================================
358 void WNT_Window::InvalidateContent (const Handle(Aspect_DisplayConnection)& )
359 {
360   if (myHWindow != NULL)
361   {
362     ::InvalidateRect ((HWND )myHWindow, NULL, TRUE);
363   }
364 }
365
366 // =======================================================================
367 // function : VirtualKeyFromNative
368 // purpose  :
369 // =======================================================================
370 Aspect_VKey WNT_Window::VirtualKeyFromNative (Standard_Integer theKey)
371 {
372   if (theKey >= Standard_Integer('0')
373    && theKey <= Standard_Integer('9'))
374   {
375     return Aspect_VKey((theKey - Standard_Integer('0')) + Aspect_VKey_0);
376   }
377   if (theKey >= Standard_Integer('A')
378    && theKey <= Standard_Integer('Z'))
379   {
380     // main latin alphabet keys
381     return Aspect_VKey((theKey - Standard_Integer('A')) + Aspect_VKey_A);
382   }
383   if (theKey >= VK_F1
384    && theKey <= VK_F24)
385   {
386     // special keys
387     if (theKey <= VK_F12)
388     {
389       return Aspect_VKey((theKey - VK_F1) + Aspect_VKey_F1);
390     }
391     return Aspect_VKey_UNKNOWN;
392   }
393   if (theKey >= VK_NUMPAD0
394    && theKey <= VK_NUMPAD9)
395   {
396     // numpad keys
397     return Aspect_VKey((theKey - VK_NUMPAD0) + Aspect_VKey_Numpad0);
398   }
399
400   switch (theKey)
401   {
402     case VK_LBUTTON:
403     case VK_RBUTTON:
404     case VK_CANCEL:
405     case VK_MBUTTON:
406     case VK_XBUTTON1:
407     case VK_XBUTTON2:
408       return Aspect_VKey_UNKNOWN;
409     case VK_BACK:
410       return Aspect_VKey_Backspace;
411     case VK_TAB:
412       return Aspect_VKey_Tab;
413     case VK_CLEAR:
414       return Aspect_VKey_UNKNOWN;
415     case VK_RETURN:
416       return Aspect_VKey_Enter;
417     case VK_SHIFT:
418       return Aspect_VKey_Shift;
419     case VK_CONTROL:
420       return Aspect_VKey_Control;
421     case VK_MENU:
422       return Aspect_VKey_Alt; //Aspect_VKey_Menu;
423     case VK_PAUSE:
424     case VK_CAPITAL:
425       return Aspect_VKey_UNKNOWN;
426     case VK_ESCAPE:
427       return Aspect_VKey_Escape;
428     case VK_CONVERT:
429     case VK_NONCONVERT:
430     case VK_ACCEPT:
431     case VK_MODECHANGE:
432       return Aspect_VKey_UNKNOWN;
433     case VK_SPACE:
434       return Aspect_VKey_Space;
435     case VK_PRIOR:
436       return Aspect_VKey_PageUp;
437     case VK_NEXT:
438       return Aspect_VKey_PageDown;
439     case VK_END:
440       return Aspect_VKey_End;
441     case VK_HOME:
442       return Aspect_VKey_Home;
443     case VK_LEFT:
444       return Aspect_VKey_Left;
445     case VK_UP:
446       return Aspect_VKey_Up;
447     case VK_DOWN:
448       return Aspect_VKey_Down;
449     case VK_RIGHT:
450       return Aspect_VKey_Right;
451     case VK_SELECT:
452     case VK_PRINT:
453     case VK_EXECUTE:
454     case VK_SNAPSHOT:
455       return Aspect_VKey_UNKNOWN;
456     case VK_INSERT:
457       return Aspect_VKey_UNKNOWN; // Aspect_VKey_Insert
458     case VK_DELETE:
459       return Aspect_VKey_Delete;
460     case VK_HELP:
461     case VK_LWIN:
462     case VK_RWIN:
463     case VK_APPS:
464     case VK_SLEEP:
465       return Aspect_VKey_UNKNOWN;
466     case VK_MULTIPLY:
467       return Aspect_VKey_NumpadMultiply;
468     case VK_ADD:
469       return Aspect_VKey_NumpadAdd;
470     case VK_SEPARATOR:
471     case VK_DECIMAL:
472       return Aspect_VKey_UNKNOWN;
473     case VK_SUBTRACT:
474       return Aspect_VKey_NumpadSubtract;
475     case VK_DIVIDE:
476       return Aspect_VKey_NumpadDivide;
477     case VK_NUMLOCK:
478       return Aspect_VKey_Numlock;
479     case VK_SCROLL:
480       return Aspect_VKey_Scroll;
481     case VK_LSHIFT:
482     case VK_RSHIFT:
483     case VK_LCONTROL:
484     case VK_RCONTROL:
485     case VK_LMENU:
486     case VK_RMENU:
487       return Aspect_VKey_UNKNOWN;
488     case VK_BROWSER_BACK:
489       return Aspect_VKey_BrowserBack;
490     case VK_BROWSER_FORWARD:
491       return Aspect_VKey_BrowserForward;
492     case VK_BROWSER_REFRESH:
493       return Aspect_VKey_BrowserRefresh;
494     case VK_BROWSER_STOP:
495       return Aspect_VKey_BrowserStop;
496     case VK_BROWSER_SEARCH:
497       return Aspect_VKey_BrowserSearch;
498     case VK_BROWSER_FAVORITES:
499       return Aspect_VKey_BrowserFavorites;
500     case VK_BROWSER_HOME:
501       return Aspect_VKey_BrowserHome;
502     case VK_VOLUME_MUTE:
503       return Aspect_VKey_VolumeMute;
504     case VK_VOLUME_DOWN:
505       return Aspect_VKey_VolumeDown;
506     case VK_VOLUME_UP:
507       return Aspect_VKey_VolumeUp;
508     case VK_MEDIA_NEXT_TRACK:
509       return Aspect_VKey_MediaNextTrack;
510     case VK_MEDIA_PREV_TRACK:
511       return Aspect_VKey_MediaPreviousTrack;
512     case VK_MEDIA_STOP:
513       return Aspect_VKey_MediaStop;
514     case VK_MEDIA_PLAY_PAUSE:
515       return Aspect_VKey_MediaPlayPause;
516     case VK_OEM_1:
517       return Aspect_VKey_Semicolon;
518     case VK_OEM_PLUS:
519       return Aspect_VKey_Plus;
520     case VK_OEM_COMMA:
521       return Aspect_VKey_Comma;
522     case VK_OEM_MINUS:
523       return Aspect_VKey_Minus;
524     case VK_OEM_PERIOD:
525       return Aspect_VKey_Period;
526     case VK_OEM_2:
527       return Aspect_VKey_Slash;
528     case VK_OEM_3:
529       return Aspect_VKey_Tilde;
530     case VK_OEM_4:
531       return Aspect_VKey_BracketLeft;
532     case VK_OEM_5:
533       return Aspect_VKey_Backslash;
534     case VK_OEM_6:
535       return Aspect_VKey_BracketRight;
536     case VK_OEM_7:
537       return Aspect_VKey_Apostrophe;
538   }
539   return Aspect_VKey_UNKNOWN;
540 }
541
542 // =======================================================================
543 // function : MouseKeyFlagsFromEvent
544 // purpose  :
545 // =======================================================================
546 Aspect_VKeyFlags WNT_Window::MouseKeyFlagsFromEvent (WPARAM theKeys)
547 {
548   Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE;
549   if ((theKeys & MK_CONTROL) != 0)
550   {
551     aFlags |= Aspect_VKeyFlags_CTRL;
552   }
553   if ((theKeys & MK_SHIFT) != 0)
554   {
555     aFlags |= Aspect_VKeyFlags_SHIFT;
556   }
557   if (GetKeyState (VK_MENU) < 0)
558   {
559     aFlags |= Aspect_VKeyFlags_ALT;
560   }
561   return aFlags;
562 }
563
564 // =======================================================================
565 // function : MouseKeyFlagsAsync
566 // purpose  :
567 // =======================================================================
568 Aspect_VKeyFlags WNT_Window::MouseKeyFlagsAsync()
569 {
570   Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE;
571   if ((GetAsyncKeyState (VK_CONTROL) & 0x8000) != 0)
572   {
573     aFlags |= Aspect_VKeyFlags_CTRL;
574   }
575   if ((GetAsyncKeyState (VK_SHIFT) & 0x8000) != 0)
576   {
577     aFlags |= Aspect_VKeyFlags_SHIFT;
578   }
579   if ((GetAsyncKeyState (VK_MENU) & 0x8000) != 0)
580   {
581     aFlags |= Aspect_VKeyFlags_ALT;
582   }
583   return aFlags;
584 }
585
586 // =======================================================================
587 // function : MouseButtonsFromEvent
588 // purpose  :
589 // =======================================================================
590 Aspect_VKeyMouse WNT_Window::MouseButtonsFromEvent (WPARAM theKeys)
591 {
592   Aspect_VKeyMouse aButtons = Aspect_VKeyMouse_NONE;
593   if ((theKeys & MK_LBUTTON) != 0)
594   {
595     aButtons |= Aspect_VKeyMouse_LeftButton;
596   }
597   if ((theKeys & MK_MBUTTON) != 0)
598   {
599     aButtons |= Aspect_VKeyMouse_MiddleButton;
600   }
601   if ((theKeys & MK_RBUTTON) != 0)
602   {
603     aButtons |= Aspect_VKeyMouse_RightButton;
604   }
605   return aButtons;
606 }
607
608 // =======================================================================
609 // function : MouseButtonsAsync
610 // purpose  :
611 // =======================================================================
612 Aspect_VKeyMouse WNT_Window::MouseButtonsAsync()
613 {
614   Aspect_VKeyMouse aButtons = Aspect_VKeyMouse_NONE;
615   const bool isSwapped = GetSystemMetrics (SM_SWAPBUTTON) != 0;
616
617   if ((GetAsyncKeyState (!isSwapped ? VK_LBUTTON : VK_RBUTTON) & 0x8000) != 0)
618   {
619     aButtons |= Aspect_VKeyMouse_LeftButton;
620   }
621   if ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) != 0)
622   {
623     aButtons |= Aspect_VKeyMouse_MiddleButton;
624   }
625   if ((GetAsyncKeyState (!isSwapped ? VK_RBUTTON : VK_LBUTTON) & 0x8000) != 0)
626   {
627     aButtons |= Aspect_VKeyMouse_RightButton;
628   }
629   return aButtons;
630 }
631
632 // =======================================================================
633 // function : RegisterRawInputDevices
634 // purpose  :
635 // =======================================================================
636 int WNT_Window::RegisterRawInputDevices (unsigned int theRawDeviceMask)
637 {
638   if (IsVirtual()
639    || myHWindow == NULL)
640   {
641     return 0;
642   }
643
644   // hidusage.h
645   enum HidUsagePage { THE_HID_USAGE_PAGE_GENERIC = 0x01 }; // HID_USAGE_PAGE_GENERIC
646   enum HidUsage
647   {
648     THE_HID_USAGE_GENERIC_MOUSE                 = 0x02, // HID_USAGE_GENERIC_MOUSE
649     THE_HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER = 0x08, // HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER
650   };
651
652   int aNbDevices = 0;
653   RAWINPUTDEVICE aRawInDevList[2];
654   if ((theRawDeviceMask & RawInputMask_Mouse) != 0)
655   {
656     // mouse
657     RAWINPUTDEVICE& aRawMouse = aRawInDevList[aNbDevices++];
658     aRawMouse.usUsagePage = THE_HID_USAGE_PAGE_GENERIC;
659     aRawMouse.usUsage     = THE_HID_USAGE_GENERIC_MOUSE;
660     aRawMouse.dwFlags     = RIDEV_INPUTSINK;
661     aRawMouse.hwndTarget  = (HWND )myHWindow;
662   }
663   if ((theRawDeviceMask & RawInputMask_SpaceMouse) != 0)
664   {
665     // space mouse
666     RAWINPUTDEVICE& aRawSpace = aRawInDevList[aNbDevices++];
667     aRawSpace.usUsagePage = THE_HID_USAGE_PAGE_GENERIC;
668     aRawSpace.usUsage     = THE_HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER;
669     aRawSpace.dwFlags     = 0; // RIDEV_DEVNOTIFY
670     aRawSpace.hwndTarget  = (HWND )myHWindow;
671   }
672
673   for (int aTryIter = aNbDevices; aTryIter > 0; --aTryIter)
674   {
675     if (::RegisterRawInputDevices (aRawInDevList, aTryIter, sizeof(aRawInDevList[0])))
676     {
677       return aTryIter;
678     }
679
680     Message::SendTrace (aRawInDevList[aTryIter - 1].usUsage == THE_HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER
681                       ? "Warning: RegisterRawInputDevices() failed to register RAW multi-axis controller input"
682                       : "Warning: RegisterRawInputDevices() failed to register RAW mouse input");
683   }
684   return 0;
685 }
686
687 // =======================================================================
688 // function : ProcessMessage
689 // purpose  :
690 // =======================================================================
691 bool WNT_Window::ProcessMessage (Aspect_WindowInputListener& theListener,
692                                  MSG& theMsg)
693 {
694   switch (theMsg.message)
695   {
696     case WM_CLOSE:
697     {
698       if (theMsg.hwnd == (HWND )myHWindow)
699       {
700         theListener.ProcessClose();
701         return true;
702       }
703       return false;
704     }
705     case WM_ACTIVATE:
706     {
707       if (theMsg.hwnd == (HWND )myHWindow)
708       {
709         theListener.ProcessFocus (LOWORD(theMsg.wParam) == WA_CLICKACTIVE
710                                || LOWORD(theMsg.wParam) == WA_ACTIVE);
711         return true;
712       }
713       return false;
714     }
715     case WM_PAINT:
716     {
717       PAINTSTRUCT aPaint;
718       BeginPaint(theMsg.hwnd, &aPaint);
719       EndPaint  (theMsg.hwnd, &aPaint);
720       theListener.ProcessExpose();
721       return true;
722     }
723     case WM_SIZE:
724     case WM_MOVE:
725     case WM_MOVING:
726     case WM_SIZING:
727     {
728       theListener.ProcessConfigure (theMsg.message == WM_SIZE);
729       return true;
730     }
731     case WM_KEYUP:
732     case WM_KEYDOWN:
733     {
734       const Aspect_VKey aVKey = WNT_Window::VirtualKeyFromNative ((Standard_Integer )theMsg.wParam);
735       if (aVKey != Aspect_VKey_UNKNOWN)
736       {
737         const double aTimeStamp = theListener.EventTime();
738         if (theMsg.message == WM_KEYDOWN)
739         {
740           theListener.KeyDown (aVKey, aTimeStamp);
741         }
742         else
743         {
744           theListener.KeyUp (aVKey, aTimeStamp);
745         }
746         theListener.ProcessInput();
747       }
748       return true;
749     }
750     case WM_LBUTTONUP:
751     case WM_MBUTTONUP:
752     case WM_RBUTTONUP:
753     case WM_LBUTTONDOWN:
754     case WM_MBUTTONDOWN:
755     case WM_RBUTTONDOWN:
756     {
757       const Graphic3d_Vec2i aPos (LOWORD(theMsg.lParam), HIWORD(theMsg.lParam));
758       const Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent (theMsg.wParam);
759       Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE;
760       switch (theMsg.message)
761       {
762         case WM_LBUTTONUP:
763         case WM_LBUTTONDOWN:
764           aButton = Aspect_VKeyMouse_LeftButton;
765           break;
766         case WM_MBUTTONUP:
767         case WM_MBUTTONDOWN:
768           aButton = Aspect_VKeyMouse_MiddleButton;
769           break;
770         case WM_RBUTTONUP:
771         case WM_RBUTTONDOWN:
772           aButton = Aspect_VKeyMouse_RightButton;
773           break;
774       }
775       if (theMsg.message == WM_LBUTTONDOWN
776        || theMsg.message == WM_MBUTTONDOWN
777        || theMsg.message == WM_RBUTTONDOWN)
778       {
779         SetFocus  (theMsg.hwnd);
780         SetCapture(theMsg.hwnd);
781         theListener.PressMouseButton (aPos, aButton, aFlags, false);
782       }
783       else
784       {
785         ReleaseCapture();
786         theListener.ReleaseMouseButton (aPos, aButton, aFlags, false);
787       }
788       theListener.ProcessInput();
789       return true;
790     }
791     case WM_MOUSEWHEEL:
792     {
793       const int aDelta = GET_WHEEL_DELTA_WPARAM (theMsg.wParam);
794       const Standard_Real aDeltaF = Standard_Real(aDelta) / Standard_Real(WHEEL_DELTA);
795       const Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent (theMsg.wParam);
796       Graphic3d_Vec2i aPos (int(short(LOWORD(theMsg.lParam))), int(short(HIWORD(theMsg.lParam))));
797       POINT aCursorPnt = { aPos.x(), aPos.y() };
798       if (ScreenToClient (theMsg.hwnd, &aCursorPnt))
799       {
800         aPos.SetValues (aCursorPnt.x, aCursorPnt.y);
801       }
802
803       if (theMsg.hwnd != (HWND )myHWindow)
804       {
805         return false;
806       }
807
808       theListener.UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDeltaF, aFlags));
809       theListener.ProcessInput();
810       return true;
811     }
812     case WM_MOUSEMOVE:
813     {
814       Graphic3d_Vec2i aPos (LOWORD(theMsg.lParam), HIWORD(theMsg.lParam));
815       Aspect_VKeyMouse aButtons = WNT_Window::MouseButtonsFromEvent (theMsg.wParam);
816       Aspect_VKeyFlags aFlags   = WNT_Window::MouseKeyFlagsFromEvent(theMsg.wParam);
817
818       // don't make a slide-show from input events - fetch the actual mouse cursor position
819       CURSORINFO aCursor;
820       aCursor.cbSize = sizeof(aCursor);
821       if (::GetCursorInfo (&aCursor) != FALSE)
822       {
823         POINT aCursorPnt = { aCursor.ptScreenPos.x, aCursor.ptScreenPos.y };
824         if (ScreenToClient (theMsg.hwnd, &aCursorPnt))
825         {
826           // as we override mouse position, we need overriding also mouse state
827           aPos.SetValues (aCursorPnt.x, aCursorPnt.y);
828           aButtons = WNT_Window::MouseButtonsAsync();
829           aFlags   = WNT_Window::MouseKeyFlagsAsync();
830         }
831       }
832
833       if (theMsg.hwnd != (HWND )myHWindow)
834       {
835         // mouse move events come also for inactive windows
836         return false;
837       }
838
839       theListener.UpdateMousePosition (aPos, aButtons, aFlags, false);
840       theListener.ProcessInput();
841       return true;
842     }
843     case WM_INPUT:
844     {
845       UINT aSize = 0;
846       ::GetRawInputData ((HRAWINPUT )theMsg.lParam, RID_INPUT, NULL, &aSize, sizeof(RAWINPUTHEADER));
847       NCollection_LocalArray<BYTE> aRawData (aSize);
848       if (aSize == 0 || ::GetRawInputData ((HRAWINPUT )theMsg.lParam, RID_INPUT, aRawData, &aSize, sizeof(RAWINPUTHEADER)) != aSize)
849       {
850         return true;
851       }
852
853       const RAWINPUT* aRawInput = (RAWINPUT* )(BYTE* )aRawData;
854       if (aRawInput->header.dwType != RIM_TYPEHID)
855       {
856         return true;
857       }
858
859       RID_DEVICE_INFO aDevInfo;
860       aDevInfo.cbSize = sizeof(RID_DEVICE_INFO);
861       UINT aDevInfoSize = sizeof(RID_DEVICE_INFO);
862       if (::GetRawInputDeviceInfoW (aRawInput->header.hDevice, RIDI_DEVICEINFO, &aDevInfo, &aDevInfoSize) != sizeof(RID_DEVICE_INFO)
863        || (aDevInfo.hid.dwVendorId != WNT_HIDSpaceMouse::VENDOR_ID_LOGITECH
864         && aDevInfo.hid.dwVendorId != WNT_HIDSpaceMouse::VENDOR_ID_3DCONNEXION))
865       {
866         return true;
867       }
868
869       WNT_HIDSpaceMouse aSpaceData (aDevInfo.hid.dwProductId, aRawInput->data.hid.bRawData, aRawInput->data.hid.dwSizeHid);
870       if (theListener.Update3dMouse (aSpaceData))
871       {
872         InvalidateContent (Handle(Aspect_DisplayConnection)());
873       }
874       return true;
875     }
876   }
877   return false;
878 }
879
880 #endif // _WIN32