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