| 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 | #include <WNT_HIDSpaceMouse.hxx> |
| 15 | |
| 16 | namespace |
| 17 | { |
| 18 | //! Enumeration of known Space Mouse models. |
| 19 | enum SpacePid |
| 20 | { |
| 21 | // VENDOR_ID_LOGITECH |
| 22 | SpacePid_SpaceMouse = 0xC603, |
| 23 | SpacePid_CADMan = 0xC605, |
| 24 | SpacePid_SpaceMouseClassic = 0xC606, |
| 25 | SpacePid_SpaceBall5000 = 0xC621, |
| 26 | SpacePid_SpaceTraveler = 0xC623, |
| 27 | SpacePid_SpacePilot = 0xC625, |
| 28 | SpacePid_SpaceNavigator = 0xC626, //!< has only 2 "menu" buttons (second one is treated as SpaceVKey_Fit) |
| 29 | SpacePid_SpaceExplorer = 0xC627, //!< 15 buttons |
| 30 | SpacePid_NavigatorForNotebooks = 0xC628, //!< has only 2 "menu" buttons (second one is treated as SpaceVKey_Fit) |
| 31 | SpacePid_SpacePilotPro = 0xC629, //!< 31 buttons |
| 32 | SpacePid_SpaceMousePro = 0xC62B, //!< has only 15 buttons, but codes range from 0 to 26 |
| 33 | // VENDOR_ID_3DCONNEXION |
| 34 | SpacePid_SpaceMouseWireless1 = 0xC62E, //!< [plugged in] has only 2 buttons |
| 35 | SpacePid_SpaceMouseWireless2 = 0xC62F, //!< [wireless] has only 2 buttons |
| 36 | SpacePid_SpaceMouseProWireless1 = 0xC631, //!< [plugged in] has only 15 buttons |
| 37 | SpacePid_SpaceMouseProWireless2 = 0xC632, //!< [wireless] has only 15 buttons |
| 38 | SpacePid_SpaceMouseEnterprise = 0xC633, //!< 31 buttons |
| 39 | SpacePid_SpaceMouseCompact = 0xC635 |
| 40 | }; |
| 41 | |
| 42 | //! Enumeration of known keys available on various Space Mouse models. |
| 43 | enum SpaceVKey |
| 44 | { |
| 45 | SpaceVKey_INVALID = 0, |
| 46 | SpaceVKey_Menu = 1, SpaceVKey_Fit, |
| 47 | SpaceVKey_Top, SpaceVKey_Left, SpaceVKey_Right, SpaceVKey_Front, SpaceVKey_Bottom, SpaceVKey_Back, |
| 48 | SpaceVKey_RollCW, SpaceVKey_RollCCW, |
| 49 | SpaceVKey_ISO1, SpaceVKey_ISO2, |
| 50 | SpaceVKey_1, SpaceVKey_2, SpaceVKey_3, SpaceVKey_4, SpaceVKey_5, SpaceVKey_6, SpaceVKey_7, SpaceVKey_8, SpaceVKey_9, SpaceVKey_10, |
| 51 | SpaceVKey_Esc, SpaceVKey_Alt, SpaceVKey_Shift, SpaceVKey_Ctrl, |
| 52 | SpaceVKey_Rotate, SpaceVKey_PanZoom, SpaceVKey_Dominant, |
| 53 | SpaceVKey_Plus, SpaceVKey_Minus, |
| 54 | }; |
| 55 | |
| 56 | //! The raw value range on tested device is [-350; 350]. |
| 57 | enum { THE_RAW_RANGE_350 = 350 }; |
| 58 | |
| 59 | //! Convert key state bit into virtual key. |
| 60 | static SpaceVKey hidToSpaceKey (unsigned long theProductId, |
| 61 | unsigned short theKeyBit) |
| 62 | { |
| 63 | static const SpaceVKey THE_PILOT_KEYS[] = |
| 64 | { |
| 65 | SpaceVKey_1, SpaceVKey_2, SpaceVKey_3, SpaceVKey_4, SpaceVKey_5, SpaceVKey_6, |
| 66 | SpaceVKey_Top, SpaceVKey_Left, SpaceVKey_Right, SpaceVKey_Front, |
| 67 | SpaceVKey_Esc, SpaceVKey_Alt, SpaceVKey_Shift, SpaceVKey_Ctrl, |
| 68 | SpaceVKey_Fit, SpaceVKey_Menu, |
| 69 | SpaceVKey_Plus, SpaceVKey_Minus, |
| 70 | SpaceVKey_Dominant, SpaceVKey_Rotate |
| 71 | }; |
| 72 | const int THE_NB_PILOT_KEYS = sizeof(THE_PILOT_KEYS) / sizeof(SpaceVKey); |
| 73 | |
| 74 | static const SpaceVKey THE_EXPLORER_KEYS[] = |
| 75 | { |
| 76 | SpaceVKey_1, SpaceVKey_2, |
| 77 | SpaceVKey_Top, SpaceVKey_Left, SpaceVKey_Right, SpaceVKey_Front, |
| 78 | SpaceVKey_Esc, SpaceVKey_Alt, SpaceVKey_Shift, SpaceVKey_Ctrl, |
| 79 | SpaceVKey_Fit, SpaceVKey_Menu, |
| 80 | SpaceVKey_Plus, SpaceVKey_Minus, |
| 81 | SpaceVKey_Rotate |
| 82 | }; |
| 83 | const int THE_NB_EXPLORER_KEYS = sizeof(THE_EXPLORER_KEYS) / sizeof(SpaceVKey); |
| 84 | |
| 85 | // shared by latest 3Dconnexion hardware |
| 86 | static const SpaceVKey THE_SPACEMOUSEPRO_KEYS[] = |
| 87 | { |
| 88 | SpaceVKey_Menu, SpaceVKey_Fit, |
| 89 | SpaceVKey_Top, SpaceVKey_Left, SpaceVKey_Right, SpaceVKey_Front, SpaceVKey_Bottom, SpaceVKey_Back, |
| 90 | SpaceVKey_RollCW, SpaceVKey_RollCCW, SpaceVKey_ISO1, SpaceVKey_ISO2, |
| 91 | SpaceVKey_1, SpaceVKey_2, SpaceVKey_3, SpaceVKey_4, |
| 92 | SpaceVKey_5, SpaceVKey_6, SpaceVKey_7, SpaceVKey_8, SpaceVKey_9, SpaceVKey_10, |
| 93 | SpaceVKey_Esc, SpaceVKey_Alt, SpaceVKey_Shift, SpaceVKey_Ctrl, |
| 94 | SpaceVKey_Rotate, |
| 95 | SpaceVKey_PanZoom, SpaceVKey_Dominant, SpaceVKey_Plus, SpaceVKey_Minus |
| 96 | }; |
| 97 | const int THE_NB_SPACEMOUSEPRO_KEYS = sizeof(THE_SPACEMOUSEPRO_KEYS) / sizeof(SpaceVKey); |
| 98 | |
| 99 | switch (theProductId) |
| 100 | { |
| 101 | case SpacePid_SpacePilot: |
| 102 | return theKeyBit < THE_NB_PILOT_KEYS ? THE_PILOT_KEYS[theKeyBit] : SpaceVKey_INVALID; |
| 103 | case SpacePid_SpaceExplorer: |
| 104 | return theKeyBit < THE_NB_EXPLORER_KEYS ? THE_EXPLORER_KEYS[theKeyBit] : SpaceVKey_INVALID; |
| 105 | case SpacePid_SpaceNavigator: |
| 106 | case SpacePid_NavigatorForNotebooks: |
| 107 | case SpacePid_SpacePilotPro: |
| 108 | case SpacePid_SpaceMousePro: |
| 109 | case SpacePid_SpaceMouseWireless1: |
| 110 | case SpacePid_SpaceMouseWireless2: |
| 111 | case SpacePid_SpaceMouseProWireless1: |
| 112 | case SpacePid_SpaceMouseProWireless2: |
| 113 | case SpacePid_SpaceMouseEnterprise: |
| 114 | case SpacePid_SpaceMouseCompact: |
| 115 | return theKeyBit < THE_NB_SPACEMOUSEPRO_KEYS ? THE_SPACEMOUSEPRO_KEYS[theKeyBit] : SpaceVKey_INVALID; |
| 116 | } |
| 117 | return SpaceVKey_INVALID; |
| 118 | } |
| 119 | |
| 120 | } |
| 121 | |
| 122 | // ======================================================================= |
| 123 | // function : WNT_HIDSpaceMouse |
| 124 | // purpose : |
| 125 | // ======================================================================= |
| 126 | WNT_HIDSpaceMouse::WNT_HIDSpaceMouse (unsigned long theProductId, |
| 127 | const Standard_Byte* theData, |
| 128 | Standard_Size theSize) |
| 129 | : myData (theData), |
| 130 | mySize (theSize), |
| 131 | myProductId (theProductId), |
| 132 | myValueRange (THE_RAW_RANGE_350) |
| 133 | { |
| 134 | // |
| 135 | } |
| 136 | |
| 137 | // ======================================================================= |
| 138 | // function : IsKnownProduct |
| 139 | // purpose : |
| 140 | // ======================================================================= |
| 141 | bool WNT_HIDSpaceMouse::IsKnownProduct (unsigned long theProductId) |
| 142 | { |
| 143 | switch (theProductId) |
| 144 | { |
| 145 | case SpacePid_SpacePilot: |
| 146 | case SpacePid_SpaceExplorer: |
| 147 | case SpacePid_SpaceNavigator: |
| 148 | case SpacePid_NavigatorForNotebooks: |
| 149 | case SpacePid_SpacePilotPro: |
| 150 | case SpacePid_SpaceMousePro: |
| 151 | case SpacePid_SpaceMouseWireless1: |
| 152 | case SpacePid_SpaceMouseWireless2: |
| 153 | case SpacePid_SpaceMouseProWireless1: |
| 154 | case SpacePid_SpaceMouseProWireless2: |
| 155 | case SpacePid_SpaceMouseEnterprise: |
| 156 | case SpacePid_SpaceMouseCompact: |
| 157 | return true; |
| 158 | } |
| 159 | return false; |
| 160 | } |
| 161 | |
| 162 | // ======================================================================= |
| 163 | // function : Translation |
| 164 | // purpose : |
| 165 | // ======================================================================= |
| 166 | Graphic3d_Vec3d WNT_HIDSpaceMouse::Translation (bool& theIsIdle, |
| 167 | bool theIsQuadric) const |
| 168 | { |
| 169 | theIsIdle = true; |
| 170 | return myData[0] == SpaceRawInput_Translation |
| 171 | && (mySize == 7 || mySize == 13) |
| 172 | ? fromRawVec3 (theIsIdle, myData + 1, true, theIsQuadric) |
| 173 | : Graphic3d_Vec3d(); |
| 174 | } |
| 175 | |
| 176 | // ======================================================================= |
| 177 | // function : Rotation |
| 178 | // purpose : |
| 179 | // ======================================================================= |
| 180 | Graphic3d_Vec3d WNT_HIDSpaceMouse::Rotation (bool& theIsIdle, |
| 181 | bool theIsQuadric) const |
| 182 | { |
| 183 | theIsIdle = true; |
| 184 | if (myData[0] == SpaceRawInput_Rotation && mySize == 7) |
| 185 | { |
| 186 | return fromRawVec3 (theIsIdle, myData + 1, false, theIsQuadric); |
| 187 | } |
| 188 | else if (myData[0] == SpaceRawInput_Translation && mySize == 13) |
| 189 | { |
| 190 | return fromRawVec3 (theIsIdle, myData + 7, false, theIsQuadric); |
| 191 | } |
| 192 | return Graphic3d_Vec3d(); |
| 193 | } |
| 194 | |
| 195 | // ======================================================================= |
| 196 | // function : fromRawVec3 |
| 197 | // purpose : |
| 198 | // ======================================================================= |
| 199 | Graphic3d_Vec3d WNT_HIDSpaceMouse::fromRawVec3 (bool& theIsIdle, |
| 200 | const Standard_Byte* theData, |
| 201 | bool theIsTrans, |
| 202 | bool theIsQuadric) const |
| 203 | { |
| 204 | theIsIdle = true; |
| 205 | const NCollection_Vec3<int16_t>& aRaw16 = *reinterpret_cast<const NCollection_Vec3<int16_t>*>(theData); |
| 206 | Graphic3d_Vec3d aVec (aRaw16.x(), aRaw16.y(), aRaw16.z()); |
| 207 | if (theIsTrans) |
| 208 | { |
| 209 | static const int16_t THE_MIN_RAW_TRANS = 4; |
| 210 | static const int16_t THE_MIN_RAW_TRANS_Z = 8; |
| 211 | for (int aCompIter = 0; aCompIter < 3; ++aCompIter) |
| 212 | { |
| 213 | if (aRaw16[aCompIter] > -THE_MIN_RAW_TRANS && aRaw16[aCompIter] < THE_MIN_RAW_TRANS) |
| 214 | { |
| 215 | aVec[aCompIter] = 0.0; |
| 216 | } |
| 217 | else |
| 218 | { |
| 219 | theIsIdle = false; |
| 220 | } |
| 221 | } |
| 222 | if (aRaw16.z() > -THE_MIN_RAW_TRANS_Z && aRaw16.z() < THE_MIN_RAW_TRANS_Z) |
| 223 | { |
| 224 | aVec.z() = 0.0; |
| 225 | } |
| 226 | } |
| 227 | else |
| 228 | { |
| 229 | for (int aCompIter = 0; aCompIter < 3; ++aCompIter) |
| 230 | { |
| 231 | if (aRaw16[aCompIter] != 0) |
| 232 | { |
| 233 | theIsIdle = false; |
| 234 | break; |
| 235 | } |
| 236 | } |
| 237 | } |
| 238 | |
| 239 | // determine raw value range |
| 240 | for (int aCompIter = 0; aCompIter < 3; ++aCompIter) |
| 241 | { |
| 242 | if (aRaw16[aCompIter] > myValueRange |
| 243 | || -aRaw16[aCompIter] > myValueRange) |
| 244 | { |
| 245 | myValueRange = 32767; // SHRT_MAX |
| 246 | break; |
| 247 | } |
| 248 | } |
| 249 | |
| 250 | if (!theIsQuadric) |
| 251 | { |
| 252 | return aVec / double(myValueRange); |
| 253 | } |
| 254 | |
| 255 | for (int aCompIter = 0; aCompIter < 3; ++aCompIter) |
| 256 | { |
| 257 | aVec[aCompIter] = aRaw16[aCompIter] > 0 |
| 258 | ? aVec[aCompIter] * aVec[aCompIter] |
| 259 | : -aVec[aCompIter] * aVec[aCompIter]; |
| 260 | } |
| 261 | return aVec / (double(myValueRange) * double(myValueRange)); |
| 262 | } |
| 263 | |
| 264 | // ======================================================================= |
| 265 | // function : HidToSpaceKey |
| 266 | // purpose : |
| 267 | // ======================================================================= |
| 268 | Aspect_VKey WNT_HIDSpaceMouse::HidToSpaceKey (unsigned short theKeyBit) const |
| 269 | { |
| 270 | const SpaceVKey aKey = hidToSpaceKey (myProductId, theKeyBit); |
| 271 | switch (aKey) |
| 272 | { |
| 273 | case SpaceVKey_1: |
| 274 | case SpaceVKey_2: |
| 275 | case SpaceVKey_3: |
| 276 | case SpaceVKey_4: |
| 277 | case SpaceVKey_5: |
| 278 | case SpaceVKey_6: |
| 279 | case SpaceVKey_7: |
| 280 | case SpaceVKey_8: |
| 281 | case SpaceVKey_9: |
| 282 | case SpaceVKey_10: |
| 283 | return (int(aKey) - int(SpaceVKey_1)) + Aspect_VKey_1; |
| 284 | case SpaceVKey_Esc: |
| 285 | return Aspect_VKey_Escape; |
| 286 | case SpaceVKey_Shift: |
| 287 | return Aspect_VKey_Shift; |
| 288 | case SpaceVKey_Alt: |
| 289 | return Aspect_VKey_Alt; |
| 290 | case SpaceVKey_Ctrl: |
| 291 | return Aspect_VKey_Control; |
| 292 | case SpaceVKey_Top: |
| 293 | return Aspect_VKey_ViewTop; |
| 294 | case SpaceVKey_Bottom: |
| 295 | return Aspect_VKey_ViewBottom; |
| 296 | case SpaceVKey_Left: |
| 297 | return Aspect_VKey_ViewLeft; |
| 298 | case SpaceVKey_Right: |
| 299 | return Aspect_VKey_ViewRight; |
| 300 | case SpaceVKey_Front: |
| 301 | return Aspect_VKey_ViewFront; |
| 302 | case SpaceVKey_Back: |
| 303 | return Aspect_VKey_ViewBack; |
| 304 | case SpaceVKey_ISO1: |
| 305 | return Aspect_VKey_ViewAxoLeftProj; |
| 306 | case SpaceVKey_ISO2: |
| 307 | return Aspect_VKey_ViewAxoRightProj; |
| 308 | case SpaceVKey_Fit: |
| 309 | return Aspect_VKey_ViewFitAll; |
| 310 | case SpaceVKey_RollCW: |
| 311 | return Aspect_VKey_ViewRoll90CW; |
| 312 | case SpaceVKey_RollCCW: |
| 313 | return Aspect_VKey_ViewRoll90CCW; |
| 314 | case SpaceVKey_Rotate: |
| 315 | return Aspect_VKey_ViewSwitchRotate; |
| 316 | default: |
| 317 | break; |
| 318 | } |
| 319 | return Aspect_VKey_UNKNOWN; |
| 320 | } |