mirror of
https://github.com/overte-org/overte.git
synced 2025-04-19 15:43:50 +02:00
Do not merge - Spacemouse
This commit is contained in:
parent
79f7284c32
commit
603405ad61
4 changed files with 10 additions and 1210 deletions
|
@ -100,7 +100,7 @@
|
|||
#include "audio/AudioScope.h"
|
||||
#include "avatar/AvatarManager.h"
|
||||
#include "CrashHandler.h"
|
||||
#include "devices/3DConnexionClient.h"
|
||||
#include "input-plugins/SpacemouseManager.h"
|
||||
#include "devices/DdeFaceTracker.h"
|
||||
#include "devices/EyeTracker.h"
|
||||
#include "devices/Faceshift.h"
|
||||
|
@ -729,10 +729,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
// Now that menu is initalized we can sync myAvatar with it's state.
|
||||
getMyAvatar()->updateMotionBehaviorFromMenu();
|
||||
|
||||
#if 0
|
||||
// the 3Dconnexion device wants to be initiliazed after a window is displayed.
|
||||
ConnexionClient::getInstance().init();
|
||||
#endif
|
||||
SpacemouseManager::getInstance().init();
|
||||
|
||||
auto& packetReceiver = nodeList->getPacketReceiver();
|
||||
packetReceiver.registerListener(PacketType::DomainConnectionDenied, this, "handleDomainConnectionDeniedPacket");
|
||||
|
@ -1839,9 +1837,10 @@ void Application::focusOutEvent(QFocusEvent* event) {
|
|||
inputPlugin->pluginFocusOutEvent();
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
ConnexionData::getInstance().focusOutEvent();
|
||||
#endif
|
||||
|
||||
//SpacemouseDevice::getInstance().focusOutEvent();
|
||||
//SpacemouseManager::getInstance().getDevice()->focusOutEvent();
|
||||
SpacemouseManager::getInstance().ManagerFocusOutEvent();
|
||||
|
||||
// synthesize events for keys currently pressed, since we may not get their release events
|
||||
foreach (int key, _keysPressed) {
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include "devices/DdeFaceTracker.h"
|
||||
#include "devices/Faceshift.h"
|
||||
#include "devices/RealSense.h"
|
||||
#include "devices/3DConnexionClient.h"
|
||||
#include "input-plugins/SpacemouseManager.h"
|
||||
#include "MainWindow.h"
|
||||
#include "scripting/MenuScriptingInterface.h"
|
||||
#include "ui/AssetUploadDialogFactory.h"
|
||||
|
@ -464,13 +464,9 @@ Menu::Menu() {
|
|||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::MeshVisible, 0, true,
|
||||
avatar, SLOT(setEnableMeshVisible(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::DisableEyelidAdjustment, 0, false);
|
||||
#if 0
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu,
|
||||
MenuOption::Connexion,
|
||||
0, false,
|
||||
&ConnexionClient::getInstance(),
|
||||
SLOT(toggleConnexion(bool)));
|
||||
#endif
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::Connexion, 0, false, &SpacemouseManager::getInstance(), SLOT(toggleConnexion(bool)));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ComfortMode, 0, true);
|
||||
|
||||
MenuWrapper* handOptionsMenu = developerMenu->addMenu("Hands");
|
||||
|
|
|
@ -1,972 +0,0 @@
|
|||
//
|
||||
// 3DConnexionClient.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 "3DConnexionClient.h"
|
||||
|
||||
#if 0
|
||||
#include <UserActivityLogger.h>
|
||||
#include <PathUtils.h>
|
||||
|
||||
#include "Menu.h"
|
||||
|
||||
const float MAX_AXIS = 75.0f; // max forward = 2x speed
|
||||
|
||||
void ConnexionData::focusOutEvent() {
|
||||
_axisStateMap.clear();
|
||||
_buttonPressedMap.clear();
|
||||
};
|
||||
|
||||
ConnexionData& ConnexionData::getInstance() {
|
||||
static ConnexionData sharedInstance;
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
|
||||
ConnexionData::ConnexionData() : InputDevice("ConnexionClient") {}
|
||||
|
||||
|
||||
void ConnexionData::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_rotation / MAX_AXIS;
|
||||
_axisStateMap[TRANSLATE_X] = position.x;
|
||||
_axisStateMap[TRANSLATE_Y] = position.y;
|
||||
_axisStateMap[TRANSLATE_Z] = position.z;
|
||||
}
|
||||
|
||||
void ConnexionData::setButton(int lastButtonState) {
|
||||
_buttonPressedMap.clear();
|
||||
_buttonPressedMap.insert(lastButtonState);
|
||||
}
|
||||
|
||||
void ConnexionData::buildDeviceProxy(controller::DeviceProxy::Pointer proxy) {
|
||||
proxy->_name = _name = "ConnexionClient";
|
||||
proxy->getButton = [this](const controller::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
|
||||
proxy->getAxis = [this](const controller::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
|
||||
proxy->getAvailabeInputs = [this]() -> QVector<controller::Input::NamedPair> {
|
||||
using namespace controller;
|
||||
static QVector<controller::Input::NamedPair> availableInputs {
|
||||
Input::NamedPair(makeInput(BUTTON_1), "LeftButton"),
|
||||
Input::NamedPair(makeInput(BUTTON_2), "RightButton"),
|
||||
Input::NamedPair(makeInput(BUTTON_3), "BothButtons"),
|
||||
Input::NamedPair(makeInput(TRANSLATE_X), "TranslateX"),
|
||||
Input::NamedPair(makeInput(TRANSLATE_Y), "TranslateY"),
|
||||
Input::NamedPair(makeInput(TRANSLATE_Z), "TranslateZ"),
|
||||
Input::NamedPair(makeInput(ROTATE_X), "RotateX"),
|
||||
Input::NamedPair(makeInput(ROTATE_Y), "RotateY"),
|
||||
Input::NamedPair(makeInput(ROTATE_Z), "RotateZ"),
|
||||
};
|
||||
return availableInputs;
|
||||
};
|
||||
}
|
||||
|
||||
QString ConnexionData::getDefaultMappingConfig() {
|
||||
static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/vive.json";
|
||||
return MAPPING_JSON;
|
||||
}
|
||||
|
||||
//void ConnexionData::assignDefaultInputMapping(UserInputMapper& mapper) {
|
||||
// const float JOYSTICK_MOVE_SPEED = 1.0f;
|
||||
// //const float DPAD_MOVE_SPEED = 0.5f;
|
||||
// const float JOYSTICK_YAW_SPEED = 0.5f;
|
||||
// const float JOYSTICK_PITCH_SPEED = 0.25f;
|
||||
// const float BOOM_SPEED = 0.1f;
|
||||
//
|
||||
// // Y axes are flipped (up is negative)
|
||||
// // postion: Movement, strafing
|
||||
// mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(POSITION_AXIS_Y_NEG), JOYSTICK_MOVE_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(POSITION_AXIS_Y_POS), JOYSTICK_MOVE_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(POSITION_AXIS_X_POS), JOYSTICK_MOVE_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(POSITION_AXIS_X_NEG), JOYSTICK_MOVE_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(POSITION_AXIS_Z_NEG), JOYSTICK_MOVE_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(POSITION_AXIS_Z_POS), JOYSTICK_MOVE_SPEED);
|
||||
//
|
||||
// // Rotation: Camera orientation with button 1
|
||||
// mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(ROTATION_AXIS_Z_POS), JOYSTICK_YAW_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(ROTATION_AXIS_Z_NEG), JOYSTICK_YAW_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(ROTATION_AXIS_Y_NEG), JOYSTICK_PITCH_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(ROTATION_AXIS_Y_POS), JOYSTICK_PITCH_SPEED);
|
||||
//
|
||||
// // Button controls
|
||||
// // Zoom
|
||||
// mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(BUTTON_1), BOOM_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(BUTTON_2), BOOM_SPEED);
|
||||
//
|
||||
// // Zoom
|
||||
// // mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(ROTATION_AXIS_Z_NEG), BOOM_SPEED);
|
||||
// // mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(ROTATION_AXIS_Z_POS), BOOM_SPEED);
|
||||
//
|
||||
//}
|
||||
|
||||
float ConnexionData::getButton(int channel) const {
|
||||
if (!_buttonPressedMap.empty()) {
|
||||
if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) {
|
||||
return 1.0f;
|
||||
} else {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
float ConnexionData::getAxis(int channel) const {
|
||||
auto axis = _axisStateMap.find(channel);
|
||||
if (axis != _axisStateMap.end()) {
|
||||
return (*axis).second;
|
||||
} else {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
controller::Input ConnexionData::makeInput(ConnexionData::ButtonChannel button) {
|
||||
return controller::Input(_deviceID, button, controller::ChannelType::BUTTON);
|
||||
}
|
||||
|
||||
controller::Input ConnexionData::makeInput(ConnexionData::PositionChannel axis) {
|
||||
return controller::Input(_deviceID, axis, controller::ChannelType::AXIS);
|
||||
}
|
||||
|
||||
void ConnexionData::update(float deltaTime, bool jointsCaptured) {
|
||||
// the update is done in the ConnexionClient 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
|
||||
}
|
||||
|
||||
ConnexionClient& ConnexionClient::getInstance() {
|
||||
static ConnexionClient sharedInstance;
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
#ifdef HAVE_3DCONNEXIONCLIENT
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
#include <VersionHelpers.h>
|
||||
|
||||
void ConnexionClient::toggleConnexion(bool shouldEnable) {
|
||||
ConnexionData& connexiondata = ConnexionData::getInstance();
|
||||
if (shouldEnable && connexiondata.getDeviceID() == 0) {
|
||||
init();
|
||||
}
|
||||
if (!shouldEnable && connexiondata.getDeviceID() != 0) {
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void ConnexionClient::init() {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Connexion)) {
|
||||
fLast3dmouseInputTime = 0;
|
||||
|
||||
InitializeRawInput(GetActiveWindow());
|
||||
|
||||
QAbstractEventDispatcher::instance()->installNativeEventFilter(this);
|
||||
}
|
||||
}
|
||||
|
||||
void ConnexionClient::destroy() {
|
||||
QAbstractEventDispatcher::instance()->removeNativeEventFilter(this);
|
||||
ConnexionData& connexiondata = ConnexionData::getInstance();
|
||||
int deviceid = connexiondata.getDeviceID();
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
userInputMapper->removeDevice(deviceid);
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
// 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 ConnexionClient::RawInputEventFilter(void* msg, long* result) {
|
||||
ConnexionData& connexiondata = ConnexionData::getInstance();
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
if (Is3dmouseAttached() && connexiondata.getDeviceID() == 0) {
|
||||
userInputMapper->registerDevice(&connexiondata);
|
||||
UserActivityLogger::getInstance().connectedDevice("controller", "3Dconnexion");
|
||||
} else if (!Is3dmouseAttached() && connexiondata.getDeviceID() != 0) {
|
||||
userInputMapper->removeDevice(connexiondata.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;
|
||||
}
|
||||
|
||||
// Access the mouse parameters structure
|
||||
I3dMouseParam& ConnexionClient::MouseParams() {
|
||||
return f3dMouseParams;
|
||||
}
|
||||
|
||||
// Access the mouse parameters structure
|
||||
const I3dMouseParam& ConnexionClient::MouseParams() const {
|
||||
return f3dMouseParams;
|
||||
}
|
||||
|
||||
//Called with the processed motion data when a 3D mouse event is received
|
||||
void ConnexionClient::Move3d(HANDLE device, std::vector<float>& motionData) {
|
||||
Q_UNUSED(device);
|
||||
ConnexionData& connexiondata = ConnexionData::getInstance();
|
||||
connexiondata.cc_position = { motionData[0] * 1000, motionData[1] * 1000, motionData[2] * 1000 };
|
||||
connexiondata.cc_rotation = { motionData[3] * 1500, motionData[4] * 1500, motionData[5] * 1500 };
|
||||
connexiondata.handleAxisEvent();
|
||||
}
|
||||
|
||||
//Called when a 3D mouse key is pressed
|
||||
void ConnexionClient::On3dmouseKeyDown(HANDLE device, int virtualKeyCode) {
|
||||
Q_UNUSED(device);
|
||||
ConnexionData& connexiondata = ConnexionData::getInstance();
|
||||
connexiondata.setButton(virtualKeyCode);
|
||||
}
|
||||
|
||||
//Called when a 3D mouse key is released
|
||||
void ConnexionClient::On3dmouseKeyUp(HANDLE device, int virtualKeyCode) {
|
||||
Q_UNUSED(device);
|
||||
ConnexionData& connexiondata = ConnexionData::getInstance();
|
||||
connexiondata.setButton(0);
|
||||
}
|
||||
|
||||
//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 ConnexionClient::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;
|
||||
}
|
||||
|
||||
// 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 ConnexionClient::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 ConnexionClient::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 ConnexionClient::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()) {
|
||||
|
||||
// If we have not received data for a while send a zero event
|
||||
if ((--(iterator->second.fTimeToLive)) == 0) {
|
||||
iterator->second.fAxes.assign(6, .0);
|
||||
} else if ( !iterator->second.fIsDirty) { //!t_bPoll3dmouse &&
|
||||
// If we are not polling then only handle the data that was actually received
|
||||
++iterator;
|
||||
continue;
|
||||
}
|
||||
iterator->second.fIsDirty = false;
|
||||
|
||||
// get a copy of the device
|
||||
HANDLE hdevice = iterator->first;
|
||||
|
||||
// get a copy of the motion vectors and apply the user filters
|
||||
std::vector<float> motionData = iterator->second.fAxes;
|
||||
|
||||
// apply the user filters
|
||||
|
||||
// Pan Zoom filter
|
||||
// See "Programming for the 3D Mouse", Section 5.1.2
|
||||
if (!i3dmouseParam.IsPanZoom()) {
|
||||
// Pan zoom is switched off so set the translation vector values to zero
|
||||
motionData[0] = motionData[1] = motionData[2] = 0.;
|
||||
}
|
||||
|
||||
// Rotate filter
|
||||
// See "Programming for the 3D Mouse", Section 5.1.1
|
||||
if (!i3dmouseParam.IsRotate()) {
|
||||
// Rotate is switched off so set the rotation vector values to zero
|
||||
motionData[3] = motionData[4] = motionData[5] = 0.;
|
||||
}
|
||||
|
||||
// convert the translation vector into physical data
|
||||
for (int axis = 0; axis < 3; axis++) {
|
||||
motionData[axis] *= mouseData2PanZoom;
|
||||
}
|
||||
|
||||
// convert the directed Rotate vector into physical data
|
||||
// See "Programming for the 3D Mouse", Section 7.2.2
|
||||
for (int axis = 3; axis < 6; axis++) {
|
||||
motionData[axis] *= mouseData2Rotation;
|
||||
}
|
||||
|
||||
// Now that the data has had the filters and sensitivty settings applied
|
||||
// calculate the displacements since the last view update
|
||||
for (int axis = 0; axis < 6; axis++) {
|
||||
motionData[axis] *= dwElapsedTime;
|
||||
}
|
||||
|
||||
// Now a bit of book keeping before passing on the data
|
||||
if (iterator->second.IsZero()) {
|
||||
iterator = fDevice2Data.erase(iterator);
|
||||
} else {
|
||||
++iterator;
|
||||
}
|
||||
|
||||
// Work out which will be the next device
|
||||
HANDLE hNextDevice = 0;
|
||||
if (iterator != fDevice2Data.end()) {
|
||||
hNextDevice = iterator->first;
|
||||
}
|
||||
|
||||
// Pass the 3dmouse input to the view controller
|
||||
Move3d(hdevice, motionData);
|
||||
|
||||
// Because we don't know what happened in the previous call, the cache might have
|
||||
// changed so reload the iterator
|
||||
iterator = fDevice2Data.find(hNextDevice);
|
||||
}
|
||||
|
||||
if (!fDevice2Data.empty()) {
|
||||
fLast3dmouseInputTime = dwNow;
|
||||
} else {
|
||||
fLast3dmouseInputTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//Called when new raw input data is available
|
||||
void ConnexionClient::OnRawInput(UINT nInputCode, HRAWINPUT hRawInput) {
|
||||
const size_t cbSizeOfBuffer = 1024;
|
||||
BYTE pBuffer[cbSizeOfBuffer];
|
||||
|
||||
PRAWINPUT pRawInput = reinterpret_cast<PRAWINPUT>(pBuffer);
|
||||
UINT cbSize = cbSizeOfBuffer;
|
||||
|
||||
if (::GetRawInputData(hRawInput, RID_INPUT, pRawInput, &cbSize, sizeof(RAWINPUTHEADER)) == static_cast<UINT>(-1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool b3dmouseInput = TranslateRawInputData(nInputCode, pRawInput);
|
||||
::DefRawInputProc(&pRawInput, 1, sizeof(RAWINPUTHEADER));
|
||||
|
||||
// Check for any buffered messages
|
||||
cbSize = cbSizeOfBuffer;
|
||||
UINT nCount = this->GetRawInputBuffer(pRawInput, &cbSize, sizeof(RAWINPUTHEADER));
|
||||
if (nCount == (UINT)-1) {
|
||||
qDebug("GetRawInputBuffer returned error %d\n", GetLastError());
|
||||
}
|
||||
|
||||
while (nCount>0 && nCount != static_cast<UINT>(-1)) {
|
||||
PRAWINPUT pri = pRawInput;
|
||||
UINT nInput;
|
||||
for (nInput = 0; nInput<nCount; ++nInput) {
|
||||
b3dmouseInput |= TranslateRawInputData(nInputCode, pri);
|
||||
// clean the buffer
|
||||
::DefRawInputProc(&pri, 1, sizeof(RAWINPUTHEADER));
|
||||
|
||||
pri = NEXTRAWINPUTBLOCK(pri);
|
||||
}
|
||||
cbSize = cbSizeOfBuffer;
|
||||
nCount = this->GetRawInputBuffer(pRawInput, &cbSize, sizeof(RAWINPUTHEADER));
|
||||
}
|
||||
|
||||
// If we have mouse input data for the app then tell tha app about it
|
||||
if (b3dmouseInput) {
|
||||
On3dmouseInput();
|
||||
}
|
||||
}
|
||||
|
||||
bool ConnexionClient::TranslateRawInputData(UINT nInputCode, PRAWINPUT pRawInput) {
|
||||
bool bIsForeground = (nInputCode == RIM_INPUT);
|
||||
|
||||
// We are not interested in keyboard or mouse data received via raw input
|
||||
if (pRawInput->header.dwType != RIM_TYPEHID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TRACE_RIDI_DEVICENAME == 1) {
|
||||
UINT dwSize = 0;
|
||||
if (::GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_DEVICENAME, NULL, &dwSize) == 0) {
|
||||
std::vector<wchar_t> szDeviceName(dwSize + 1);
|
||||
if (::GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_DEVICENAME, &szDeviceName[0], &dwSize) > 0) {
|
||||
qDebug("Device Name = %s\nDevice handle = 0x%x\n", &szDeviceName[0], pRawInput->header.hDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RID_DEVICE_INFO sRidDeviceInfo;
|
||||
sRidDeviceInfo.cbSize = sizeof(RID_DEVICE_INFO);
|
||||
UINT cbSize = sizeof(RID_DEVICE_INFO);
|
||||
|
||||
if (::GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_DEVICEINFO, &sRidDeviceInfo, &cbSize) == cbSize) {
|
||||
if (TRACE_RIDI_DEVICEINFO == 1) {
|
||||
switch (sRidDeviceInfo.dwType) {
|
||||
case RIM_TYPEMOUSE:
|
||||
qDebug("\tsRidDeviceInfo.dwType=RIM_TYPEMOUSE\n");
|
||||
break;
|
||||
case RIM_TYPEKEYBOARD:
|
||||
qDebug("\tsRidDeviceInfo.dwType=RIM_TYPEKEYBOARD\n");
|
||||
break;
|
||||
case RIM_TYPEHID:
|
||||
qDebug("\tsRidDeviceInfo.dwType=RIM_TYPEHID\n");
|
||||
qDebug("\tVendor=0x%x\n\tProduct=0x%x\n\tUsagePage=0x%x\n\tUsage=0x%x\n",
|
||||
sRidDeviceInfo.hid.dwVendorId,
|
||||
sRidDeviceInfo.hid.dwProductId,
|
||||
sRidDeviceInfo.hid.usUsagePage,
|
||||
sRidDeviceInfo.hid.usUsage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sRidDeviceInfo.hid.dwVendorId == LOGITECH_VENDOR_ID) {
|
||||
if (pRawInput->data.hid.bRawData[0] == 0x01) { // Translation vector
|
||||
TInputData& deviceData = fDevice2Data[pRawInput->header.hDevice];
|
||||
deviceData.fTimeToLive = kTimeToLive;
|
||||
if (bIsForeground) {
|
||||
short* pnRawData = reinterpret_cast<short*>(&pRawInput->data.hid.bRawData[1]);
|
||||
// Cache the pan zoom data
|
||||
deviceData.fAxes[0] = static_cast<float>(pnRawData[0]);
|
||||
deviceData.fAxes[1] = static_cast<float>(pnRawData[1]);
|
||||
deviceData.fAxes[2] = static_cast<float>(pnRawData[2]);
|
||||
|
||||
//qDebug("Pan/Zoom RI Data =\t0x%x,\t0x%x,\t0x%x\n", pnRawData[0], pnRawData[1], pnRawData[2]);
|
||||
|
||||
if (pRawInput->data.hid.dwSizeHid >= 13) { // Highspeed package
|
||||
// Cache the rotation data
|
||||
deviceData.fAxes[3] = static_cast<float>(pnRawData[3]);
|
||||
deviceData.fAxes[4] = static_cast<float>(pnRawData[4]);
|
||||
deviceData.fAxes[5] = static_cast<float>(pnRawData[5]);
|
||||
deviceData.fIsDirty = true;
|
||||
|
||||
//qDebug("Rotation RI Data =\t0x%x,\t0x%x,\t0x%x\n", pnRawData[3], pnRawData[4], pnRawData[5]);
|
||||
return true;
|
||||
}
|
||||
} else { // Zero out the data if the app is not in forground
|
||||
deviceData.fAxes.assign(6, 0.f);
|
||||
}
|
||||
} else if (pRawInput->data.hid.bRawData[0] == 0x02) { // Rotation vector
|
||||
// If we are not in foreground do nothing
|
||||
// The rotation vector was zeroed out with the translation vector in the previous message
|
||||
if (bIsForeground) {
|
||||
TInputData& deviceData = fDevice2Data[pRawInput->header.hDevice];
|
||||
deviceData.fTimeToLive = kTimeToLive;
|
||||
|
||||
short* pnRawData = reinterpret_cast<short*>(&pRawInput->data.hid.bRawData[1]);
|
||||
// Cache the rotation data
|
||||
deviceData.fAxes[3] = static_cast<float>(pnRawData[0]);
|
||||
deviceData.fAxes[4] = static_cast<float>(pnRawData[1]);
|
||||
deviceData.fAxes[5] = static_cast<float>(pnRawData[2]);
|
||||
deviceData.fIsDirty = true;
|
||||
|
||||
//qDebug("Rotation RI Data =\t0x%x,\t0x%x,\t0x%x\n", pnRawData[0], pnRawData[1], pnRawData[2]);
|
||||
|
||||
return true;
|
||||
}
|
||||
} else if (pRawInput->data.hid.bRawData[0] == 0x03) { // Keystate change
|
||||
// this is a package that contains 3d mouse keystate information
|
||||
// bit0=key1, bit=key2 etc.
|
||||
|
||||
unsigned long dwKeystate = *reinterpret_cast<unsigned long*>(&pRawInput->data.hid.bRawData[1]);
|
||||
|
||||
//qDebug("ButtonData =0x%x\n", dwKeystate);
|
||||
|
||||
// Log the keystate changes
|
||||
unsigned long dwOldKeystate = fDevice2Keystate[pRawInput->header.hDevice];
|
||||
if (dwKeystate != 0) {
|
||||
fDevice2Keystate[pRawInput->header.hDevice] = dwKeystate;
|
||||
} else {
|
||||
fDevice2Keystate.erase(pRawInput->header.hDevice);
|
||||
}
|
||||
|
||||
// Only call the keystate change handlers if the app is in foreground
|
||||
if (bIsForeground) {
|
||||
unsigned long dwChange = dwKeystate ^ dwOldKeystate;
|
||||
|
||||
for (int nKeycode = 1; nKeycode<33; nKeycode++) {
|
||||
if (dwChange & 0x01) {
|
||||
int nVirtualKeyCode = HidToVirtualKey(sRidDeviceInfo.hid.dwProductId, nKeycode);
|
||||
if (nVirtualKeyCode) {
|
||||
if (dwKeystate & 0x01) {
|
||||
On3dmouseKeyDown(pRawInput->header.hDevice, nVirtualKeyCode);
|
||||
} else {
|
||||
On3dmouseKeyUp(pRawInput->header.hDevice, nVirtualKeyCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
dwChange >>= 1;
|
||||
dwKeystate >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
MouseParameters::MouseParameters() :
|
||||
fNavigation(NAVIGATION_OBJECT_MODE),
|
||||
fPivot(PIVOT_AUTO),
|
||||
fPivotVisibility(PIVOT_SHOW),
|
||||
fIsLockHorizon(true),
|
||||
fIsPanZoom(true),
|
||||
fIsRotate(true),
|
||||
fSpeed(SPEED_LOW)
|
||||
{
|
||||
}
|
||||
|
||||
bool MouseParameters::IsPanZoom() const {
|
||||
return fIsPanZoom;
|
||||
}
|
||||
|
||||
bool MouseParameters::IsRotate() const {
|
||||
return fIsRotate;
|
||||
}
|
||||
|
||||
MouseParameters::Speed MouseParameters::GetSpeed() const {
|
||||
return fSpeed;
|
||||
}
|
||||
|
||||
void MouseParameters::SetPanZoom(bool isPanZoom) {
|
||||
fIsPanZoom = isPanZoom;
|
||||
}
|
||||
|
||||
void MouseParameters::SetRotate(bool isRotate) {
|
||||
fIsRotate = isRotate;
|
||||
}
|
||||
|
||||
void MouseParameters::SetSpeed(Speed speed) {
|
||||
fSpeed = speed;
|
||||
}
|
||||
|
||||
MouseParameters::Navigation MouseParameters::GetNavigationMode() const {
|
||||
return fNavigation;
|
||||
}
|
||||
|
||||
MouseParameters::Pivot MouseParameters::GetPivotMode() const {
|
||||
return fPivot;
|
||||
}
|
||||
|
||||
MouseParameters::PivotVisibility MouseParameters::GetPivotVisibility() const {
|
||||
return fPivotVisibility;
|
||||
}
|
||||
|
||||
bool MouseParameters::IsLockHorizon() const {
|
||||
return fIsLockHorizon;
|
||||
}
|
||||
|
||||
void MouseParameters::SetLockHorizon(bool bOn) {
|
||||
fIsLockHorizon=bOn;
|
||||
}
|
||||
|
||||
void MouseParameters::SetNavigationMode(Navigation navigation) {
|
||||
fNavigation=navigation;
|
||||
}
|
||||
|
||||
void MouseParameters::SetPivotMode(Pivot pivot) {
|
||||
if (fPivot!=PIVOT_MANUAL || pivot!=PIVOT_AUTO_OVERRIDE) {
|
||||
fPivot = pivot;
|
||||
}
|
||||
}
|
||||
|
||||
void MouseParameters::SetPivotVisibility(PivotVisibility visibility) {
|
||||
fPivotVisibility = visibility;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int fConnexionClientID;
|
||||
|
||||
static ConnexionDeviceState lastState;
|
||||
|
||||
static void DeviceAddedHandler(unsigned int connection);
|
||||
static void DeviceRemovedHandler(unsigned int connection);
|
||||
static void MessageHandler(unsigned int connection, unsigned int messageType, void *messageArgument);
|
||||
|
||||
void ConnexionClient::toggleConnexion(bool shouldEnable) {
|
||||
if (shouldEnable && !Is3dmouseAttached()) {
|
||||
init();
|
||||
}
|
||||
if (!shouldEnable && Is3dmouseAttached()) {
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void ConnexionClient::init() {
|
||||
// Make sure the framework is installed
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Connexion)) {
|
||||
// Install message handler and register our client
|
||||
InstallConnexionHandlers(MessageHandler, DeviceAddedHandler, DeviceRemovedHandler);
|
||||
// Either use this to take over in our application only... does not work
|
||||
// fConnexionClientID = RegisterConnexionClient('MCTt', "\pConnexion Client Test", kConnexionClientModeTakeOver, kConnexionMaskAll);
|
||||
|
||||
// ...or use this to take over system-wide
|
||||
fConnexionClientID = RegisterConnexionClient(kConnexionClientWildcard, NULL, kConnexionClientModeTakeOver, kConnexionMaskAll);
|
||||
ConnexionData& connexiondata = ConnexionData::getInstance();
|
||||
memcpy(&connexiondata.clientId, &fConnexionClientID, (long)sizeof(int));
|
||||
|
||||
// A separate API call is required to capture buttons beyond the first 8
|
||||
SetConnexionClientButtonMask(fConnexionClientID, kConnexionMaskAllButtons);
|
||||
|
||||
// use default switches
|
||||
ConnexionClientControl(fConnexionClientID, kConnexionCtlSetSwitches, kConnexionSwitchesDisabled, NULL);
|
||||
|
||||
if (Is3dmouseAttached() && connexiondata.getDeviceID() == 0) {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
userInputMapper->registerDevice(&connexiondata);
|
||||
UserActivityLogger::getInstance().connectedDevice("controller", "3Dconnexion");
|
||||
}
|
||||
//let one axis be dominant
|
||||
//ConnexionClientControl(fConnexionClientID, kConnexionCtlSetSwitches, kConnexionSwitchDominant | kConnexionSwitchEnableAll, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void ConnexionClient::destroy() {
|
||||
// Make sure the framework is installed
|
||||
if (&InstallConnexionHandlers != NULL) {
|
||||
// Unregister our client and clean up all handlers
|
||||
if (fConnexionClientID) {
|
||||
UnregisterConnexionClient(fConnexionClientID);
|
||||
}
|
||||
CleanupConnexionHandlers();
|
||||
fConnexionClientID = 0;
|
||||
ConnexionData& connexiondata = ConnexionData::getInstance();
|
||||
if (connexiondata.getDeviceID()!=0) {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
userInputMapper->removeDevice(connexiondata.getDeviceID());
|
||||
connexiondata.setDeviceID(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceAddedHandler(unsigned int connection) {
|
||||
ConnexionData& connexiondata = ConnexionData::getInstance();
|
||||
if (connexiondata.getDeviceID() == 0) {
|
||||
qCWarning(interfaceapp) << "3Dconnexion device added ";
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
userInputMapper->registerDevice(&connexiondata);
|
||||
UserActivityLogger::getInstance().connectedDevice("controller", "3Dconnexion");
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceRemovedHandler(unsigned int connection) {
|
||||
ConnexionData& connexiondata = ConnexionData::getInstance();
|
||||
if (connexiondata.getDeviceID() != 0) {
|
||||
qCWarning(interfaceapp) << "3Dconnexion device removed";
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
userInputMapper->removeDevice(connexiondata.getDeviceID());
|
||||
connexiondata.setDeviceID(0);
|
||||
}
|
||||
}
|
||||
|
||||
bool ConnexionClient::Is3dmouseAttached() {
|
||||
int result;
|
||||
if (fConnexionClientID) {
|
||||
if (ConnexionControl(kConnexionCtlGetDeviceID, 0, &result)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MessageHandler(unsigned int connection, unsigned int messageType, void *messageArgument) {
|
||||
ConnexionDeviceState *state;
|
||||
|
||||
switch (messageType) {
|
||||
case kConnexionMsgDeviceState:
|
||||
state = (ConnexionDeviceState*)messageArgument;
|
||||
if (state->client == fConnexionClientID) {
|
||||
ConnexionData& connexiondata = ConnexionData::getInstance();
|
||||
connexiondata.cc_position = { state->axis[0], state->axis[1], state->axis[2] };
|
||||
connexiondata.cc_rotation = { state->axis[3], state->axis[4], state->axis[5] };
|
||||
|
||||
connexiondata.handleAxisEvent();
|
||||
if (state->buttons != lastState.buttons) {
|
||||
connexiondata.setButton(state->buttons);
|
||||
}
|
||||
memmove(&lastState, state, (long)sizeof(ConnexionDeviceState));
|
||||
}
|
||||
break;
|
||||
case kConnexionMsgPrefsChanged:
|
||||
// the prefs have changed, do something
|
||||
break;
|
||||
default:
|
||||
// other messageTypes can happen and should be ignored
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // __APPLE__
|
||||
|
||||
#endif // HAVE_3DCONNEXIONCLIENT
|
||||
#endif
|
|
@ -1,223 +0,0 @@
|
|||
// 3DConnexionClient.h
|
||||
// interface/src/devices
|
||||
//
|
||||
// Created by Marcel 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
|
||||
//
|
||||
|
||||
#ifndef hifi_3DConnexionClient_h
|
||||
#define hifi_3DConnexionClient_h
|
||||
|
||||
#if 0
|
||||
#include <QObject>
|
||||
#include <QLibrary>
|
||||
#include <controllers/UserInputMapper.h>
|
||||
|
||||
#include "InterfaceLogging.h"
|
||||
|
||||
#ifndef HAVE_3DCONNEXIONCLIENT
|
||||
class ConnexionClient : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static ConnexionClient& getInstance();
|
||||
void init() {};
|
||||
void destroy() {};
|
||||
bool Is3dmouseAttached() { return false; };
|
||||
public slots:
|
||||
void toggleConnexion(bool shouldEnable) {};
|
||||
};
|
||||
#endif // NOT_HAVE_3DCONNEXIONCLIENT
|
||||
|
||||
#ifdef HAVE_3DCONNEXIONCLIENT
|
||||
// the windows connexion rawinput
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
#include "I3dMouseParams.h"
|
||||
#include <QAbstractNativeEventFilter>
|
||||
#include <QAbstractEventDispatcher>
|
||||
#include <Winsock2.h>
|
||||
#include <windows.h>
|
||||
|
||||
// windows rawinput parameters
|
||||
class MouseParameters : public I3dMouseParam {
|
||||
public:
|
||||
MouseParameters();
|
||||
|
||||
// I3dmouseSensor interface
|
||||
bool IsPanZoom() const;
|
||||
bool IsRotate() const;
|
||||
Speed GetSpeed() const;
|
||||
|
||||
void SetPanZoom(bool isPanZoom);
|
||||
void SetRotate(bool isRotate);
|
||||
void SetSpeed(Speed speed);
|
||||
|
||||
// I3dmouseNavigation interface
|
||||
Navigation GetNavigationMode() const;
|
||||
Pivot GetPivotMode() const;
|
||||
PivotVisibility GetPivotVisibility() const;
|
||||
bool IsLockHorizon() const;
|
||||
|
||||
void SetLockHorizon(bool bOn);
|
||||
void SetNavigationMode(Navigation navigation);
|
||||
void SetPivotMode(Pivot pivot);
|
||||
void SetPivotVisibility(PivotVisibility visibility);
|
||||
|
||||
static bool Is3dmouseAttached();
|
||||
|
||||
private:
|
||||
MouseParameters(const MouseParameters&);
|
||||
const MouseParameters& operator = (const MouseParameters&);
|
||||
|
||||
Navigation fNavigation;
|
||||
Pivot fPivot;
|
||||
PivotVisibility fPivotVisibility;
|
||||
bool fIsLockHorizon;
|
||||
|
||||
bool fIsPanZoom;
|
||||
bool fIsRotate;
|
||||
Speed fSpeed;
|
||||
};
|
||||
|
||||
class ConnexionClient : public QObject, public QAbstractNativeEventFilter {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ConnexionClient() {};
|
||||
|
||||
static ConnexionClient& getInstance();
|
||||
void init();
|
||||
void destroy();
|
||||
bool Is3dmouseAttached();
|
||||
|
||||
ConnexionClient* client;
|
||||
|
||||
I3dMouseParam& MouseParams();
|
||||
const I3dMouseParam& MouseParams() const;
|
||||
|
||||
virtual void Move3d(HANDLE device, std::vector<float>& motionData);
|
||||
virtual void On3dmouseKeyDown(HANDLE device, int virtualKeyCode);
|
||||
virtual void On3dmouseKeyUp(HANDLE device, int virtualKeyCode);
|
||||
|
||||
virtual bool nativeEventFilter(const QByteArray& eventType, void* message, long* result) Q_DECL_OVERRIDE
|
||||
{
|
||||
MSG* msg = static_cast< MSG * >(message);
|
||||
return RawInputEventFilter(message, result);
|
||||
}
|
||||
|
||||
public slots:
|
||||
void toggleConnexion(bool shouldEnable);
|
||||
|
||||
signals:
|
||||
void Move3d(std::vector<float>& motionData);
|
||||
void On3dmouseKeyDown(int virtualKeyCode);
|
||||
void On3dmouseKeyUp(int virtualKeyCode);
|
||||
|
||||
private:
|
||||
bool InitializeRawInput(HWND hwndTarget);
|
||||
|
||||
bool RawInputEventFilter(void* msg, long* result);
|
||||
|
||||
void OnRawInput(UINT nInputCode, HRAWINPUT hRawInput);
|
||||
UINT GetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader);
|
||||
bool TranslateRawInputData(UINT nInputCode, PRAWINPUT pRawInput);
|
||||
void On3dmouseInput();
|
||||
|
||||
class TInputData {
|
||||
public:
|
||||
TInputData() : fAxes(6) {}
|
||||
|
||||
bool IsZero() {
|
||||
return (0.0f == fAxes[0] && 0.0f == fAxes[1] && 0.0f == fAxes[2] &&
|
||||
0.0f == fAxes[3] && 0.0f == fAxes[4] && 0.0f == fAxes[5]);
|
||||
}
|
||||
|
||||
int fTimeToLive; // For telling if the device was unplugged while sending data
|
||||
bool fIsDirty;
|
||||
std::vector<float> fAxes;
|
||||
|
||||
};
|
||||
|
||||
HWND fWindow;
|
||||
|
||||
// Data cache to handle multiple rawinput devices
|
||||
std::map< HANDLE, TInputData> fDevice2Data;
|
||||
std::map< HANDLE, unsigned long> fDevice2Keystate;
|
||||
|
||||
// 3dmouse parameters
|
||||
MouseParameters f3dMouseParams; // Rotate, Pan Zoom etc.
|
||||
|
||||
// use to calculate distance traveled since last event
|
||||
DWORD fLast3dmouseInputTime;
|
||||
};
|
||||
|
||||
// the osx connexion api
|
||||
#else
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include "ConnexionClientAPI.h"
|
||||
|
||||
class ConnexionClient : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static ConnexionClient& getInstance();
|
||||
void init();
|
||||
void destroy();
|
||||
bool Is3dmouseAttached();
|
||||
public slots:
|
||||
void toggleConnexion(bool shouldEnable);
|
||||
};
|
||||
|
||||
#endif // __APPLE__
|
||||
|
||||
#endif // HAVE_3DCONNEXIONCLIENT
|
||||
|
||||
|
||||
// connnects to the userinputmapper
|
||||
class ConnexionData : public QObject, public controller::InputDevice {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static ConnexionData& getInstance();
|
||||
ConnexionData();
|
||||
enum PositionChannel {
|
||||
TRANSLATE_X,
|
||||
TRANSLATE_Y,
|
||||
TRANSLATE_Z,
|
||||
ROTATE_X,
|
||||
ROTATE_Y,
|
||||
ROTATE_Z,
|
||||
};
|
||||
|
||||
enum ButtonChannel {
|
||||
BUTTON_1 = 1,
|
||||
BUTTON_2 = 2,
|
||||
BUTTON_3 = 3
|
||||
};
|
||||
|
||||
typedef std::unordered_set<int> ButtonPressedMap;
|
||||
typedef std::map<int, float> AxisStateMap;
|
||||
|
||||
float getButton(int channel) const;
|
||||
float getAxis(int channel) const;
|
||||
|
||||
controller::Input makeInput(ConnexionData::PositionChannel axis);
|
||||
controller::Input makeInput(ConnexionData::ButtonChannel button);
|
||||
virtual void buildDeviceProxy(controller::DeviceProxy::Pointer proxy) override;
|
||||
virtual QString getDefaultMappingConfig() override;
|
||||
virtual void update(float deltaTime, bool jointsCaptured) override;
|
||||
virtual void focusOutEvent() override;
|
||||
|
||||
glm::vec3 cc_position;
|
||||
glm::vec3 cc_rotation;
|
||||
int clientId;
|
||||
|
||||
void setButton(int lastButtonState);
|
||||
void handleAxisEvent();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // defined(hifi_3DConnexionClient_h)
|
Loading…
Reference in a new issue