//// SpacemouseManager.cpp// interface/src/devices//// Created by MarcelEdward Verhagen on 09-06-15.// Copyright 2015 High Fidelity, Inc.//// Distributed under the Apache License, Version 2.0.// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include "SpacemouseManager.h" #ifdef Q_OS_WIN#include <VersionHelpers.h>#endif #include <UserActivityLogger.h>#include <PathUtils.h> #include <controllers/UserInputMapper.h> const char* SpacemouseManager::NAME { "Spacemouse" }; const float MAX_AXIS = 75.0f; // max forward = 2x speed#define LOGITECH_VENDOR_ID 0x46d #ifndef RIDEV_DEVNOTIFY#define RIDEV_DEVNOTIFY 0x00002000#endif const int TRACE_RIDI_DEVICENAME = 0;const int TRACE_RIDI_DEVICEINFO = 0; #ifdef _WIN64typedef unsigned __int64 QWORD;#endif bool Is3dmouseAttached(); std::shared_ptr<SpacemouseDevice> instance; bool SpacemouseManager::isSupported() const { return Is3dmouseAttached();} bool SpacemouseManager::activate() { fLast3dmouseInputTime = 0; InitializeRawInput(GetActiveWindow()); QAbstractEventDispatcher::instance()->installNativeEventFilter(this); if (!instance) { instance = std::make_shared<SpacemouseDevice>(); } if (instance->getDeviceID() == controller::Input::INVALID_DEVICE) { auto userInputMapper = DependencyManager::get<UserInputMapper>(); userInputMapper->registerDevice(instance); } return true;} void SpacemouseManager::deactivate() { QAbstractEventDispatcher::instance()->removeNativeEventFilter(this); int deviceid = instance->getDeviceID(); auto userInputMapper = DependencyManager::get<UserInputMapper>(); userInputMapper->removeDevice(deviceid);} void SpacemouseManager::pluginFocusOutEvent() { instance->focusOutEvent(); } void SpacemouseManager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) { } SpacemouseDevice::SpacemouseDevice() : InputDevice(SpacemouseManager::NAME){} void SpacemouseDevice::focusOutEvent() { _axisStateMap.clear(); _buttonPressedMap.clear();}; void SpacemouseDevice::handleAxisEvent() { auto rotation = cc_rotation / MAX_AXIS; _axisStateMap[ROTATE_X] = rotation.x; _axisStateMap[ROTATE_Y] = rotation.y; _axisStateMap[ROTATE_Z] = rotation.z; auto position = cc_position / MAX_AXIS; _axisStateMap[TRANSLATE_X] = position.x; _axisStateMap[TRANSLATE_Y] = position.y; _axisStateMap[TRANSLATE_Z] = position.z;} void SpacemouseDevice::setButton(int lastButtonState) { _buttonPressedMap.clear(); _buttonPressedMap.insert(lastButtonState);} controller::Input::NamedVector SpacemouseDevice::getAvailableInputs() const { using namespace controller; static const Input::NamedVector availableInputs{ makePair(BUTTON_1, "LeftButton"), makePair(BUTTON_2, "RightButton"), //makePair(BUTTON_3, "BothButtons"), makePair(TRANSLATE_X, "TranslateX"), makePair(TRANSLATE_Y, "TranslateY"), makePair(TRANSLATE_Z, "TranslateZ"), makePair(ROTATE_X, "RotateX"), makePair(ROTATE_Y, "RotateY"), makePair(ROTATE_Z, "RotateZ"), }; return availableInputs;} QString SpacemouseDevice::getDefaultMappingConfig() const { static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/spacemouse.json"; return MAPPING_JSON;} float SpacemouseDevice::getButton(int channel) const { if (!_buttonPressedMap.empty()) { if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) { return 1.0f; } else { return 0.0f; } } return 0.0f;} float SpacemouseDevice::getAxis(int channel) const { auto axis = _axisStateMap.find(channel); if (axis != _axisStateMap.end()) { return (*axis).second; } else { return 0.0f; }} controller::Input SpacemouseDevice::makeInput(SpacemouseDevice::ButtonChannel button) const { return controller::Input(_deviceID, button, controller::ChannelType::BUTTON);} controller::Input SpacemouseDevice::makeInput(SpacemouseDevice::PositionChannel axis) const { return controller::Input(_deviceID, axis, controller::ChannelType::AXIS);} controller::Input::NamedPair SpacemouseDevice::makePair(SpacemouseDevice::ButtonChannel button, const QString& name) const { return controller::Input::NamedPair(makeInput(button), name);} controller::Input::NamedPair SpacemouseDevice::makePair(SpacemouseDevice::PositionChannel axis, const QString& name) const { return controller::Input::NamedPair(makeInput(axis), name);} void SpacemouseDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) { // the update is done in the SpacemouseManager class. // for windows in the nativeEventFilter the inputmapper is connected or registed or removed when an 3Dconnnexion device is attached or detached // for osx the api will call DeviceAddedHandler or DeviceRemoveHandler when a 3Dconnexion device is attached or detached} #ifdef Q_OS_WIN bool SpacemouseManager::nativeEventFilter(const QByteArray& eventType, void* message, long* result) { MSG* msg = static_cast< MSG * >(message); return RawInputEventFilter(message, result);} //Get an initialized array of PRAWINPUTDEVICE for the 3D devices//pNumDevices returns the number of devices to register. Currently this is always 1.static PRAWINPUTDEVICE GetDevicesToRegister(unsigned int* pNumDevices) { // Array of raw input devices to register static RAWINPUTDEVICE sRawInputDevices[] = { { 0x01, 0x08, 0x00, 0x00 } // Usage Page = 0x01 Generic Desktop Page, Usage Id= 0x08 Multi-axis Controller }; if (pNumDevices) { *pNumDevices = sizeof(sRawInputDevices) / sizeof(sRawInputDevices[0]); } return sRawInputDevices;} //Detect the 3D mousebool Is3dmouseAttached() { unsigned int numDevicesOfInterest = 0; PRAWINPUTDEVICE devicesToRegister = GetDevicesToRegister(&numDevicesOfInterest); unsigned int nDevices = 0; if (::GetRawInputDeviceList(NULL, &nDevices, sizeof(RAWINPUTDEVICELIST)) != 0) { return false; } if (nDevices == 0) { return false; } std::vector<RAWINPUTDEVICELIST> rawInputDeviceList(nDevices); if (::GetRawInputDeviceList(&rawInputDeviceList[0], &nDevices, sizeof(RAWINPUTDEVICELIST)) == static_cast<unsigned int>(-1)) { return false; } for (unsigned int i = 0; i < nDevices; ++i) { RID_DEVICE_INFO rdi = { sizeof(rdi) }; unsigned int cbSize = sizeof(rdi); if (GetRawInputDeviceInfo(rawInputDeviceList[i].hDevice, RIDI_DEVICEINFO, &rdi, &cbSize) > 0) { //skip non HID and non logitec (3DConnexion) devices if (rdi.dwType != RIM_TYPEHID || rdi.hid.dwVendorId != LOGITECH_VENDOR_ID) { continue; } //check if devices matches Multi-axis Controller for (unsigned int j = 0; j < numDevicesOfInterest; ++j) { if (devicesToRegister[j].usUsage == rdi.hid.usUsage && devicesToRegister[j].usUsagePage == rdi.hid.usUsagePage) { return true; } } } } return false;} // object angular velocity per mouse tick 0.008 milliradians per second per countstatic const double k3dmouseAngularVelocity = 8.0e-6; // radians per second per count static const int kTimeToLive = 5; enum ConnexionPid { CONNEXIONPID_SPACEPILOT = 0xc625, CONNEXIONPID_SPACENAVIGATOR = 0xc626, CONNEXIONPID_SPACEEXPLORER = 0xc627, CONNEXIONPID_SPACENAVIGATORFORNOTEBOOKS = 0xc628, CONNEXIONPID_SPACEPILOTPRO = 0xc629}; // e3dmouse_virtual_keyenum V3dk { V3DK_INVALID = 0, V3DK_MENU = 1, V3DK_FIT, V3DK_TOP, V3DK_LEFT, V3DK_RIGHT, V3DK_FRONT, V3DK_BOTTOM, V3DK_BACK, V3DK_CW, V3DK_CCW, V3DK_ISO1, V3DK_ISO2, V3DK_1, V3DK_2, V3DK_3, V3DK_4, V3DK_5, V3DK_6, V3DK_7, V3DK_8, V3DK_9, V3DK_10, V3DK_ESC, V3DK_ALT, V3DK_SHIFT, V3DK_CTRL, V3DK_ROTATE, V3DK_PANZOOM, V3DK_DOMINANT, V3DK_PLUS, V3DK_MINUS}; struct tag_VirtualKeys { ConnexionPid pid; size_t nKeys; V3dk *vkeys;}; // e3dmouse_virtual_keystatic const V3dk SpaceExplorerKeys[] = { V3DK_INVALID, // there is no button 0 V3DK_1, V3DK_2, V3DK_TOP, V3DK_LEFT, V3DK_RIGHT, V3DK_FRONT, V3DK_ESC, V3DK_ALT, V3DK_SHIFT, V3DK_CTRL, V3DK_FIT, V3DK_MENU, V3DK_PLUS, V3DK_MINUS, V3DK_ROTATE}; //e3dmouse_virtual_keystatic const V3dk SpacePilotKeys[] = { V3DK_INVALID, V3DK_1, V3DK_2, V3DK_3, V3DK_4, V3DK_5, V3DK_6, V3DK_TOP, V3DK_LEFT, V3DK_RIGHT, V3DK_FRONT, V3DK_ESC, V3DK_ALT, V3DK_SHIFT, V3DK_CTRL, V3DK_FIT, V3DK_MENU, V3DK_PLUS, V3DK_MINUS, V3DK_DOMINANT, V3DK_ROTATE,}; static const struct tag_VirtualKeys _3dmouseVirtualKeys[] = { CONNEXIONPID_SPACEPILOT, sizeof(SpacePilotKeys) / sizeof(SpacePilotKeys[0]), const_cast<V3dk *>(SpacePilotKeys), CONNEXIONPID_SPACEEXPLORER, sizeof(SpaceExplorerKeys) / sizeof(SpaceExplorerKeys[0]), const_cast<V3dk *>(SpaceExplorerKeys)}; // Converts a hid device keycode (button identifier) of a pre-2009 3Dconnexion USB device to the standard 3d mouse virtual key definition.// pid USB Product ID (PID) of 3D mouse device// hidKeyCode Hid keycode as retrieved from a Raw Input packet// return The standard 3d mouse virtual key (button identifier) or zero if an error occurs. // Converts a hid device keycode (button identifier) of a pre-2009 3Dconnexion USB device// to the standard 3d mouse virtual key definition.unsigned short HidToVirtualKey(unsigned long pid, unsigned short hidKeyCode) { unsigned short virtualkey = hidKeyCode; for (size_t i = 0; i<sizeof(_3dmouseVirtualKeys) / sizeof(_3dmouseVirtualKeys[0]); ++i) { if (pid == _3dmouseVirtualKeys[i].pid) { if (hidKeyCode < _3dmouseVirtualKeys[i].nKeys) { virtualkey = _3dmouseVirtualKeys[i].vkeys[hidKeyCode]; } else { virtualkey = V3DK_INVALID; } break; } } // Remaining devices are unchanged return virtualkey;} bool SpacemouseManager::RawInputEventFilter(void* msg, long* result) { auto userInputMapper = DependencyManager::get<UserInputMapper>(); if (Is3dmouseAttached() && instance->getDeviceID() == controller::Input::INVALID_DEVICE) { userInputMapper->registerDevice(instance); } else if (!Is3dmouseAttached() && instance->getDeviceID() != controller::Input::INVALID_DEVICE) { userInputMapper->removeDevice(instance->getDeviceID()); } if (!Is3dmouseAttached()) { return false; } MSG* message = (MSG*)(msg); if (message->message == WM_INPUT) { HRAWINPUT hRawInput = reinterpret_cast<HRAWINPUT>(message->lParam); OnRawInput(RIM_INPUT, hRawInput); if (result != 0) { result = 0; } return true; } return false;} //Called with the processed motion data when a 3D mouse event is receivedvoid SpacemouseManager::Move3d(HANDLE device, std::vector<float>& motionData) { Q_UNUSED(device); instance->cc_position = { motionData[0] * 1000, motionData[1] * 1000, motionData[2] * 1000 }; instance->cc_rotation = { motionData[3] * 1500, motionData[4] * 1500, motionData[5] * 1500 }; instance->handleAxisEvent();} //Called when a 3D mouse key is pressedvoid SpacemouseManager::On3dmouseKeyDown(HANDLE device, int virtualKeyCode) { Q_UNUSED(device); instance->setButton(virtualKeyCode);} //Called when a 3D mouse key is releasedvoid SpacemouseManager::On3dmouseKeyUp(HANDLE device, int virtualKeyCode) { Q_UNUSED(device); instance->setButton(0);} // Initialize the window to recieve raw-input messages// This needs to be called initially so that Windows will send the messages from the 3D mouse to the window.bool SpacemouseManager::InitializeRawInput(HWND hwndTarget) { fWindow = hwndTarget; // Simply fail if there is no window if (!hwndTarget) { return false; } unsigned int numDevices = 0; PRAWINPUTDEVICE devicesToRegister = GetDevicesToRegister(&numDevices); if (numDevices == 0) { return false; } unsigned int cbSize = sizeof(devicesToRegister[0]); for (size_t i = 0; i < numDevices; i++) { // Set the target window to use //devicesToRegister[i].hwndTarget = hwndTarget; // If Vista or newer, enable receiving the WM_INPUT_DEVICE_CHANGE message. if (IsWindowsVistaOrGreater()) { devicesToRegister[i].dwFlags |= RIDEV_DEVNOTIFY; } } return (::RegisterRawInputDevices(devicesToRegister, numDevices, cbSize) != FALSE);} //Get the raw input data from WindowsUINT SpacemouseManager::GetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader) { //Includes workaround for incorrect alignment of the RAWINPUT structure on x64 os //when running as Wow64 (copied directly from 3DConnexion code)#ifdef _WIN64 return ::GetRawInputBuffer(pData, pcbSize, cbSizeHeader);#else BOOL bIsWow64 = FALSE; ::IsWow64Process(GetCurrentProcess(), &bIsWow64); if (!bIsWow64 || pData == NULL) { return ::GetRawInputBuffer(pData, pcbSize, cbSizeHeader); } else { HWND hwndTarget = fWindow; size_t cbDataSize = 0; UINT nCount = 0; PRAWINPUT pri = pData; MSG msg; while (PeekMessage(&msg, hwndTarget, WM_INPUT, WM_INPUT, PM_NOREMOVE)) { HRAWINPUT hRawInput = reinterpret_cast<HRAWINPUT>(msg.lParam); size_t cbSize = *pcbSize - cbDataSize; if (::GetRawInputData(hRawInput, RID_INPUT, pri, &cbSize, cbSizeHeader) == static_cast<UINT>(-1)) { if (nCount == 0) { return static_cast<UINT>(-1); } else { break; } } ++nCount; // Remove the message for the data just read PeekMessage(&msg, hwndTarget, WM_INPUT, WM_INPUT, PM_REMOVE); pri = NEXTRAWINPUTBLOCK(pri); cbDataSize = reinterpret_cast<ULONG_PTR>(pri)-reinterpret_cast<ULONG_PTR>(pData); if (cbDataSize >= *pcbSize) { cbDataSize = *pcbSize; break; } } return nCount; }#endif} // Process the raw input device data// On3dmouseInput() does all the preprocessing of the rawinput device data before// finally calling the Move3d method.void SpacemouseManager::On3dmouseInput() { // Don't do any data processing in background bool bIsForeground = (::GetActiveWindow() != NULL); if (!bIsForeground) { // set all cached data to zero so that a zero event is seen and the cached data deleted for (std::map<HANDLE, TInputData>::iterator it = fDevice2Data.begin(); it != fDevice2Data.end(); it++) { it->second.fAxes.assign(6, .0); it->second.fIsDirty = true; } } DWORD dwNow = ::GetTickCount(); // Current time; DWORD dwElapsedTime; // Elapsed time since we were last here if (0 == fLast3dmouseInputTime) { dwElapsedTime = 10; // System timer resolution } else { dwElapsedTime = dwNow - fLast3dmouseInputTime; if (fLast3dmouseInputTime > dwNow) { dwElapsedTime = ~dwElapsedTime + 1; } if (dwElapsedTime<1) { dwElapsedTime = 1; } else if (dwElapsedTime > 500) { // Check for wild numbers because the device was removed while sending data dwElapsedTime = 10; } } //qDebug("On3DmouseInput() period is %dms\n", dwElapsedTime); float mouseData2Rotation = k3dmouseAngularVelocity; // v = w * r, we don't know r yet so lets assume r=1.) float mouseData2PanZoom = k3dmouseAngularVelocity; // Grab the I3dmouseParam interface I3dMouseParam& i3dmouseParam = f3dMouseParams; // Take a look at the users preferred speed setting and adjust the sensitivity accordingly I3dMouseSensor::Speed speedSetting = i3dmouseParam.GetSpeed(); // See "Programming for the 3D Mouse", Section 5.1.3 float speed = (speedSetting == I3dMouseSensor::SPEED_LOW ? 0.25f : speedSetting == I3dMouseSensor::SPEED_HIGH ? 4.f : 1.f); // Multiplying by the following will convert the 3d mouse data to real world units mouseData2PanZoom *= speed; mouseData2Rotation *= speed; std::map<HANDLE, TInputData>::iterator iterator = fDevice2Data.begin(); while (iterator != fDevice2Data.end()) {Lines 1–500 of 937. Load more
// // SpacemouseManager.cpp // interface/src/devices // // Created by MarcelEdward Verhagen on 09-06-15. // Copyright 2015 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "SpacemouseManager.h" #ifdef Q_OS_WIN #include <VersionHelpers.h> #endif #include <UserActivityLogger.h> #include <PathUtils.h> #include <controllers/UserInputMapper.h> const char* SpacemouseManager::NAME { "Spacemouse" }; const float MAX_AXIS = 75.0f; // max forward = 2x speed #define LOGITECH_VENDOR_ID 0x46d #ifndef RIDEV_DEVNOTIFY #define RIDEV_DEVNOTIFY 0x00002000 #endif const int TRACE_RIDI_DEVICENAME = 0; const int TRACE_RIDI_DEVICEINFO = 0; #ifdef _WIN64 typedef unsigned __int64 QWORD; #endif bool Is3dmouseAttached(); std::shared_ptr<SpacemouseDevice> instance; bool SpacemouseManager::isSupported() const { return Is3dmouseAttached(); } bool SpacemouseManager::activate() { fLast3dmouseInputTime = 0; InitializeRawInput(GetActiveWindow()); QAbstractEventDispatcher::instance()->installNativeEventFilter(this); if (!instance) { instance = std::make_shared<SpacemouseDevice>(); } if (instance->getDeviceID() == controller::Input::INVALID_DEVICE) { auto userInputMapper = DependencyManager::get<UserInputMapper>(); userInputMapper->registerDevice(instance); } return true; } void SpacemouseManager::deactivate() { QAbstractEventDispatcher::instance()->removeNativeEventFilter(this); int deviceid = instance->getDeviceID(); auto userInputMapper = DependencyManager::get<UserInputMapper>(); userInputMapper->removeDevice(deviceid); } void SpacemouseManager::pluginFocusOutEvent() { instance->focusOutEvent(); } void SpacemouseManager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) { } SpacemouseDevice::SpacemouseDevice() : InputDevice(SpacemouseManager::NAME) { } void SpacemouseDevice::focusOutEvent() { _axisStateMap.clear(); _buttonPressedMap.clear(); }; void SpacemouseDevice::handleAxisEvent() { auto rotation = cc_rotation / MAX_AXIS; _axisStateMap[ROTATE_X] = rotation.x; _axisStateMap[ROTATE_Y] = rotation.y; _axisStateMap[ROTATE_Z] = rotation.z; auto position = cc_position / MAX_AXIS; _axisStateMap[TRANSLATE_X] = position.x; _axisStateMap[TRANSLATE_Y] = position.y; _axisStateMap[TRANSLATE_Z] = position.z; } void SpacemouseDevice::setButton(int lastButtonState) { _buttonPressedMap.clear(); _buttonPressedMap.insert(lastButtonState); } controller::Input::NamedVector SpacemouseDevice::getAvailableInputs() const { using namespace controller; static const Input::NamedVector availableInputs{ makePair(BUTTON_1, "LeftButton"), makePair(BUTTON_2, "RightButton"), //makePair(BUTTON_3, "BothButtons"), makePair(TRANSLATE_X, "TranslateX"), makePair(TRANSLATE_Y, "TranslateY"), makePair(TRANSLATE_Z, "TranslateZ"), makePair(ROTATE_X, "RotateX"), makePair(ROTATE_Y, "RotateY"), makePair(ROTATE_Z, "RotateZ"), }; return availableInputs; } QString SpacemouseDevice::getDefaultMappingConfig() const { static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/spacemouse.json"; return MAPPING_JSON; } float SpacemouseDevice::getButton(int channel) const { if (!_buttonPressedMap.empty()) { if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) { return 1.0f; } else { return 0.0f; } } return 0.0f; } float SpacemouseDevice::getAxis(int channel) const { auto axis = _axisStateMap.find(channel); if (axis != _axisStateMap.end()) { return (*axis).second; } else { return 0.0f; } } controller::Input SpacemouseDevice::makeInput(SpacemouseDevice::ButtonChannel button) const { return controller::Input(_deviceID, button, controller::ChannelType::BUTTON); } controller::Input SpacemouseDevice::makeInput(SpacemouseDevice::PositionChannel axis) const { return controller::Input(_deviceID, axis, controller::ChannelType::AXIS); } controller::Input::NamedPair SpacemouseDevice::makePair(SpacemouseDevice::ButtonChannel button, const QString& name) const { return controller::Input::NamedPair(makeInput(button), name); } controller::Input::NamedPair SpacemouseDevice::makePair(SpacemouseDevice::PositionChannel axis, const QString& name) const { return controller::Input::NamedPair(makeInput(axis), name); } void SpacemouseDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) { // the update is done in the SpacemouseManager class. // for windows in the nativeEventFilter the inputmapper is connected or registed or removed when an 3Dconnnexion device is attached or detached // for osx the api will call DeviceAddedHandler or DeviceRemoveHandler when a 3Dconnexion device is attached or detached } #ifdef Q_OS_WIN bool SpacemouseManager::nativeEventFilter(const QByteArray& eventType, void* message, long* result) { MSG* msg = static_cast< MSG * >(message); return RawInputEventFilter(message, result); } //Get an initialized array of PRAWINPUTDEVICE for the 3D devices //pNumDevices returns the number of devices to register. Currently this is always 1. static PRAWINPUTDEVICE GetDevicesToRegister(unsigned int* pNumDevices) { // Array of raw input devices to register static RAWINPUTDEVICE sRawInputDevices[] = { { 0x01, 0x08, 0x00, 0x00 } // Usage Page = 0x01 Generic Desktop Page, Usage Id= 0x08 Multi-axis Controller }; if (pNumDevices) { *pNumDevices = sizeof(sRawInputDevices) / sizeof(sRawInputDevices[0]); } return sRawInputDevices; } //Detect the 3D mouse bool Is3dmouseAttached() { unsigned int numDevicesOfInterest = 0; PRAWINPUTDEVICE devicesToRegister = GetDevicesToRegister(&numDevicesOfInterest); unsigned int nDevices = 0; if (::GetRawInputDeviceList(NULL, &nDevices, sizeof(RAWINPUTDEVICELIST)) != 0) { return false; } if (nDevices == 0) { return false; } std::vector<RAWINPUTDEVICELIST> rawInputDeviceList(nDevices); if (::GetRawInputDeviceList(&rawInputDeviceList[0], &nDevices, sizeof(RAWINPUTDEVICELIST)) == static_cast<unsigned int>(-1)) { return false; } for (unsigned int i = 0; i < nDevices; ++i) { RID_DEVICE_INFO rdi = { sizeof(rdi) }; unsigned int cbSize = sizeof(rdi); if (GetRawInputDeviceInfo(rawInputDeviceList[i].hDevice, RIDI_DEVICEINFO, &rdi, &cbSize) > 0) { //skip non HID and non logitec (3DConnexion) devices if (rdi.dwType != RIM_TYPEHID || rdi.hid.dwVendorId != LOGITECH_VENDOR_ID) { continue; } //check if devices matches Multi-axis Controller for (unsigned int j = 0; j < numDevicesOfInterest; ++j) { if (devicesToRegister[j].usUsage == rdi.hid.usUsage && devicesToRegister[j].usUsagePage == rdi.hid.usUsagePage) { return true; } } } } return false; } // object angular velocity per mouse tick 0.008 milliradians per second per count static const double k3dmouseAngularVelocity = 8.0e-6; // radians per second per count static const int kTimeToLive = 5; enum ConnexionPid { CONNEXIONPID_SPACEPILOT = 0xc625, CONNEXIONPID_SPACENAVIGATOR = 0xc626, CONNEXIONPID_SPACEEXPLORER = 0xc627, CONNEXIONPID_SPACENAVIGATORFORNOTEBOOKS = 0xc628, CONNEXIONPID_SPACEPILOTPRO = 0xc629 }; // e3dmouse_virtual_key enum V3dk { V3DK_INVALID = 0, V3DK_MENU = 1, V3DK_FIT, V3DK_TOP, V3DK_LEFT, V3DK_RIGHT, V3DK_FRONT, V3DK_BOTTOM, V3DK_BACK, V3DK_CW, V3DK_CCW, V3DK_ISO1, V3DK_ISO2, V3DK_1, V3DK_2, V3DK_3, V3DK_4, V3DK_5, V3DK_6, V3DK_7, V3DK_8, V3DK_9, V3DK_10, V3DK_ESC, V3DK_ALT, V3DK_SHIFT, V3DK_CTRL, V3DK_ROTATE, V3DK_PANZOOM, V3DK_DOMINANT, V3DK_PLUS, V3DK_MINUS }; struct tag_VirtualKeys { ConnexionPid pid; size_t nKeys; V3dk *vkeys; }; // e3dmouse_virtual_key static const V3dk SpaceExplorerKeys[] = { V3DK_INVALID, // there is no button 0 V3DK_1, V3DK_2, V3DK_TOP, V3DK_LEFT, V3DK_RIGHT, V3DK_FRONT, V3DK_ESC, V3DK_ALT, V3DK_SHIFT, V3DK_CTRL, V3DK_FIT, V3DK_MENU, V3DK_PLUS, V3DK_MINUS, V3DK_ROTATE }; //e3dmouse_virtual_key static const V3dk SpacePilotKeys[] = { V3DK_INVALID, V3DK_1, V3DK_2, V3DK_3, V3DK_4, V3DK_5, V3DK_6, V3DK_TOP, V3DK_LEFT, V3DK_RIGHT, V3DK_FRONT, V3DK_ESC, V3DK_ALT, V3DK_SHIFT, V3DK_CTRL, V3DK_FIT, V3DK_MENU, V3DK_PLUS, V3DK_MINUS, V3DK_DOMINANT, V3DK_ROTATE, }; static const struct tag_VirtualKeys _3dmouseVirtualKeys[] = { CONNEXIONPID_SPACEPILOT, sizeof(SpacePilotKeys) / sizeof(SpacePilotKeys[0]), const_cast<V3dk *>(SpacePilotKeys), CONNEXIONPID_SPACEEXPLORER, sizeof(SpaceExplorerKeys) / sizeof(SpaceExplorerKeys[0]), const_cast<V3dk *>(SpaceExplorerKeys) }; // Converts a hid device keycode (button identifier) of a pre-2009 3Dconnexion USB device to the standard 3d mouse virtual key definition. // pid USB Product ID (PID) of 3D mouse device // hidKeyCode Hid keycode as retrieved from a Raw Input packet // return The standard 3d mouse virtual key (button identifier) or zero if an error occurs. // Converts a hid device keycode (button identifier) of a pre-2009 3Dconnexion USB device // to the standard 3d mouse virtual key definition. unsigned short HidToVirtualKey(unsigned long pid, unsigned short hidKeyCode) { unsigned short virtualkey = hidKeyCode; for (size_t i = 0; i<sizeof(_3dmouseVirtualKeys) / sizeof(_3dmouseVirtualKeys[0]); ++i) { if (pid == _3dmouseVirtualKeys[i].pid) { if (hidKeyCode < _3dmouseVirtualKeys[i].nKeys) { virtualkey = _3dmouseVirtualKeys[i].vkeys[hidKeyCode]; } else { virtualkey = V3DK_INVALID; } break; } } // Remaining devices are unchanged return virtualkey; } bool SpacemouseManager::RawInputEventFilter(void* msg, long* result) { auto userInputMapper = DependencyManager::get<UserInputMapper>(); if (Is3dmouseAttached() && instance->getDeviceID() == controller::Input::INVALID_DEVICE) { userInputMapper->registerDevice(instance); } else if (!Is3dmouseAttached() && instance->getDeviceID() != controller::Input::INVALID_DEVICE) { userInputMapper->removeDevice(instance->getDeviceID()); } if (!Is3dmouseAttached()) { return false; } MSG* message = (MSG*)(msg); if (message->message == WM_INPUT) { HRAWINPUT hRawInput = reinterpret_cast<HRAWINPUT>(message->lParam); OnRawInput(RIM_INPUT, hRawInput); if (result != 0) { result = 0; } return true; } return false; } //Called with the processed motion data when a 3D mouse event is received void SpacemouseManager::Move3d(HANDLE device, std::vector<float>& motionData) { Q_UNUSED(device); instance->cc_position = { motionData[0] * 1000, motionData[1] * 1000, motionData[2] * 1000 }; instance->cc_rotation = { motionData[3] * 1500, motionData[4] * 1500, motionData[5] * 1500 }; instance->handleAxisEvent(); } //Called when a 3D mouse key is pressed void SpacemouseManager::On3dmouseKeyDown(HANDLE device, int virtualKeyCode) { Q_UNUSED(device); instance->setButton(virtualKeyCode); } //Called when a 3D mouse key is released void SpacemouseManager::On3dmouseKeyUp(HANDLE device, int virtualKeyCode) { Q_UNUSED(device); instance->setButton(0); } // Initialize the window to recieve raw-input messages // This needs to be called initially so that Windows will send the messages from the 3D mouse to the window. bool SpacemouseManager::InitializeRawInput(HWND hwndTarget) { fWindow = hwndTarget; // Simply fail if there is no window if (!hwndTarget) { return false; } unsigned int numDevices = 0; PRAWINPUTDEVICE devicesToRegister = GetDevicesToRegister(&numDevices); if (numDevices == 0) { return false; } unsigned int cbSize = sizeof(devicesToRegister[0]); for (size_t i = 0; i < numDevices; i++) { // Set the target window to use //devicesToRegister[i].hwndTarget = hwndTarget; // If Vista or newer, enable receiving the WM_INPUT_DEVICE_CHANGE message. if (IsWindowsVistaOrGreater()) { devicesToRegister[i].dwFlags |= RIDEV_DEVNOTIFY; } } return (::RegisterRawInputDevices(devicesToRegister, numDevices, cbSize) != FALSE); } //Get the raw input data from Windows UINT SpacemouseManager::GetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader) { //Includes workaround for incorrect alignment of the RAWINPUT structure on x64 os //when running as Wow64 (copied directly from 3DConnexion code) #ifdef _WIN64 return ::GetRawInputBuffer(pData, pcbSize, cbSizeHeader); #else BOOL bIsWow64 = FALSE; ::IsWow64Process(GetCurrentProcess(), &bIsWow64); if (!bIsWow64 || pData == NULL) { return ::GetRawInputBuffer(pData, pcbSize, cbSizeHeader); } else { HWND hwndTarget = fWindow; size_t cbDataSize = 0; UINT nCount = 0; PRAWINPUT pri = pData; MSG msg; while (PeekMessage(&msg, hwndTarget, WM_INPUT, WM_INPUT, PM_NOREMOVE)) { HRAWINPUT hRawInput = reinterpret_cast<HRAWINPUT>(msg.lParam); size_t cbSize = *pcbSize - cbDataSize; if (::GetRawInputData(hRawInput, RID_INPUT, pri, &cbSize, cbSizeHeader) == static_cast<UINT>(-1)) { if (nCount == 0) { return static_cast<UINT>(-1); } else { break; } } ++nCount; // Remove the message for the data just read PeekMessage(&msg, hwndTarget, WM_INPUT, WM_INPUT, PM_REMOVE); pri = NEXTRAWINPUTBLOCK(pri); cbDataSize = reinterpret_cast<ULONG_PTR>(pri)-reinterpret_cast<ULONG_PTR>(pData); if (cbDataSize >= *pcbSize) { cbDataSize = *pcbSize; break; } } return nCount; } #endif } // Process the raw input device data // On3dmouseInput() does all the preprocessing of the rawinput device data before // finally calling the Move3d method. void SpacemouseManager::On3dmouseInput() { // Don't do any data processing in background bool bIsForeground = (::GetActiveWindow() != NULL); if (!bIsForeground) { // set all cached data to zero so that a zero event is seen and the cached data deleted for (std::map<HANDLE, TInputData>::iterator it = fDevice2Data.begin(); it != fDevice2Data.end(); it++) { it->second.fAxes.assign(6, .0); it->second.fIsDirty = true; } } DWORD dwNow = ::GetTickCount(); // Current time; DWORD dwElapsedTime; // Elapsed time since we were last here if (0 == fLast3dmouseInputTime) { dwElapsedTime = 10; // System timer resolution } else { dwElapsedTime = dwNow - fLast3dmouseInputTime; if (fLast3dmouseInputTime > dwNow) { dwElapsedTime = ~dwElapsedTime + 1; } if (dwElapsedTime<1) { dwElapsedTime = 1; } else if (dwElapsedTime > 500) { // Check for wild numbers because the device was removed while sending data dwElapsedTime = 10; } } //qDebug("On3DmouseInput() period is %dms\n", dwElapsedTime); float mouseData2Rotation = k3dmouseAngularVelocity; // v = w * r, we don't know r yet so lets assume r=1.) float mouseData2PanZoom = k3dmouseAngularVelocity; // Grab the I3dmouseParam interface I3dMouseParam& i3dmouseParam = f3dMouseParams; // Take a look at the users preferred speed setting and adjust the sensitivity accordingly I3dMouseSensor::Speed speedSetting = i3dmouseParam.GetSpeed(); // See "Programming for the 3D Mouse", Section 5.1.3 float speed = (speedSetting == I3dMouseSensor::SPEED_LOW ? 0.25f : speedSetting == I3dMouseSensor::SPEED_HIGH ? 4.f : 1.f); // Multiplying by the following will convert the 3d mouse data to real world units mouseData2PanZoom *= speed; mouseData2Rotation *= speed; std::map<HANDLE, TInputData>::iterator iterator = fDevice2Data.begin(); while (iterator != fDevice2Data.end()) {