0031668: Visualization - WebGL sample doesn't work on Emscripten 1.39
[occt.git] / src / WNT / WNT_HIDSpaceMouse.hxx
1 // Copyright (c) 2019-2020 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #ifndef _WNT_HIDSpaceMouse_Header
15 #define _WNT_HIDSpaceMouse_Header
16
17 #include <Aspect_VKey.hxx>
18 #include <Graphic3d_Vec.hxx>
19
20 //! Wrapper over Space Mouse data chunk within WM_INPUT event (known also as Raw Input in WinAPI).
21 //! This class predefines specific list of supported devices, which does not depend on 3rdparty library provided by mouse vendor.
22 //! Supported input chunks:
23 //! - Rotation (3 directions);
24 //! - Translation (3 directions);
25 //! - Pressed buttons.
26 //!
27 //! To use the class, register Raw Input device:
28 //! @code
29 //!  Handle(WNT_Window) theWindow;
30 //!  RAWINPUTDEVICE aRawInDevList[1];
31 //!  RAWINPUTDEVICE& aRawSpace = aRawInDevList[0];
32 //!  aRawSpace.usUsagePage = HID_USAGE_PAGE_GENERIC;
33 //!  aRawSpace.usUsage     = HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER;
34 //!  aRawSpace.dwFlags     = 0; // RIDEV_DEVNOTIFY
35 //!  aRawSpace.hwndTarget  = (HWND )theWindow->NativeHandle();
36 //!  if (!::RegisterRawInputDevices (aRawInDevList, 1, sizeof(aRawInDevList[0]))) { Error; }
37 //! @endcode
38 //!
39 //! Then handle WM_INPUT events within window message loop.
40 //! @code
41 //!  AIS_ViewController theViewCtrl;
42 //!  case WM_INPUT:
43 //!  {
44 //!    UINT aSize = 0;
45 //!    ::GetRawInputData ((HRAWINPUT )theLParam, RID_INPUT, NULL, &aSize, sizeof(RAWINPUTHEADER));
46 //!    NCollection_LocalArray<BYTE> aRawData (aSize); // receive Raw Input for any device and process known devices
47 //!    if (aSize == 0 || ::GetRawInputData ((HRAWINPUT )theLParam, RID_INPUT, aRawData, &aSize, sizeof(RAWINPUTHEADER)) != aSize)
48 //!    {
49 //!      break;
50 //!    }
51 //!    const RAWINPUT* aRawInput = (RAWINPUT* )(BYTE* )aRawData;
52 //!    if (aRawInput->header.dwType != RIM_TYPEHID)
53 //!    {
54 //!      break;
55 //!    }
56 //!
57 //!    RID_DEVICE_INFO aDevInfo; aDevInfo.cbSize = sizeof(RID_DEVICE_INFO);
58 //!    UINT aDevInfoSize = sizeof(RID_DEVICE_INFO);
59 //!    if (::GetRawInputDeviceInfoW (aRawInput->header.hDevice, RIDI_DEVICEINFO, &aDevInfo, &aDevInfoSize) != sizeof(RID_DEVICE_INFO)
60 //!     || (aDevInfo.hid.dwVendorId != WNT_HIDSpaceMouse::VENDOR_ID_LOGITECH
61 //!      && aDevInfo.hid.dwVendorId != WNT_HIDSpaceMouse::VENDOR_ID_3DCONNEXION))
62 //!    {
63 //!      break;
64 //!    }
65 //!
66 //!    Aspect_VKeySet& aKeys = theViewCtrl.ChangeKeys();
67 //!    const double aTimeStamp = theViewCtrl.EventTime();
68 //!    WNT_HIDSpaceMouse aSpaceData (aDevInfo.hid.dwProductId, aRawInput->data.hid.bRawData, aRawInput->data.hid.dwSizeHid);
69 //!    if (aSpaceData.IsTranslation())
70 //!    {
71 //!      // process translation input
72 //!      bool isIdle = true, isQuadric = true;
73 //!      const Graphic3d_Vec3d aTrans = aSpaceData.Translation (isIdle, isQuadric);
74 //!      aKeys.KeyFromAxis (Aspect_VKey_NavSlideLeft, Aspect_VKey_NavSlideRight, aTimeStamp, aTrans.x());
75 //!      aKeys.KeyFromAxis (Aspect_VKey_NavForward,   Aspect_VKey_NavBackward,   aTimeStamp, aTrans.y());
76 //!      aKeys.KeyFromAxis (Aspect_VKey_NavSlideUp,   Aspect_VKey_NavSlideDown,  aTimeStamp, aTrans.z());
77 //!    }
78 //!    if (aSpaceData.IsRotation()) {} // process rotation input
79 //!    if (aSpaceData.IsKeyState()) {} // process keys input
80 //!    break;
81 //!  }
82 //! @endcode
83 class WNT_HIDSpaceMouse
84 {
85 public:
86   //! Vendor HID identifier.
87   enum { VENDOR_ID_LOGITECH = 0x46D, VENDOR_ID_3DCONNEXION = 0x256F };
88
89   //! Return if product id is known by this class.
90   Standard_EXPORT static bool IsKnownProduct (unsigned long theProductId);
91
92 public:
93   //! Main constructor.
94   Standard_EXPORT WNT_HIDSpaceMouse (unsigned long theProductId,
95                                      const Standard_Byte* theData,
96                                      Standard_Size theSize);
97
98   //! Return the raw value range.
99   int16_t RawValueRange() const { return myValueRange; }
100
101   //! Set the raw value range.
102   void SetRawValueRange (int16_t theRange) { myValueRange = theRange > myValueRange ? theRange : myValueRange; }
103
104   //! Return TRUE if data chunk defines new translation values.
105   bool IsTranslation() const
106   {
107     return myData[0] == SpaceRawInput_Translation
108         && (mySize == 7 || mySize == 13);
109   }
110
111   //! Return new translation values.
112   //! @param theIsIdle [out] flag indicating idle state (no translation)
113   //! @param theIsQuadric [in] flag to apply non-linear scale factor
114   //! @return vector of 3 elements defining translation values within [-1..1] range, 0 meaning idle,
115   //!         .x defining left/right slide, .y defining forward/backward and .z defining up/down slide.
116   Standard_EXPORT Graphic3d_Vec3d Translation (bool& theIsIdle,
117                                                bool theIsQuadric) const;
118
119   //! Return TRUE if data chunk defines new rotation values.
120   bool IsRotation() const
121   {
122     return (myData[0] == SpaceRawInput_Rotation    && mySize == 7)
123         || (myData[0] == SpaceRawInput_Translation && mySize == 13);
124   }
125
126   //! Return new rotation values.
127   //! @param theIsIdle [out] flag indicating idle state (no rotation)
128   //! @param theIsQuadric [in] flag to apply non-linear scale factor
129   //! @return vector of 3 elements defining rotation values within [-1..1] range, 0 meaning idle,
130   //!         .x defining tilt, .y defining roll and .z defining spin.
131   Standard_EXPORT Graphic3d_Vec3d Rotation (bool& theIsIdle,
132                                             bool theIsQuadric) const;
133
134   //! Return TRUE for key state data chunk.
135   bool IsKeyState() const { return myData[0] == SpaceRawInput_KeyState; }
136
137   //! Return new keystate.
138   uint32_t KeyState() const { return *reinterpret_cast<const uint32_t*>(myData + 1); }
139
140   //! Convert key state bit into virtual key.
141   Standard_EXPORT Aspect_VKey HidToSpaceKey (unsigned short theKeyBit) const;
142
143 private:
144
145   //! Translate raw data chunk of 3 int16 values into normalized vec3.
146   //! The values are considered within the range [-350; 350], with 0 as neutral state.
147   Graphic3d_Vec3d fromRawVec3 (bool& theIsIdle,
148                                const Standard_Byte* theData,
149                                bool theIsTrans,
150                                bool theIsQuadric) const;
151
152   //! Data chunk type.
153   enum
154   {
155     SpaceRawInput_Translation = 0x01, //!< translation data chunk
156     SpaceRawInput_Rotation    = 0x02, //!< rotation    data chunk
157     SpaceRawInput_KeyState    = 0x03, //!< keystate    data chunk
158   };
159
160 private:
161   const Standard_Byte* myData;       //!< RAW data chunk
162   Standard_Size        mySize;       //!< size of RAW data chunk
163   unsigned long        myProductId;  //!< product id
164   mutable int16_t      myValueRange; //!< RAW value range
165 };
166
167 #endif // _WNT_HIDSpaceMouse_Header