From 94ae1ef638c5e48788853fe1a6ceb13315214999 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Mon, 2 Nov 2015 20:37:57 -0800 Subject: [PATCH 01/29] Fix accumulateTime --- libraries/animation/src/AnimClip.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/animation/src/AnimClip.cpp b/libraries/animation/src/AnimClip.cpp index 8f50874ed3..b2b6f728fd 100644 --- a/libraries/animation/src/AnimClip.cpp +++ b/libraries/animation/src/AnimClip.cpp @@ -81,7 +81,7 @@ void AnimClip::setCurrentFrameInternal(float frame) { // because dt is 0, we should not encounter any triggers const float dt = 0.0f; Triggers triggers; - _frame = ::accumulateTime(_startFrame, _endFrame, _timeScale, frame, dt, _loopFlag, _id, triggers); + _frame = ::accumulateTime(_startFrame, _endFrame, _timeScale, frame + _startFrame, dt, _loopFlag, _id, triggers); } void AnimClip::copyFromNetworkAnim() { From b74ed36883ad03602096c8280a230e5475df8b51 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Mon, 2 Nov 2015 20:39:31 -0800 Subject: [PATCH 02/29] Fix outro start times, and introduce away states (which are not used in C++ code, but are used in script). --- .../defaultAvatar_full/avatar-animation.json | 89 ++++++++++++++++--- 1 file changed, 78 insertions(+), 11 deletions(-) diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index fd1099a85b..9398b94890 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -178,7 +178,7 @@ "type": "clip", "data": { "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/point_right_hand.fbx", - "startFrame": 0.0, + "startFrame": 12.0, "endFrame": 65.0, "timeScale": 1.0, "loopFlag": false @@ -327,7 +327,7 @@ "type": "clip", "data": { "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/point_left_hand.fbx", - "startFrame": 0.0, + "startFrame": 12.0, "endFrame": 65.0, "timeScale": 1.0, "loopFlag": false @@ -378,15 +378,16 @@ "states": [ { "id": "idle", - "interpTarget": 6, - "interpDuration": 6, + "interpTarget": 15, + "interpDuration": 15, "transitions": [ { "var": "isMovingForward", "state": "walkFwd" }, { "var": "isMovingBackward", "state": "walkBwd" }, { "var": "isMovingRight", "state": "strafeRight" }, { "var": "isMovingLeft", "state": "strafeLeft" }, { "var": "isTurningRight", "state": "turnRight" }, - { "var": "isTurningLeft", "state": "turnLeft" } + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isAway", "state": "awayIntro" } ] }, { @@ -399,7 +400,8 @@ { "var": "isMovingRight", "state": "strafeRight" }, { "var": "isMovingLeft", "state": "strafeLeft" }, { "var": "isTurningRight", "state": "turnRight" }, - { "var": "isTurningLeft", "state": "turnLeft" } + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isAway", "state": "awayIntro" } ] }, { @@ -412,7 +414,8 @@ { "var": "isMovingRight", "state": "strafeRight" }, { "var": "isMovingLeft", "state": "strafeLeft" }, { "var": "isTurningRight", "state": "turnRight" }, - { "var": "isTurningLeft", "state": "turnLeft" } + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isAway", "state": "awayIntro" } ] }, { @@ -425,7 +428,8 @@ { "var": "isMovingBackward", "state": "walkBwd" }, { "var": "isMovingLeft", "state": "strafeLeft" }, { "var": "isTurningRight", "state": "turnRight" }, - { "var": "isTurningLeft", "state": "turnLeft" } + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isAway", "state": "awayIntro" } ] }, { @@ -438,7 +442,8 @@ { "var": "isMovingBackward", "state": "walkBwd" }, { "var": "isMovingRight", "state": "strafeRight" }, { "var": "isTurningRight", "state": "turnRight" }, - { "var": "isTurningLeft", "state": "turnLeft" } + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isAway", "state": "awayIntro" } ] }, { @@ -451,7 +456,8 @@ { "var": "isMovingBackward", "state": "walkBwd" }, { "var": "isMovingRight", "state": "strafeRight" }, { "var": "isMovingLeft", "state": "strafeLeft" }, - { "var": "isTurningLeft", "state": "turnLeft" } + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isAway", "state": "awayIntro" } ] }, { @@ -464,7 +470,32 @@ { "var": "isMovingBackward", "state": "walkBwd" }, { "var": "isMovingRight", "state": "strafeRight" }, { "var": "isMovingLeft", "state": "strafeLeft" }, - { "var": "isTurningRight", "state": "turnRight" } + { "var": "isTurningRight", "state": "turnRight" }, + { "var": "isAway", "state": "awayIntro" } + ] + }, + { + "id": "awayIntro", + "interpTarget": 30, + "interpDuration": 30, + "transitions": [ + { "var": "awayIntroOnDone", "state": "away"} + ] + }, + { + "id": "away", + "interpTarget": 3, + "interpDuration": 3, + "transitions": [ + { "var": "isNotAway", "state": "awayOutro" } + ] + }, + { + "id": "awayOutro", + "interpTarget": 3, + "interpDuration": 3, + "transitions": [ + { "var": "awayOutroOnDone", "state": "idle" } ] } ] @@ -704,6 +735,42 @@ "children": [] } ] + }, + { + "id": "awayIntro", + "type": "clip", + "data": { + "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/kneel/kneel.fbx", + "startFrame": 0.0, + "endFrame": 83.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "away", + "type": "clip", + "data": { + "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/kneel/kneel.fbx", + "startFrame": 83.0, + "endFrame": 84.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "awayOutro", + "type": "clip", + "data": { + "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/kneel/kneel.fbx", + "startFrame": 84.0, + "endFrame": 167.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] } ] } From 1b7ed3d847fa71d6df316bf36755b43daedf4c20 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Mon, 2 Nov 2015 20:40:40 -0800 Subject: [PATCH 03/29] away script --- examples/away.js | 84 ++++++++++++++++++++++++++++++++++++++ examples/defaultScripts.js | 1 + 2 files changed, 85 insertions(+) create mode 100644 examples/away.js diff --git a/examples/away.js b/examples/away.js new file mode 100644 index 0000000000..9fd688dbb7 --- /dev/null +++ b/examples/away.js @@ -0,0 +1,84 @@ +"use strict"; +/*jslint vars: true, plusplus: true*/ +/*global HMD, AudioDevice, MyAvatar, Controller, Script, Overlays, print*/ + +// Goes into "paused" when the '.' key (and automatically when started in HMD), and normal when pressing any key. +// See MAIN CONTROL, below, for what "paused" actually does. + +var OVERLAY_DATA = { + text: "Paused:\npress any key to continue", + font: {size: 75}, + color: {red: 200, green: 255, blue: 255}, + alpha: 0.9 +}; + +// ANIMATION +// We currently don't have play/stopAnimation integrated with the animation graph, but we can get the same effect +// using an animation graph with a state that we turn on and off through the animation var defined with that state. +var awayAnimationHandlerId, activeAnimationHandlerId; +function playAwayAnimation() { + function animateAway() { + return {isAway: true, isNotAway: false, isNotMoving: false}; + } + awayAnimationHandlerId = MyAvatar.addAnimationStateHandler(animateAway, null); +} +function stopAwayAnimation() { + MyAvatar.removeAnimationStateHandler(awayAnimationHandlerId); + function animateActive(state) { + if (!state.isAway) { // Once the right state gets reflected back to us, we don't need the hander any more. + // But we are locked against handler changes during the execution of a handler, so remove asynchronously. + Script.setTimeout(function () { MyAvatar.removeAnimationStateHandler(activeAnimationHandlerId); }, 0); + } + return {isAway: false, isNotAway: true}; // IWBNI we had a way of deleting an anim var. + } + activeAnimationHandlerId = MyAvatar.addAnimationStateHandler(animateActive, ['isAway']); +} + +// OVERLAY +var overlay = Overlays.addOverlay("text", OVERLAY_DATA); +function showOverlay() { + var screen = Controller.getViewportDimensions(); + Overlays.editOverlay(overlay, {visible: true, x: screen.x / 4, y: screen.y / 4}); +} +function hideOverlay() { + Overlays.editOverlay(overlay, {visible: false}); +} +hideOverlay(); + + +// MAIN CONTROL +var wasMuted, isAway; +function goAway() { + if (isAway) { + return; + } + isAway = true; + print('going "away"'); + wasMuted = AudioDevice.getMuted(); + if (!wasMuted) { + AudioDevice.toggleMute(); + } + MyAvatar.setEnableMeshVisible(false); // just for our own display, without changing point of view + playAwayAnimation(); // animation is still seen by others + showOverlay(); +} +function goActive(event) { + if (!isAway) { + if (event.text === '.') { + goAway(); + } + return; + } + isAway = false; + print('going "active"'); + if (!wasMuted) { + AudioDevice.toggleMute(); + } + MyAvatar.setEnableMeshVisible(true); // IWBNI we respected Developer->Avatar->Draw Mesh setting. + stopAwayAnimation(); + hideOverlay(); +} +Controller.keyPressEvent.connect(goActive); +if (HMD.active) { + goAway(); +} diff --git a/examples/defaultScripts.js b/examples/defaultScripts.js index 53e7e43aa9..6efe6edef3 100644 --- a/examples/defaultScripts.js +++ b/examples/defaultScripts.js @@ -8,6 +8,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +Script.load("away.js"); Script.load("progress.js"); Script.load("edit.js"); Script.load("selectAudioDevice.js"); From 603405ad61d8009fa81e0c6c2e791dc2d3731af4 Mon Sep 17 00:00:00 2001 From: EdgarPironti Date: Mon, 2 Nov 2015 23:29:15 -0800 Subject: [PATCH 04/29] Do not merge - Spacemouse --- interface/src/Application.cpp | 13 +- interface/src/Menu.cpp | 12 +- interface/src/devices/3DConnexionClient.cpp | 972 -------------------- interface/src/devices/3DConnexionClient.h | 223 ----- 4 files changed, 10 insertions(+), 1210 deletions(-) delete mode 100755 interface/src/devices/3DConnexionClient.cpp delete mode 100755 interface/src/devices/3DConnexionClient.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6d41679bea..dc166e729b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -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) { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 1565db2905..c15ce4a066 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -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"); diff --git a/interface/src/devices/3DConnexionClient.cpp b/interface/src/devices/3DConnexionClient.cpp deleted file mode 100755 index 38a9b4cb29..0000000000 --- a/interface/src/devices/3DConnexionClient.cpp +++ /dev/null @@ -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 -#include - -#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 { - using namespace controller; - static QVector 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 - -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->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(SpacePilotKeys), - CONNEXIONPID_SPACEEXPLORER, - sizeof(SpaceExplorerKeys) / sizeof(SpaceExplorerKeys[0]), - const_cast(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(); - 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(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& 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(nDevices); - if (::GetRawInputDeviceList(&rawInputDeviceList[0], &nDevices, sizeof(RAWINPUTDEVICELIST)) == static_cast(-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(msg.lParam); - size_t cbSize = *pcbSize - cbDataSize; - if (::GetRawInputData(hRawInput, RID_INPUT, pri, &cbSize, cbSizeHeader) == static_cast(-1)) { - if (nCount == 0) { - return static_cast(-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(pri)-reinterpret_cast(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::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::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 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(pBuffer); - UINT cbSize = cbSizeOfBuffer; - - if (::GetRawInputData(hRawInput, RID_INPUT, pRawInput, &cbSize, sizeof(RAWINPUTHEADER)) == static_cast(-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(-1)) { - PRAWINPUT pri = pRawInput; - UINT nInput; - for (nInput = 0; nInputGetRawInputBuffer(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 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(&pRawInput->data.hid.bRawData[1]); - // Cache the pan zoom data - deviceData.fAxes[0] = static_cast(pnRawData[0]); - deviceData.fAxes[1] = static_cast(pnRawData[1]); - deviceData.fAxes[2] = static_cast(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(pnRawData[3]); - deviceData.fAxes[4] = static_cast(pnRawData[4]); - deviceData.fAxes[5] = static_cast(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(&pRawInput->data.hid.bRawData[1]); - // Cache the rotation data - deviceData.fAxes[3] = static_cast(pnRawData[0]); - deviceData.fAxes[4] = static_cast(pnRawData[1]); - deviceData.fAxes[5] = static_cast(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(&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->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->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->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->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 \ No newline at end of file diff --git a/interface/src/devices/3DConnexionClient.h b/interface/src/devices/3DConnexionClient.h deleted file mode 100755 index 03a43d4c64..0000000000 --- a/interface/src/devices/3DConnexionClient.h +++ /dev/null @@ -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 -#include -#include - -#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 -#include -#include -#include - -// 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& 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& 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 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 -#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 ButtonPressedMap; - typedef std::map 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) From 5d695da630dbdabfd9fdcd72d188ce15fbaec674 Mon Sep 17 00:00:00 2001 From: EdgarPironti Date: Mon, 2 Nov 2015 23:31:10 -0800 Subject: [PATCH 05/29] Do not merge - Spacemouse --- .../Spacemouse/spacemouseExample.js | 72 ++ .../resources/controllers/spacemouse.json | 15 + .../src/input-plugins/SpacemouseManager.cpp | 1022 +++++++++++++++++ .../src/input-plugins/SpacemouseManager.h | 236 ++++ 4 files changed, 1345 insertions(+) create mode 100644 examples/controllers/Spacemouse/spacemouseExample.js create mode 100644 interface/resources/controllers/spacemouse.json create mode 100644 libraries/input-plugins/src/input-plugins/SpacemouseManager.cpp create mode 100644 libraries/input-plugins/src/input-plugins/SpacemouseManager.h diff --git a/examples/controllers/Spacemouse/spacemouseExample.js b/examples/controllers/Spacemouse/spacemouseExample.js new file mode 100644 index 0000000000..904f29cd75 --- /dev/null +++ b/examples/controllers/Spacemouse/spacemouseExample.js @@ -0,0 +1,72 @@ +// +// spaceMouseDebug.js +// examples +// +// 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 +// + + + +var firstmove = 1; +var position = { + x: 0, + y: 0, + z: 0 + }; +var rotation = { + x: 0, + y: 0, + z: 0 + }; + +function toggleFirstMove() { + if(firstmove){ + print("____________________________________"); + firstmove = 0; + } +} + +function spacemouseCheck() { + return Controller.Hardware.Spacemouse !== undefined; +} + +function update(deltaTime) { + if(spacemouseCheck){ + if(Controller.getValue(Controller.Standard.LY) != 0){ + toggleFirstMove(); + print("Controller TX: " + Controller.getValue(Controller.Standard.LY)); + } + + if(Controller.getValue(Controller.Standard.LX) != 0){ + toggleFirstMove(); + print("Controller TZ: " + Controller.getValue(Controller.Standard.LX)); + } + + if(Controller.getValue(Controller.Standard.LT) != 0){ + toggleFirstMove(); + print("Controller TY: " + Controller.getValue(Controller.Standard.LT)); + } + + if(Controller.getValue(Controller.Standard.RY) != 0){ + toggleFirstMove(); + print("Controller RX: " + Controller.getValue(Controller.Standard.RY)); + } + + if(Controller.getValue(Controller.Standard.RX) != 0){ + toggleFirstMove(); + print("Controller RZ: " + Controller.getValue(Controller.Standard.RX)); + } + + if(Controller.getValue(Controller.Standard.RT) != 0){ + toggleFirstMove(); + print("Controller RY: " + Controller.getValue(Controller.Standard.RT)); + } + + firstmove = 1; + } +} + +Script.update.connect(update); \ No newline at end of file diff --git a/interface/resources/controllers/spacemouse.json b/interface/resources/controllers/spacemouse.json new file mode 100644 index 0000000000..61af605512 --- /dev/null +++ b/interface/resources/controllers/spacemouse.json @@ -0,0 +1,15 @@ +{ + "name": "Spacemouse to Standard", + "channels": [ + { "from": "Spacemouse.TranslateX", "to": "Standard.LY" }, + { "from": "Spacemouse.TranslateZ", "filters": "invert", "to": "Standard.LX" }, + + { "from": "Spacemouse.RotateX", "to": "Standard.RY" }, + { "from": "Spacemouse.RotateZ", "to": "Standard.RX" }, + + { "from": "Spacemouse.LeftButton", "to": "Standard.Back" }, + { "from": "Spacemouse.RightButton", "to": "Standard.Start" } + + ] +} + diff --git a/libraries/input-plugins/src/input-plugins/SpacemouseManager.cpp b/libraries/input-plugins/src/input-plugins/SpacemouseManager.cpp new file mode 100644 index 0000000000..3078f99a23 --- /dev/null +++ b/libraries/input-plugins/src/input-plugins/SpacemouseManager.cpp @@ -0,0 +1,1022 @@ +// +// 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" + +#include +#include + +#include +#include + +#include "../../../interface/src/Menu.h" + +const float MAX_AXIS = 75.0f; // max forward = 2x speed + +static std::shared_ptr instance = NULL; +SpacemouseDevice::SpacemouseDevice() : +InputDevice("Spacemouse") +{ + instance = std::shared_ptr(this); +} + +void SpacemouseDevice::focusOutEvent() { + _axisStateMap.clear(); + _buttonPressedMap.clear(); +}; + + +//SpacemouseDevice& SpacemouseDevice::getInstance() { +// static SpacemouseDevice sharedInstance; +// return sharedInstance; +//} + + + +//std::shared_ptr SpacemouseManager::getDevice(){ +// return instance; +//} + +//SpacemouseDevice::SpacemouseDevice() : InputDevice("Spacemouse") {} + + +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_rotation / 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; +} + +//void SpacemouseDevice::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 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, bool jointsCaptured) { + // 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 +} + +SpacemouseManager& SpacemouseManager::getInstance() { + static SpacemouseManager sharedInstance; + if (instance == NULL){ + new SpacemouseDevice(); + } + return sharedInstance; +} + +void SpacemouseManager::ManagerFocusOutEvent() { + instance->focusOutEvent(); +} + +#ifdef HAVE_SPACEMOUSE + +#ifdef Q_OS_WIN + +#include + + + +void SpacemouseManager::toggleSpacemouse(bool shouldEnable) { + //SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); + //if (shouldEnable && spacemousedevice.getDeviceID() == controller::Input::INVALID_DEVICE) { + if (shouldEnable && instance->getDeviceID() == controller::Input::INVALID_DEVICE) { + init(); + } + if (!shouldEnable && instance->getDeviceID() != controller::Input::INVALID_DEVICE) { + destroy(); + } +} + +void SpacemouseManager::init() { + if (Menu::getInstance()->isOptionChecked(MenuOption::Connexion)) { + fLast3dmouseInputTime = 0; + + InitializeRawInput(GetActiveWindow()); + + QAbstractEventDispatcher::instance()->installNativeEventFilter(this); + } +} + +void SpacemouseManager::destroy() { + QAbstractEventDispatcher::instance()->removeNativeEventFilter(this); + //SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); + //int deviceid = spacemousedevice.getDeviceID(); + int deviceid = instance->getDeviceID(); + auto userInputMapper = DependencyManager::get(); + 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(SpacePilotKeys), + CONNEXIONPID_SPACEEXPLORER, + sizeof(SpaceExplorerKeys) / sizeof(SpaceExplorerKeys[0]), + const_cast(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(); + //if (Is3dmouseAttached() && spacemousedevice.getDeviceID() == controller::Input::INVALID_DEVICE) { + if (Is3dmouseAttached() && instance->getDeviceID() == controller::Input::INVALID_DEVICE) { + userInputMapper->registerDevice(instance); + UserActivityLogger::getInstance().connectedDevice("controller", "Spacemouse"); + } + //else if (!Is3dmouseAttached() && spacemousedevice.getDeviceID() != controller::Input::INVALID_DEVICE) { + 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(message->lParam); + OnRawInput(RIM_INPUT, hRawInput); + if (result != 0) { + result = 0; + } + return true; + } + return false; +} + +// Access the mouse parameters structure +I3dMouseParam& SpacemouseManager::MouseParams() { + return f3dMouseParams; +} + +// Access the mouse parameters structure +const I3dMouseParam& SpacemouseManager::MouseParams() const { + return f3dMouseParams; +} + +//Called with the processed motion data when a 3D mouse event is received +void SpacemouseManager::Move3d(HANDLE device, std::vector& 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); + //SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); + instance->setButton(virtualKeyCode); +} + +//Called when a 3D mouse key is released +void SpacemouseManager::On3dmouseKeyUp(HANDLE device, int virtualKeyCode) { + Q_UNUSED(device); + //SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); + instance->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 SpacemouseManager::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(nDevices); + if (::GetRawInputDeviceList(&rawInputDeviceList[0], &nDevices, sizeof(RAWINPUTDEVICELIST)) == static_cast(-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 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(msg.lParam); + size_t cbSize = *pcbSize - cbDataSize; + if (::GetRawInputData(hRawInput, RID_INPUT, pri, &cbSize, cbSizeHeader) == static_cast(-1)) { + if (nCount == 0) { + return static_cast(-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(pri)-reinterpret_cast(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::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::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 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 SpacemouseManager::OnRawInput(UINT nInputCode, HRAWINPUT hRawInput) { + const size_t cbSizeOfBuffer = 1024; + BYTE pBuffer[cbSizeOfBuffer]; + + PRAWINPUT pRawInput = reinterpret_cast(pBuffer); + UINT cbSize = cbSizeOfBuffer; + + if (::GetRawInputData(hRawInput, RID_INPUT, pRawInput, &cbSize, sizeof(RAWINPUTHEADER)) == static_cast(-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(-1)) { + PRAWINPUT pri = pRawInput; + UINT nInput; + for (nInput = 0; nInputGetRawInputBuffer(pRawInput, &cbSize, sizeof(RAWINPUTHEADER)); + } + + // If we have mouse input data for the app then tell tha app about it + if (b3dmouseInput) { + On3dmouseInput(); + } +} + +bool SpacemouseManager::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 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(&pRawInput->data.hid.bRawData[1]); + // Cache the pan zoom data + deviceData.fAxes[0] = static_cast(pnRawData[0]); + deviceData.fAxes[1] = static_cast(pnRawData[1]); + deviceData.fAxes[2] = static_cast(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(pnRawData[3]); + deviceData.fAxes[4] = static_cast(pnRawData[4]); + deviceData.fAxes[5] = static_cast(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(&pRawInput->data.hid.bRawData[1]); + // Cache the rotation data + deviceData.fAxes[3] = static_cast(pnRawData[0]); + deviceData.fAxes[4] = static_cast(pnRawData[1]); + deviceData.fAxes[5] = static_cast(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(&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 SpacemouseDeviceState 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 SpacemouseManager::toggleSpacemouse(bool shouldEnable) { + if (shouldEnable && !Is3dmouseAttached()) { + init(); + } + if (!shouldEnable && Is3dmouseAttached()) { + destroy(); + } +} + +void SpacemouseManager::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); + SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); + memcpy(&spacemousedevice.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() && spacemousedevice.getDeviceID() == controller::Input::INVALID_DEVICE) { + auto userInputMapper = DependencyManager::get(); + userInputMapper->registerDevice(&spacemousedevice); + UserActivityLogger::getInstance().connectedDevice("controller", "Spacemouse"); + } + //let one axis be dominant + //ConnexionClientControl(fConnexionClientID, kConnexionCtlSetSwitches, kConnexionSwitchDominant | kConnexionSwitchEnableAll, NULL); + } +} + +void SpacemouseManager::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; + SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); + if (spacemousedevice.getDeviceID() != controller::Input::INVALID_DEVICE) { + auto userInputMapper = DependencyManager::get(); + userInputMapper->removeDevice(spacemousedevice.getDeviceID()); + spacemousedevice.setDeviceID(0); + } + } +} + +void DeviceAddedHandler(unsigned int connection) { + SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); + if (spacemousedevice.getDeviceID() == controller::Input::INVALID_DEVICE) { + qCWarning(interfaceapp) << "Spacemouse device added "; + auto userInputMapper = DependencyManager::get(); + userInputMapper->registerDevice(&spacemousedevice); + UserActivityLogger::getInstance().connectedDevice("controller", "Spacemouse"); + } +} + +void DeviceRemovedHandler(unsigned int connection) { + SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); + if (spacemousedevice.getDeviceID() != controller::Input::INVALID_DEVICE) { + qCWarning(interfaceapp) << "Spacemouse device removed"; + auto userInputMapper = DependencyManager::get(); + userInputMapper->removeDevice(spacemousedevice.getDeviceID()); + spacemousedevice.setDeviceID(controller::Input::INVALID_DEVICE); + } +} + +bool SpacemouseManager::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) { + SpacemouseDeviceState *state; + + switch (messageType) { + case kConnexionMsgDeviceState: + state = (SpacemouseDeviceState*)messageArgument; + if (state->client == fConnexionClientID) { + //SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); + instance->cc_position = { state->axis[0], state->axis[1], state->axis[2] }; + instance->cc_rotation = { state->axis[3], state->axis[4], state->axis[5] }; + + instance->handleAxisEvent(); + if (state->buttons != lastState.buttons) { + instance->setButton(state->buttons); + } + memmove(&lastState, state, (long)sizeof(SpacemouseDeviceState)); + } + break; + case kConnexionMsgPrefsChanged: + // the prefs have changed, do something + break; + default: + // other messageTypes can happen and should be ignored + break; + } + +} + +#endif // __APPLE__ + +#endif diff --git a/libraries/input-plugins/src/input-plugins/SpacemouseManager.h b/libraries/input-plugins/src/input-plugins/SpacemouseManager.h new file mode 100644 index 0000000000..5379af9991 --- /dev/null +++ b/libraries/input-plugins/src/input-plugins/SpacemouseManager.h @@ -0,0 +1,236 @@ +// SpacemouseManager.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_SpacemouseManager_h +#define hifi_SpacemouseManager_h + +#include +#include +#include +#include +#include + +#include "InputPlugin.h" + +#ifndef HAVE_SPACEMOUSE +class SpacemouseManager : public QObject { + Q_OBJECT +public: + static SpacemouseManager& getInstance(); + void ManagerFocusOutEvent(); + void init() {}; + void destroy() {}; + bool Is3dmouseAttached() { return false; }; + public slots: + void toggleConnexion(bool shouldEnable) {}; +}; +#endif + +#ifdef HAVE_SPACEMOUSE +// the windows connexion rawinput +#ifdef Q_OS_WIN + +#include "../../../interface/external/3dconnexionclient/include/I3dMouseParams.h" +#include +#include +#include +#include + +// 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 SpacemouseManager : public QObject, public QAbstractNativeEventFilter { +//class SpacemouseManager : public InputPlugin, public controller::InputDevice { + + Q_OBJECT +public: + SpacemouseManager() {}; + + static SpacemouseManager& getInstance(); + void init(); + void destroy(); + bool Is3dmouseAttached(); + + SpacemouseManager* client; + + void ManagerFocusOutEvent(); + + I3dMouseParam& MouseParams(); + const I3dMouseParam& MouseParams() const; + + virtual void Move3d(HANDLE device, std::vector& 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 toggleSpacemouse(bool shouldEnable); + + //std::shared_ptr getDevice(); + + +signals: + void Move3d(std::vector& 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 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 +#include "../../../interface/external/3dconnexionclient/include/ConnexionClientAPI.h" + +class SpacemouseManager : public QObject { + Q_OBJECT +public: + static SpacemouseManager& getInstance(); + void init(); + void destroy(); + bool Is3dmouseAttached(); + public slots: + void toggleSpacemouse(bool shouldEnable); +}; + +#endif // __APPLE__ + +#endif + + +// connnects to the userinputmapper +class SpacemouseDevice : public QObject, public controller::InputDevice { + Q_OBJECT + +public: + //static SpacemouseDevice& getInstance(); + SpacemouseDevice(); + 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 ButtonPressedMap; + typedef std::map AxisStateMap; + + float getButton(int channel) const; + float getAxis(int channel) const; + + controller::Input makeInput(SpacemouseDevice::PositionChannel axis) const; + controller::Input makeInput(SpacemouseDevice::ButtonChannel button) const; + + controller::Input::NamedPair makePair(SpacemouseDevice::PositionChannel axis, const QString& name) const; + controller::Input::NamedPair makePair(SpacemouseDevice::ButtonChannel button, const QString& name) const; + + virtual controller::Input::NamedVector getAvailableInputs() const override; + virtual QString getDefaultMappingConfig() const 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 // defined(hifi_SpacemouseManager_h) \ No newline at end of file From a7162eefbebbc550548f9eba209331643a7c0deb Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 3 Nov 2015 13:10:25 -0800 Subject: [PATCH 06/29] Add alphaVar for ik. --- .../resources/meshes/defaultAvatar_full/avatar-animation.json | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index 9398b94890..df8b9b16c8 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -5,6 +5,7 @@ "type": "overlay", "data": { "alpha": 1.0, + "alphaVar": "ikOverlayAlpha", "boneSet": "fullBody" }, "children": [ From fb4174b9a2753fbf280c6e59520264e360589bc5 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 3 Nov 2015 13:11:31 -0800 Subject: [PATCH 07/29] Control alphaVar, and deal with overlapping cycles. --- examples/away.js | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/examples/away.js b/examples/away.js index 9fd688dbb7..c183f236fd 100644 --- a/examples/away.js +++ b/examples/away.js @@ -5,6 +5,7 @@ // Goes into "paused" when the '.' key (and automatically when started in HMD), and normal when pressing any key. // See MAIN CONTROL, below, for what "paused" actually does. +var IK_WINDOW_AFTER_GOING_ACTIVE = 3000; // milliseconds var OVERLAY_DATA = { text: "Paused:\npress any key to continue", font: {size: 75}, @@ -15,23 +16,41 @@ var OVERLAY_DATA = { // ANIMATION // We currently don't have play/stopAnimation integrated with the animation graph, but we can get the same effect // using an animation graph with a state that we turn on and off through the animation var defined with that state. -var awayAnimationHandlerId, activeAnimationHandlerId; +var awayAnimationHandlerId, activeAnimationHandlerId, stopper; function playAwayAnimation() { function animateAway() { - return {isAway: true, isNotAway: false, isNotMoving: false}; + return {isAway: true, isNotAway: false, isNotMoving: false, ikOverlayAlpha: 0.0}; + } + if (stopper) { + Script.clearTimeout(stopper); + MyAvatar.removeAnimationStateHandler(activeAnimationHandlerId); // do it now, before making new assignment } awayAnimationHandlerId = MyAvatar.addAnimationStateHandler(animateAway, null); } function stopAwayAnimation() { MyAvatar.removeAnimationStateHandler(awayAnimationHandlerId); + if (stopper) { print('WARNING: unexpected double stop'); return; } + // How do we know when to turn ikOverlayAlpha back on? + // It cannot be as soon as we want to stop the away animation, because then things will look goofy as we come out of that animation. + // (Imagine an away animation that sits or kneels, and then stands back up when coming out of it. If head is at the HMD, then it won't + // want to track the standing up animation.) + // Our standard anim graph flips 'awayOutroOnDone' for one frame, but it's a trigger (not an animVar) and other folks might use different graphs. + // So... Just give us a fixed amount of time to be done with animation, before we turn ik back on. + var backToNormal = false; + stopper = Script.setTimeout(function () { + backToNormal = true; + stopper = false; + }, IK_WINDOW_AFTER_GOING_ACTIVE); function animateActive(state) { - if (!state.isAway) { // Once the right state gets reflected back to us, we don't need the hander any more. - // But we are locked against handler changes during the execution of a handler, so remove asynchronously. - Script.setTimeout(function () { MyAvatar.removeAnimationStateHandler(activeAnimationHandlerId); }, 0); - } - return {isAway: false, isNotAway: true}; // IWBNI we had a way of deleting an anim var. + if (state.ikOverlayAlpha) { + // Once the right state gets reflected back to us, we don't need the hander any more. + // But we are locked against handler changes during the execution of a handler, so remove asynchronously. + Script.setTimeout(function () { MyAvatar.removeAnimationStateHandler(activeAnimationHandlerId); }, 0); + } + // It might be cool to "come back to life" by fading the ik overlay back in over a short time. But let's see how this goes. + return {isAway: false, isNotAway: true, ikOverlayAlpha: backToNormal ? 1.0 : 0.0}; // IWBNI we had a way of deleting an anim var. } - activeAnimationHandlerId = MyAvatar.addAnimationStateHandler(animateActive, ['isAway']); + activeAnimationHandlerId = MyAvatar.addAnimationStateHandler(animateActive, ['isAway', 'isNotAway', 'isNotMoving', 'ikOverlayAlpha']); } // OVERLAY @@ -48,8 +67,8 @@ hideOverlay(); // MAIN CONTROL var wasMuted, isAway; -function goAway() { - if (isAway) { +function goAway(event) { + if (isAway || event.isAutoRepeat) { // isAutoRepeat is true when held down (or when Windows feels like it) return; } isAway = true; @@ -63,9 +82,9 @@ function goAway() { showOverlay(); } function goActive(event) { - if (!isAway) { + if (!isAway || event.isAutoRepeat) { if (event.text === '.') { - goAway(); + goAway(event); } return; } @@ -79,6 +98,7 @@ function goActive(event) { hideOverlay(); } Controller.keyPressEvent.connect(goActive); +Script.scriptEnding.connect(goActive); if (HMD.active) { - goAway(); + goAway({}); // give a dummy event object } From 4bf98613505631009bb9b799d11d81bc9f3d3fa9 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 3 Nov 2015 15:36:02 -0800 Subject: [PATCH 08/29] Forgot license header. --- examples/away.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/examples/away.js b/examples/away.js index c183f236fd..dba26e0697 100644 --- a/examples/away.js +++ b/examples/away.js @@ -1,7 +1,16 @@ "use strict"; /*jslint vars: true, plusplus: true*/ /*global HMD, AudioDevice, MyAvatar, Controller, Script, Overlays, print*/ - +// +// away.js +// examples +// +// Created by Howard Stearns 11/3/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 +// // Goes into "paused" when the '.' key (and automatically when started in HMD), and normal when pressing any key. // See MAIN CONTROL, below, for what "paused" actually does. From 7adf38f7812ded2f4a03b2f178da5f00e2b68ca7 Mon Sep 17 00:00:00 2001 From: EdgarPironti Date: Tue, 3 Nov 2015 18:22:55 -0800 Subject: [PATCH 09/29] Spacemouse migration --- .../Spacemouse/spacemouseExample.js | 12 +- .../resources/controllers/spacemouse.json | 16 +- interface/src/Menu.cpp | 2 +- .../src/input-plugins/SpacemouseManager.cpp | 186 ++++++------------ .../src/input-plugins/SpacemouseManager.h | 8 +- 5 files changed, 82 insertions(+), 142 deletions(-) diff --git a/examples/controllers/Spacemouse/spacemouseExample.js b/examples/controllers/Spacemouse/spacemouseExample.js index 904f29cd75..46ccd80fa7 100644 --- a/examples/controllers/Spacemouse/spacemouseExample.js +++ b/examples/controllers/Spacemouse/spacemouseExample.js @@ -37,32 +37,32 @@ function update(deltaTime) { if(spacemouseCheck){ if(Controller.getValue(Controller.Standard.LY) != 0){ toggleFirstMove(); - print("Controller TX: " + Controller.getValue(Controller.Standard.LY)); + print("- Controller TY: " + Controller.getValue(Controller.Standard.LY)); } if(Controller.getValue(Controller.Standard.LX) != 0){ toggleFirstMove(); - print("Controller TZ: " + Controller.getValue(Controller.Standard.LX)); + print("- Controller RZ: " + Controller.getValue(Controller.Standard.LX)); } if(Controller.getValue(Controller.Standard.LT) != 0){ toggleFirstMove(); - print("Controller TY: " + Controller.getValue(Controller.Standard.LT)); + print("- Controller LEFTB: " + Controller.getValue(Controller.Standard.LT)); } if(Controller.getValue(Controller.Standard.RY) != 0){ toggleFirstMove(); - print("Controller RX: " + Controller.getValue(Controller.Standard.RY)); + print("- Controller TZ: " + Controller.getValue(Controller.Standard.RY)); } if(Controller.getValue(Controller.Standard.RX) != 0){ toggleFirstMove(); - print("Controller RZ: " + Controller.getValue(Controller.Standard.RX)); + print("- Controller TX: " + Controller.getValue(Controller.Standard.RX)); } if(Controller.getValue(Controller.Standard.RT) != 0){ toggleFirstMove(); - print("Controller RY: " + Controller.getValue(Controller.Standard.RT)); + print("- Controller RIGHTB: " + Controller.getValue(Controller.Standard.RT)); } firstmove = 1; diff --git a/interface/resources/controllers/spacemouse.json b/interface/resources/controllers/spacemouse.json index 61af605512..e02d0d4101 100644 --- a/interface/resources/controllers/spacemouse.json +++ b/interface/resources/controllers/spacemouse.json @@ -1,15 +1,15 @@ { "name": "Spacemouse to Standard", "channels": [ - { "from": "Spacemouse.TranslateX", "to": "Standard.LY" }, - { "from": "Spacemouse.TranslateZ", "filters": "invert", "to": "Standard.LX" }, - - { "from": "Spacemouse.RotateX", "to": "Standard.RY" }, - { "from": "Spacemouse.RotateZ", "to": "Standard.RX" }, - - { "from": "Spacemouse.LeftButton", "to": "Standard.Back" }, - { "from": "Spacemouse.RightButton", "to": "Standard.Start" } + { "from": "Spacemouse.TranslateX", "to": "Standard.RX" }, + { "from": "Spacemouse.TranslateY", "to": "Standard.LY" }, + { "from": "Spacemouse.TranslateZ", "to": "Standard.RY" }, + + { "from": "Spacemouse.RotateZ", "to": "Standard.LX" }, + + { "from": "Spacemouse.LeftButton", "to": "Standard.LT" }, + { "from": "Spacemouse.RightButton", "to": "Standard.RT" } ] } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index c15ce4a066..162b713948 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -465,7 +465,7 @@ Menu::Menu() { avatar, SLOT(setEnableMeshVisible(bool))); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::DisableEyelidAdjustment, 0, false); - addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::Connexion, 0, false, &SpacemouseManager::getInstance(), SLOT(toggleConnexion(bool))); + addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::Connexion, 0, false, &SpacemouseManager::getInstance(), SLOT(toggleSpacemouse(bool))); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ComfortMode, 0, true); diff --git a/libraries/input-plugins/src/input-plugins/SpacemouseManager.cpp b/libraries/input-plugins/src/input-plugins/SpacemouseManager.cpp index 3078f99a23..3f68be8039 100644 --- a/libraries/input-plugins/src/input-plugins/SpacemouseManager.cpp +++ b/libraries/input-plugins/src/input-plugins/SpacemouseManager.cpp @@ -34,26 +34,12 @@ void SpacemouseDevice::focusOutEvent() { }; -//SpacemouseDevice& SpacemouseDevice::getInstance() { -// static SpacemouseDevice sharedInstance; -// return sharedInstance; -//} - - - -//std::shared_ptr SpacemouseManager::getDevice(){ -// return instance; -//} - -//SpacemouseDevice::SpacemouseDevice() : InputDevice("Spacemouse") {} - - 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_rotation / MAX_AXIS; + auto position = cc_position / MAX_AXIS; _axisStateMap[TRANSLATE_X] = position.x; _axisStateMap[TRANSLATE_Y] = position.y; _axisStateMap[TRANSLATE_Z] = position.z; @@ -75,9 +61,9 @@ controller::Input::NamedVector SpacemouseDevice::getAvailableInputs() const { makePair(BUTTON_2, "RightButton"), //makePair(BUTTON_3, "BothButtons"), makePair(TRANSLATE_X, "TranslateX"), - //makePair(TRANSLATE_Y, "TranslateY"), + makePair(TRANSLATE_Y, "TranslateY"), makePair(TRANSLATE_Z, "TranslateZ"), - makePair(ROTATE_X, "RotateX"), + //makePair(ROTATE_X, "RotateX"), //makePair(ROTATE_Y, "RotateY"), makePair(ROTATE_Z, "RotateZ"), @@ -90,45 +76,11 @@ QString SpacemouseDevice::getDefaultMappingConfig() const { return MAPPING_JSON; } -//void SpacemouseDevice::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 SpacemouseDevice::getButton(int channel) const { if (!_buttonPressedMap.empty()) { if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) { return 1.0f; - } - else { + } else { return 0.0f; } } @@ -139,8 +91,7 @@ float SpacemouseDevice::getAxis(int channel) const { auto axis = _axisStateMap.find(channel); if (axis != _axisStateMap.end()) { return (*axis).second; - } - else { + } else { return 0.0f; } } @@ -179,18 +130,14 @@ void SpacemouseManager::ManagerFocusOutEvent() { instance->focusOutEvent(); } -#ifdef HAVE_SPACEMOUSE +#ifdef HAVE_3DCONNEXIONCLIENT #ifdef Q_OS_WIN #include - - void SpacemouseManager::toggleSpacemouse(bool shouldEnable) { - //SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); - //if (shouldEnable && spacemousedevice.getDeviceID() == controller::Input::INVALID_DEVICE) { - if (shouldEnable && instance->getDeviceID() == controller::Input::INVALID_DEVICE) { + if (shouldEnable) { init(); } if (!shouldEnable && instance->getDeviceID() != controller::Input::INVALID_DEVICE) { @@ -205,13 +152,18 @@ void SpacemouseManager::init() { InitializeRawInput(GetActiveWindow()); QAbstractEventDispatcher::instance()->installNativeEventFilter(this); + + if (instance->getDeviceID() != controller::Input::INVALID_DEVICE) { + auto userInputMapper = DependencyManager::get(); + userInputMapper->registerDevice(instance); + UserActivityLogger::getInstance().connectedDevice("controller", "Spacemouse"); + } + } } void SpacemouseManager::destroy() { QAbstractEventDispatcher::instance()->removeNativeEventFilter(this); - //SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); - //int deviceid = spacemousedevice.getDeviceID(); int deviceid = instance->getDeviceID(); auto userInputMapper = DependencyManager::get(); userInputMapper->removeDevice(deviceid); @@ -306,8 +258,7 @@ unsigned short HidToVirtualKey(unsigned long pid, unsigned short hidKeyCode) { if (pid == _3dmouseVirtualKeys[i].pid) { if (hidKeyCode < _3dmouseVirtualKeys[i].nKeys) { virtualkey = _3dmouseVirtualKeys[i].vkeys[hidKeyCode]; - } - else { + } else { virtualkey = V3DK_INVALID; } break; @@ -318,15 +269,12 @@ unsigned short HidToVirtualKey(unsigned long pid, unsigned short hidKeyCode) { } bool SpacemouseManager::RawInputEventFilter(void* msg, long* result) { - //SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); auto userInputMapper = DependencyManager::get(); - //if (Is3dmouseAttached() && spacemousedevice.getDeviceID() == controller::Input::INVALID_DEVICE) { if (Is3dmouseAttached() && instance->getDeviceID() == controller::Input::INVALID_DEVICE) { userInputMapper->registerDevice(instance); UserActivityLogger::getInstance().connectedDevice("controller", "Spacemouse"); } - //else if (!Is3dmouseAttached() && spacemousedevice.getDeviceID() != controller::Input::INVALID_DEVICE) { else if (!Is3dmouseAttached() && instance->getDeviceID() != controller::Input::INVALID_DEVICE) { userInputMapper->removeDevice(instance->getDeviceID()); } @@ -361,6 +309,7 @@ const I3dMouseParam& SpacemouseManager::MouseParams() const { //Called with the processed motion data when a 3D mouse event is received void SpacemouseManager::Move3d(HANDLE device, std::vector& 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(); @@ -478,8 +427,7 @@ UINT SpacemouseManager::GetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT c ::IsWow64Process(GetCurrentProcess(), &bIsWow64); if (!bIsWow64 || pData == NULL) { return ::GetRawInputBuffer(pData, pcbSize, cbSizeHeader); - } - else { + } else { HWND hwndTarget = fWindow; size_t cbDataSize = 0; @@ -493,8 +441,7 @@ UINT SpacemouseManager::GetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT c if (::GetRawInputData(hRawInput, RID_INPUT, pri, &cbSize, cbSizeHeader) == static_cast(-1)) { if (nCount == 0) { return static_cast(-1); - } - else { + } else { break; } } @@ -534,16 +481,14 @@ void SpacemouseManager::On3dmouseInput() { if (0 == fLast3dmouseInputTime) { dwElapsedTime = 10; // System timer resolution - } - else { + } else { dwElapsedTime = dwNow - fLast3dmouseInputTime; if (fLast3dmouseInputTime > dwNow) { dwElapsedTime = ~dwElapsedTime + 1; } if (dwElapsedTime<1) { dwElapsedTime = 1; - } - else if (dwElapsedTime > 500) { + } else if (dwElapsedTime > 500) { // Check for wild numbers because the device was removed while sending data dwElapsedTime = 10; } @@ -572,8 +517,7 @@ void SpacemouseManager::On3dmouseInput() { // 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 && + } else if (!iterator->second.fIsDirty) { //!t_bPoll3dmouse && // If we are not polling then only handle the data that was actually received ++iterator; continue; @@ -591,14 +535,14 @@ void SpacemouseManager::On3dmouseInput() { // 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 + // 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 + // Rotate is switched off so set the rotation vector values to zero motionData[3] = motionData[4] = motionData[5] = 0.; } @@ -622,8 +566,7 @@ void SpacemouseManager::On3dmouseInput() { // Now a bit of book keeping before passing on the data if (iterator->second.IsZero()) { iterator = fDevice2Data.erase(iterator); - } - else { + } else { ++iterator; } @@ -643,8 +586,7 @@ void SpacemouseManager::On3dmouseInput() { if (!fDevice2Data.empty()) { fLast3dmouseInputTime = dwNow; - } - else { + } else { fLast3dmouseInputTime = 0; } } @@ -746,22 +688,20 @@ bool SpacemouseManager::TranslateRawInputData(UINT nInputCode, PRAWINPUT pRawInp //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(pnRawData[3]); - deviceData.fAxes[4] = static_cast(pnRawData[4]); - deviceData.fAxes[5] = static_cast(pnRawData[5]); - deviceData.fIsDirty = true; + //if (pRawInput->data.hid.dwSizeHid >= 13) { // Highspeed package + // // Cache the rotation data + // deviceData.fAxes[3] = static_cast(pnRawData[3]); + // deviceData.fAxes[4] = static_cast(pnRawData[4]); + // deviceData.fAxes[5] = static_cast(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 + // 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 + } 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) { @@ -779,8 +719,7 @@ bool SpacemouseManager::TranslateRawInputData(UINT nInputCode, PRAWINPUT pRawInp return true; } - } - else if (pRawInput->data.hid.bRawData[0] == 0x03) { // Keystate change + } 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. @@ -792,8 +731,7 @@ bool SpacemouseManager::TranslateRawInputData(UINT nInputCode, PRAWINPUT pRawInp unsigned long dwOldKeystate = fDevice2Keystate[pRawInput->header.hDevice]; if (dwKeystate != 0) { fDevice2Keystate[pRawInput->header.hDevice] = dwKeystate; - } - else { + } else { fDevice2Keystate.erase(pRawInput->header.hDevice); } @@ -807,8 +745,7 @@ bool SpacemouseManager::TranslateRawInputData(UINT nInputCode, PRAWINPUT pRawInp if (nVirtualKeyCode) { if (dwKeystate & 0x01) { On3dmouseKeyDown(pRawInput->header.hDevice, nVirtualKeyCode); - } - else { + } else { On3dmouseKeyUp(pRawInput->header.hDevice, nVirtualKeyCode); } } @@ -824,13 +761,13 @@ bool SpacemouseManager::TranslateRawInputData(UINT nInputCode, PRAWINPUT pRawInp } MouseParameters::MouseParameters() : -fNavigation(NAVIGATION_OBJECT_MODE), -fPivot(PIVOT_AUTO), -fPivotVisibility(PIVOT_SHOW), -fIsLockHorizon(true), -fIsPanZoom(true), -fIsRotate(true), -fSpeed(SPEED_LOW) + fNavigation(NAVIGATION_OBJECT_MODE), + fPivot(PIVOT_AUTO), + fPivotVisibility(PIVOT_SHOW), + fIsLockHorizon(true), + fIsPanZoom(true), + fIsRotate(true), + fSpeed(SPEED_LOW) { } @@ -921,8 +858,9 @@ void SpacemouseManager::init() { // ...or use this to take over system-wide fConnexionClientID = RegisterConnexionClient(kConnexionClientWildcard, NULL, kConnexionClientModeTakeOver, kConnexionMaskAll); - SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); - memcpy(&spacemousedevice.clientId, &fConnexionClientID, (long)sizeof(int)); + //SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); + //memcpy(&spacemousedevice.clientId, &fConnexionClientID, (long)sizeof(int)); + memcpy(&instance->clientId, &fConnexionClientID, (long)sizeof(int)); // A separate API call is required to capture buttons beyond the first 8 SetConnexionClientButtonMask(fConnexionClientID, kConnexionMaskAllButtons); @@ -930,9 +868,9 @@ void SpacemouseManager::init() { // use default switches ConnexionClientControl(fConnexionClientID, kConnexionCtlSetSwitches, kConnexionSwitchesDisabled, NULL); - if (Is3dmouseAttached() && spacemousedevice.getDeviceID() == controller::Input::INVALID_DEVICE) { + if (Is3dmouseAttached() && instance->getDeviceID() == controller::Input::INVALID_DEVICE) { auto userInputMapper = DependencyManager::get(); - userInputMapper->registerDevice(&spacemousedevice); + userInputMapper->registerDevice(instance); UserActivityLogger::getInstance().connectedDevice("controller", "Spacemouse"); } //let one axis be dominant @@ -949,32 +887,32 @@ void SpacemouseManager::destroy() { } CleanupConnexionHandlers(); fConnexionClientID = 0; - SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); - if (spacemousedevice.getDeviceID() != controller::Input::INVALID_DEVICE) { + //SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); + if (instance->getDeviceID() != controller::Input::INVALID_DEVICE) { auto userInputMapper = DependencyManager::get(); - userInputMapper->removeDevice(spacemousedevice.getDeviceID()); - spacemousedevice.setDeviceID(0); + userInputMapper->removeDevice(instance->getDeviceID()); + instance->setDeviceID(controller::Input::INVALID_DEVICE); } } } void DeviceAddedHandler(unsigned int connection) { - SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); - if (spacemousedevice.getDeviceID() == controller::Input::INVALID_DEVICE) { + //SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); + if (instance->getDeviceID() == controller::Input::INVALID_DEVICE) { qCWarning(interfaceapp) << "Spacemouse device added "; auto userInputMapper = DependencyManager::get(); - userInputMapper->registerDevice(&spacemousedevice); + userInputMapper->registerDevice(instance); UserActivityLogger::getInstance().connectedDevice("controller", "Spacemouse"); } } void DeviceRemovedHandler(unsigned int connection) { - SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); - if (spacemousedevice.getDeviceID() != controller::Input::INVALID_DEVICE) { + //SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); + if (instance->getDeviceID() != controller::Input::INVALID_DEVICE) { qCWarning(interfaceapp) << "Spacemouse device removed"; auto userInputMapper = DependencyManager::get(); - userInputMapper->removeDevice(spacemousedevice.getDeviceID()); - spacemousedevice.setDeviceID(controller::Input::INVALID_DEVICE); + userInputMapper->removeDevice(instance->getDeviceID()); + instance->setDeviceID(controller::Input::INVALID_DEVICE); } } diff --git a/libraries/input-plugins/src/input-plugins/SpacemouseManager.h b/libraries/input-plugins/src/input-plugins/SpacemouseManager.h index 5379af9991..0d6556d059 100644 --- a/libraries/input-plugins/src/input-plugins/SpacemouseManager.h +++ b/libraries/input-plugins/src/input-plugins/SpacemouseManager.h @@ -11,6 +11,8 @@ #ifndef hifi_SpacemouseManager_h #define hifi_SpacemouseManager_h +#define HAVE_3DCONNEXIONCLIENT + #include #include #include @@ -19,7 +21,7 @@ #include "InputPlugin.h" -#ifndef HAVE_SPACEMOUSE +#ifndef HAVE_3DCONNEXIONCLIENT class SpacemouseManager : public QObject { Q_OBJECT public: @@ -29,11 +31,11 @@ public: void destroy() {}; bool Is3dmouseAttached() { return false; }; public slots: - void toggleConnexion(bool shouldEnable) {}; + void toggleSpacemouse(bool shouldEnable) {}; }; #endif -#ifdef HAVE_SPACEMOUSE +#ifdef HAVE_3DCONNEXIONCLIENT // the windows connexion rawinput #ifdef Q_OS_WIN From ade0862948ae8d010d8450b6d4056716348e388d Mon Sep 17 00:00:00 2001 From: EdgarPironti Date: Wed, 4 Nov 2015 00:49:40 -0800 Subject: [PATCH 10/29] Spacemouse fixes --- .../controllers/Spacemouse/spacemouseExample.js | 8 ++++---- interface/resources/controllers/spacemouse.json | 4 ++-- .../src/input-plugins/SpacemouseManager.cpp | 14 +++----------- .../src/input-plugins/SpacemouseManager.h | 9 ++------- 4 files changed, 11 insertions(+), 24 deletions(-) diff --git a/examples/controllers/Spacemouse/spacemouseExample.js b/examples/controllers/Spacemouse/spacemouseExample.js index 46ccd80fa7..92e89055b7 100644 --- a/examples/controllers/Spacemouse/spacemouseExample.js +++ b/examples/controllers/Spacemouse/spacemouseExample.js @@ -45,9 +45,9 @@ function update(deltaTime) { print("- Controller RZ: " + Controller.getValue(Controller.Standard.LX)); } - if(Controller.getValue(Controller.Standard.LT) != 0){ + if(Controller.getValue(Controller.Standard.LB) != 0){ toggleFirstMove(); - print("- Controller LEFTB: " + Controller.getValue(Controller.Standard.LT)); + print("- Controller LEFTB: " + Controller.getValue(Controller.Standard.LB)); } if(Controller.getValue(Controller.Standard.RY) != 0){ @@ -60,9 +60,9 @@ function update(deltaTime) { print("- Controller TX: " + Controller.getValue(Controller.Standard.RX)); } - if(Controller.getValue(Controller.Standard.RT) != 0){ + if(Controller.getValue(Controller.Standard.RB) != 0){ toggleFirstMove(); - print("- Controller RIGHTB: " + Controller.getValue(Controller.Standard.RT)); + print("- Controller RIGHTB: " + Controller.getValue(Controller.Standard.RB)); } firstmove = 1; diff --git a/interface/resources/controllers/spacemouse.json b/interface/resources/controllers/spacemouse.json index e02d0d4101..adcfef71a6 100644 --- a/interface/resources/controllers/spacemouse.json +++ b/interface/resources/controllers/spacemouse.json @@ -8,8 +8,8 @@ { "from": "Spacemouse.RotateZ", "to": "Standard.LX" }, - { "from": "Spacemouse.LeftButton", "to": "Standard.LT" }, - { "from": "Spacemouse.RightButton", "to": "Standard.RT" } + { "from": "Spacemouse.LeftButton", "to": "Standard.LB" }, + { "from": "Spacemouse.RightButton", "to": "Standard.RB" } ] } diff --git a/libraries/input-plugins/src/input-plugins/SpacemouseManager.cpp b/libraries/input-plugins/src/input-plugins/SpacemouseManager.cpp index 3f68be8039..9c1307a18e 100644 --- a/libraries/input-plugins/src/input-plugins/SpacemouseManager.cpp +++ b/libraries/input-plugins/src/input-plugins/SpacemouseManager.cpp @@ -21,7 +21,7 @@ const float MAX_AXIS = 75.0f; // max forward = 2x speed -static std::shared_ptr instance = NULL; +static std::shared_ptr instance; SpacemouseDevice::SpacemouseDevice() : InputDevice("Spacemouse") { @@ -120,9 +120,9 @@ void SpacemouseDevice::update(float deltaTime, bool jointsCaptured) { SpacemouseManager& SpacemouseManager::getInstance() { static SpacemouseManager sharedInstance; - if (instance == NULL){ + if (instance == nullptr) { new SpacemouseDevice(); - } + } return sharedInstance; } @@ -318,14 +318,12 @@ void SpacemouseManager::Move3d(HANDLE device, std::vector& motionData) { //Called when a 3D mouse key is pressed void SpacemouseManager::On3dmouseKeyDown(HANDLE device, int virtualKeyCode) { Q_UNUSED(device); - //SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); instance->setButton(virtualKeyCode); } //Called when a 3D mouse key is released void SpacemouseManager::On3dmouseKeyUp(HANDLE device, int virtualKeyCode) { Q_UNUSED(device); - //SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); instance->setButton(0); } @@ -858,8 +856,6 @@ void SpacemouseManager::init() { // ...or use this to take over system-wide fConnexionClientID = RegisterConnexionClient(kConnexionClientWildcard, NULL, kConnexionClientModeTakeOver, kConnexionMaskAll); - //SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); - //memcpy(&spacemousedevice.clientId, &fConnexionClientID, (long)sizeof(int)); memcpy(&instance->clientId, &fConnexionClientID, (long)sizeof(int)); // A separate API call is required to capture buttons beyond the first 8 @@ -887,7 +883,6 @@ void SpacemouseManager::destroy() { } CleanupConnexionHandlers(); fConnexionClientID = 0; - //SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); if (instance->getDeviceID() != controller::Input::INVALID_DEVICE) { auto userInputMapper = DependencyManager::get(); userInputMapper->removeDevice(instance->getDeviceID()); @@ -897,7 +892,6 @@ void SpacemouseManager::destroy() { } void DeviceAddedHandler(unsigned int connection) { - //SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); if (instance->getDeviceID() == controller::Input::INVALID_DEVICE) { qCWarning(interfaceapp) << "Spacemouse device added "; auto userInputMapper = DependencyManager::get(); @@ -907,7 +901,6 @@ void DeviceAddedHandler(unsigned int connection) { } void DeviceRemovedHandler(unsigned int connection) { - //SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); if (instance->getDeviceID() != controller::Input::INVALID_DEVICE) { qCWarning(interfaceapp) << "Spacemouse device removed"; auto userInputMapper = DependencyManager::get(); @@ -934,7 +927,6 @@ void MessageHandler(unsigned int connection, unsigned int messageType, void *mes case kConnexionMsgDeviceState: state = (SpacemouseDeviceState*)messageArgument; if (state->client == fConnexionClientID) { - //SpacemouseDevice& spacemousedevice = SpacemouseDevice::getInstance(); instance->cc_position = { state->axis[0], state->axis[1], state->axis[2] }; instance->cc_rotation = { state->axis[3], state->axis[4], state->axis[5] }; diff --git a/libraries/input-plugins/src/input-plugins/SpacemouseManager.h b/libraries/input-plugins/src/input-plugins/SpacemouseManager.h index 0d6556d059..26e0155825 100644 --- a/libraries/input-plugins/src/input-plugins/SpacemouseManager.h +++ b/libraries/input-plugins/src/input-plugins/SpacemouseManager.h @@ -89,8 +89,7 @@ private: }; class SpacemouseManager : public QObject, public QAbstractNativeEventFilter { -//class SpacemouseManager : public InputPlugin, public controller::InputDevice { - + Q_OBJECT public: SpacemouseManager() {}; @@ -118,10 +117,7 @@ public: } public slots: - void toggleSpacemouse(bool shouldEnable); - - //std::shared_ptr getDevice(); - + void toggleSpacemouse(bool shouldEnable); signals: void Move3d(std::vector& motionData); @@ -193,7 +189,6 @@ class SpacemouseDevice : public QObject, public controller::InputDevice { Q_OBJECT public: - //static SpacemouseDevice& getInstance(); SpacemouseDevice(); enum PositionChannel { TRANSLATE_X, From fe12891f61dfa2ecefe1a3e1281a7bfeb1be7f36 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Wed, 4 Nov 2015 10:48:02 -0800 Subject: [PATCH 11/29] whitespace only --- examples/away.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/away.js b/examples/away.js index dba26e0697..eb841a07f8 100644 --- a/examples/away.js +++ b/examples/away.js @@ -31,8 +31,8 @@ function playAwayAnimation() { return {isAway: true, isNotAway: false, isNotMoving: false, ikOverlayAlpha: 0.0}; } if (stopper) { - Script.clearTimeout(stopper); - MyAvatar.removeAnimationStateHandler(activeAnimationHandlerId); // do it now, before making new assignment + Script.clearTimeout(stopper); + MyAvatar.removeAnimationStateHandler(activeAnimationHandlerId); // do it now, before making new assignment } awayAnimationHandlerId = MyAvatar.addAnimationStateHandler(animateAway, null); } @@ -47,16 +47,16 @@ function stopAwayAnimation() { // So... Just give us a fixed amount of time to be done with animation, before we turn ik back on. var backToNormal = false; stopper = Script.setTimeout(function () { - backToNormal = true; - stopper = false; + backToNormal = true; + stopper = false; }, IK_WINDOW_AFTER_GOING_ACTIVE); function animateActive(state) { - if (state.ikOverlayAlpha) { - // Once the right state gets reflected back to us, we don't need the hander any more. - // But we are locked against handler changes during the execution of a handler, so remove asynchronously. - Script.setTimeout(function () { MyAvatar.removeAnimationStateHandler(activeAnimationHandlerId); }, 0); - } - // It might be cool to "come back to life" by fading the ik overlay back in over a short time. But let's see how this goes. + if (state.ikOverlayAlpha) { + // Once the right state gets reflected back to us, we don't need the hander any more. + // But we are locked against handler changes during the execution of a handler, so remove asynchronously. + Script.setTimeout(function () { MyAvatar.removeAnimationStateHandler(activeAnimationHandlerId); }, 0); + } + // It might be cool to "come back to life" by fading the ik overlay back in over a short time. But let's see how this goes. return {isAway: false, isNotAway: true, ikOverlayAlpha: backToNormal ? 1.0 : 0.0}; // IWBNI we had a way of deleting an anim var. } activeAnimationHandlerId = MyAvatar.addAnimationStateHandler(animateActive, ['isAway', 'isNotAway', 'isNotMoving', 'ikOverlayAlpha']); From 883f9c09bf9c4e917dd4f35fe0be339c6ca2eb73 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Wed, 4 Nov 2015 10:49:12 -0800 Subject: [PATCH 12/29] add gratuitous whitespace --- examples/away.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/away.js b/examples/away.js index eb841a07f8..5cefd0d609 100644 --- a/examples/away.js +++ b/examples/away.js @@ -38,7 +38,10 @@ function playAwayAnimation() { } function stopAwayAnimation() { MyAvatar.removeAnimationStateHandler(awayAnimationHandlerId); - if (stopper) { print('WARNING: unexpected double stop'); return; } + if (stopper) { + print('WARNING: unexpected double stop'); + return; + } // How do we know when to turn ikOverlayAlpha back on? // It cannot be as soon as we want to stop the away animation, because then things will look goofy as we come out of that animation. // (Imagine an away animation that sits or kneels, and then stands back up when coming out of it. If head is at the HMD, then it won't From 3fdd7ca470d9aae563c5752ea65796063684a44f Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Wed, 4 Nov 2015 10:57:03 -0800 Subject: [PATCH 13/29] obscure the code and increase the likelihood of future whitespace-only diffs --- examples/away.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/away.js b/examples/away.js index 5cefd0d609..fa7925a545 100644 --- a/examples/away.js +++ b/examples/away.js @@ -98,16 +98,16 @@ function goActive(event) { if (event.text === '.') { goAway(event); } - return; + } else { + isAway = false; + print('going "active"'); + if (!wasMuted) { + AudioDevice.toggleMute(); + } + MyAvatar.setEnableMeshVisible(true); // IWBNI we respected Developer->Avatar->Draw Mesh setting. + stopAwayAnimation(); + hideOverlay(); } - isAway = false; - print('going "active"'); - if (!wasMuted) { - AudioDevice.toggleMute(); - } - MyAvatar.setEnableMeshVisible(true); // IWBNI we respected Developer->Avatar->Draw Mesh setting. - stopAwayAnimation(); - hideOverlay(); } Controller.keyPressEvent.connect(goActive); Script.scriptEnding.connect(goActive); From 4fd2027fb4400af3eacaeeaa57987d74307ee0a5 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Wed, 4 Nov 2015 11:42:21 -0800 Subject: [PATCH 14/29] change name --- examples/away.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/away.js b/examples/away.js index fa7925a545..516365218c 100644 --- a/examples/away.js +++ b/examples/away.js @@ -93,7 +93,7 @@ function goAway(event) { playAwayAnimation(); // animation is still seen by others showOverlay(); } -function goActive(event) { +function switchActiveState(event) { if (!isAway || event.isAutoRepeat) { if (event.text === '.') { goAway(event); @@ -109,8 +109,8 @@ function goActive(event) { hideOverlay(); } } -Controller.keyPressEvent.connect(goActive); -Script.scriptEnding.connect(goActive); +Controller.keyPressEvent.connect(switchActiveState); +Script.scriptEnding.connect(switchActiveState); if (HMD.active) { goAway({}); // give a dummy event object } From 69f1cfbcb9125aa9d449a5d01b3734bcd51309e8 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 4 Nov 2015 12:04:34 -0800 Subject: [PATCH 15/29] Fixes for Mac build and crash on startup For some reason the qt code gen is getting confused by the #if 0 in 3DConnextionClient.h, so I added a stub implementation. In Application.cpp the change of moving idle into paintGL had a sideeffect of calling OffscreenGlCanvas before it was initialized. To work around this I added a guard to prevent calling idle before all the gl windows/widgets have been initialized. --- interface/src/Application.cpp | 12 ++++++------ interface/src/Application.h | 3 ++- interface/src/devices/3DConnexionClient.h | 15 +++++++++++++++ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d31d9de4a0..556664ec10 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -940,14 +940,12 @@ void Application::initializeGL() { qCDebug(interfaceapp) << "Created Display Window."; // initialize glut for shape drawing; Qt apparently initializes it on OS X - #ifndef __APPLE__ - static bool isInitialized = false; - if (isInitialized) { + if (_isGLInitialized) { return; } else { - isInitialized = true; + _isGLInitialized = true; } - #endif + // Where the gpuContext is initialized and where the TRUE Backend is created and assigned gpu::Context::init(); _gpuContext = std::make_shared(); @@ -1059,7 +1057,9 @@ void Application::paintGL() { _lastFramesPerSecondUpdate = now; } - idle(now); + if (_isGLInitialized) { + idle(now); + } PROFILE_RANGE(__FUNCTION__); PerformanceTimer perfTimer("paintGL"); diff --git a/interface/src/Application.h b/interface/src/Application.h index 212687c11e..5a5d5a015c 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -414,7 +414,7 @@ private: bool _dependencyManagerIsSetup; - OffscreenGlCanvas* _offscreenContext; + OffscreenGlCanvas* _offscreenContext {nullptr}; DisplayPluginPointer _displayPlugin; InputPluginList _activeInputPlugins; @@ -548,6 +548,7 @@ private: quint64 _lastSimsPerSecondUpdate = 0; bool _isForeground = true; // starts out assumed to be in foreground bool _inPaint = false; + bool _isGLInitialized {false}; }; #endif // hifi_Application_h diff --git a/interface/src/devices/3DConnexionClient.h b/interface/src/devices/3DConnexionClient.h index 03a43d4c64..b6fa6a37c3 100755 --- a/interface/src/devices/3DConnexionClient.h +++ b/interface/src/devices/3DConnexionClient.h @@ -220,4 +220,19 @@ public: #endif +#include +#include + +// stub +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 // defined(hifi_3DConnexionClient_h) From 6cfc0b9487bf820f7b2210243b9d0ca3ebd89d5c Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 4 Nov 2015 13:07:38 -0800 Subject: [PATCH 16/29] update openssl binaries link --- BUILD.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD.md b/BUILD.md index 72dfa5725e..5abb3ae4e7 100644 --- a/BUILD.md +++ b/BUILD.md @@ -2,7 +2,7 @@ * [cmake](http://www.cmake.org/cmake/resources/software.html) ~> 2.8.12.2 * [Qt](http://www.qt.io/download-open-source) ~> 5.4.1 -* [OpenSSL](https://www.openssl.org/related/binaries.html) ~> 1.0.1m +* [OpenSSL](https://www.openssl.org/community/binaries.html) ~> 1.0.1m * IMPORTANT: Using the recommended version of OpenSSL is critical to avoid security vulnerabilities. * [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional) From 4dec31d524a2d835f05e54111785bca47e08de91 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 4 Nov 2015 13:20:47 -0800 Subject: [PATCH 17/29] Fix crash in Oculus simulator --- plugins/oculus/src/OculusDebugDisplayPlugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/oculus/src/OculusDebugDisplayPlugin.cpp b/plugins/oculus/src/OculusDebugDisplayPlugin.cpp index 2021ce1c5a..7a8b355ddd 100644 --- a/plugins/oculus/src/OculusDebugDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDebugDisplayPlugin.cpp @@ -25,7 +25,7 @@ bool OculusDebugDisplayPlugin::isSupported() const { } void OculusDebugDisplayPlugin::customizeContext() { - WindowOpenGLDisplayPlugin::customizeContext(); + OculusBaseDisplayPlugin::customizeContext(); enableVsync(false); } From d46d521d81e65b62a47b13740cd94a8438a6e020 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 4 Nov 2015 15:10:23 -0800 Subject: [PATCH 18/29] Added #else branch to #if 0 --- interface/src/devices/3DConnexionClient.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/devices/3DConnexionClient.h b/interface/src/devices/3DConnexionClient.h index b6fa6a37c3..7435739bca 100755 --- a/interface/src/devices/3DConnexionClient.h +++ b/interface/src/devices/3DConnexionClient.h @@ -218,7 +218,7 @@ public: void handleAxisEvent(); }; -#endif +#else // #if 0 #include #include @@ -235,4 +235,6 @@ public slots: void toggleConnexion(bool shouldEnable) {}; }; +#endif + #endif // defined(hifi_3DConnexionClient_h) From 20d1035821b83b5d4d29bbf3ca94d4db09a15498 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 4 Nov 2015 15:50:21 -0800 Subject: [PATCH 19/29] Fixing step yaw to move by consistent amounts, be 'tappable' --- .../resources/controllers/keyboardMouse.json | 35 +++++++++++++++---- interface/src/Application.cpp | 2 +- .../controllers/impl/filters/PulseFilter.cpp | 15 ++++++-- .../controllers/impl/filters/PulseFilter.h | 7 ++-- 4 files changed, 45 insertions(+), 14 deletions(-) diff --git a/interface/resources/controllers/keyboardMouse.json b/interface/resources/controllers/keyboardMouse.json index f99472b0e9..4a68ca0d20 100644 --- a/interface/resources/controllers/keyboardMouse.json +++ b/interface/resources/controllers/keyboardMouse.json @@ -12,28 +12,49 @@ { "from": "Keyboard.W", "when": "Keyboard.Shift", "to": "Actions.PITCH_UP" }, - { "from": { "makeAxis" : ["Keyboard.MouseMoveLeft", "Keyboard.MouseMoveRight"] }, + { "comment" : "Mouse turn need to be small continuous increments", + "from": { "makeAxis" : [ + [ "Keyboard.MouseMoveLeft" ], + [ "Keyboard.MouseMoveRight" ] + ] + }, "when": [ "Application.InHMD", "Application.ComfortMode", "Keyboard.RightMouseButton" ], "to": "Actions.StepYaw", "filters": [ "constrainToInteger", - { "type": "pulse", "interval": 0.5 }, - { "type": "scale", "scale": 15 } + { "type": "pulse", "interval": 0.2 }, + { "type": "scale", "scale": 22.5 } + ] + }, + + { "comment" : "Touchpad turn need to be small continuous increments, but without the RMB constraint", + "from": { "makeAxis" : [ + [ "Keyboard.TouchpadLeft" ], + [ "Keyboard.TouchpadRight" ] + ] + }, + "when": [ "Application.InHMD", "Application.ComfortMode" ], + "to": "Actions.StepYaw", + "filters": + [ + "constrainToInteger", + { "type": "pulse", "interval": 0.2 }, + { "type": "scale", "scale": 22.5 } ] }, { "from": { "makeAxis" : [ - ["Keyboard.A", "Keyboard.Left", "Keyboard.TouchpadLeft"], - ["Keyboard.D", "Keyboard.Right", "Keyboard.TouchpadRight"] + ["Keyboard.A", "Keyboard.Left" ], + ["Keyboard.D", "Keyboard.Right"] ] }, "when": [ "Application.InHMD", "Application.ComfortMode" ], "to": "Actions.StepYaw", "filters": [ - { "type": "pulse", "interval": 0.5 }, - { "type": "scale", "scale": 15 } + { "type": "pulse", "interval": 0.5, "resetOnZero": true }, + { "type": "scale", "scale": 22.5 } ] }, diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d31d9de4a0..da92605cb8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2795,7 +2795,7 @@ void Application::update(float deltaTime) { float timeFactor = EXPECTED_FRAME_RATE * deltaTime; myAvatar->setDriveKeys(PITCH, -1.0f * userInputMapper->getActionState(controller::Action::PITCH) / timeFactor); myAvatar->setDriveKeys(YAW, -1.0f * userInputMapper->getActionState(controller::Action::YAW) / timeFactor); - myAvatar->setDriveKeys(STEP_YAW, -1.0f * userInputMapper->getActionState(controller::Action::STEP_YAW) / timeFactor); + myAvatar->setDriveKeys(STEP_YAW, -1.0f * userInputMapper->getActionState(controller::Action::STEP_YAW)); } } myAvatar->setDriveKeys(ZOOM, userInputMapper->getActionState(controller::Action::TRANSLATE_CAMERA_Z)); diff --git a/libraries/controllers/src/controllers/impl/filters/PulseFilter.cpp b/libraries/controllers/src/controllers/impl/filters/PulseFilter.cpp index f4e1f04791..6ef9d40802 100644 --- a/libraries/controllers/src/controllers/impl/filters/PulseFilter.cpp +++ b/libraries/controllers/src/controllers/impl/filters/PulseFilter.cpp @@ -13,7 +13,7 @@ using namespace controller; - +const float PulseFilter::DEFAULT_LAST_EMIT_TIME = -::std::numeric_limits::max(); float PulseFilter::apply(float value) const { float result = 0.0f; @@ -25,13 +25,22 @@ float PulseFilter::apply(float value) const { _lastEmitTime = now; result = value; } + } else if (_resetOnZero) { + _lastEmitTime = DEFAULT_LAST_EMIT_TIME; } return result; } bool PulseFilter::parseParameters(const QJsonValue& parameters) { - static const QString JSON_MIN = QStringLiteral("interval"); - return parseSingleFloatParameter(parameters, JSON_MIN, _interval); + static const QString JSON_INTERVAL = QStringLiteral("interval"); + static const QString JSON_RESET = QStringLiteral("resetOnZero"); + if (parameters.isObject()) { + auto obj = parameters.toObject(); + if (obj.contains(JSON_RESET)) { + _resetOnZero = obj[JSON_RESET].toBool(); + } + } + return parseSingleFloatParameter(parameters, JSON_INTERVAL, _interval); } diff --git a/libraries/controllers/src/controllers/impl/filters/PulseFilter.h b/libraries/controllers/src/controllers/impl/filters/PulseFilter.h index 2512b479cf..dbe2eba81b 100644 --- a/libraries/controllers/src/controllers/impl/filters/PulseFilter.h +++ b/libraries/controllers/src/controllers/impl/filters/PulseFilter.h @@ -21,14 +21,15 @@ public: PulseFilter() {} PulseFilter(float interval) : _interval(interval) {} - virtual float apply(float value) const override; virtual bool parseParameters(const QJsonValue& parameters); private: - mutable float _lastEmitTime { -::std::numeric_limits::max() }; - float _interval = 1.0f; + static const float DEFAULT_LAST_EMIT_TIME; + mutable float _lastEmitTime { DEFAULT_LAST_EMIT_TIME }; + bool _resetOnZero { false }; + float _interval { 1.0f }; }; } From 8d16f60b15ee192e07bfffa2bbc8b4c556e6b920 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 5 Nov 2015 09:02:39 -0800 Subject: [PATCH 20/29] Removed hardcoded define HAVE_3DCONNEXIONCLIENT This should be set from cmake, right? --- libraries/input-plugins/src/input-plugins/SpacemouseManager.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/input-plugins/src/input-plugins/SpacemouseManager.h b/libraries/input-plugins/src/input-plugins/SpacemouseManager.h index 01df038ccb..e444b73d9f 100644 --- a/libraries/input-plugins/src/input-plugins/SpacemouseManager.h +++ b/libraries/input-plugins/src/input-plugins/SpacemouseManager.h @@ -11,8 +11,6 @@ #ifndef hifi_SpacemouseManager_h #define hifi_SpacemouseManager_h -#define HAVE_3DCONNEXIONCLIENT - #include #include #include From 2318e48fa8dfce0e0ad2ecd1cf108693a57998f5 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 5 Nov 2015 09:43:41 -0800 Subject: [PATCH 21/29] AvatarRig: fix for crash when index was -1 --- libraries/animation/src/AvatarRig.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/animation/src/AvatarRig.cpp b/libraries/animation/src/AvatarRig.cpp index 4dbf5207b1..b72e15a0ce 100644 --- a/libraries/animation/src/AvatarRig.cpp +++ b/libraries/animation/src/AvatarRig.cpp @@ -13,7 +13,7 @@ /// Updates the state of the joint at the specified index. void AvatarRig::updateJointState(int index, glm::mat4 rootTransform) { - if (index < 0 && index >= _jointStates.size()) { + if (index < 0 || index >= _jointStates.size()) { return; // bail } JointState& state = _jointStates[index]; From 4a3b434fd48f7186988d4350e72fa8df92a65044 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 5 Nov 2015 10:35:02 -0800 Subject: [PATCH 22/29] change grabbing-non-colliding to trigger. fix whiteboard and some other scripts --- examples/controllers/handControllerGrab.js | 75 ++++++++++--------- .../whiteboard/colorSelectorEntityScript.js | 4 +- .../whiteboard/eraseBoardEntityScript.js | 4 +- .../whiteboard/whiteboardEntityScript.js | 8 +- .../painting/whiteboard/whiteboardSpawner.js | 5 +- examples/toybox/lights/lightSwitch.js | 7 +- unpublishedScripts/basketballsResetter.js | 4 +- unpublishedScripts/hiddenEntityReset.js | 4 +- unpublishedScripts/masterReset.js | 5 +- unpublishedScripts/targetsResetter.js | 4 +- 10 files changed, 66 insertions(+), 54 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index b0721de119..6ea08e5a43 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -101,10 +101,10 @@ var STATE_DISTANCE_HOLDING = 2; var STATE_CONTINUE_DISTANCE_HOLDING = 3; var STATE_NEAR_GRABBING = 4; var STATE_CONTINUE_NEAR_GRABBING = 5; -var STATE_NEAR_GRABBING_NON_COLLIDING = 6; -var STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING = 7; -var STATE_FAR_GRABBING_NON_COLLIDING = 8; -var STATE_CONTINUE_FAR_GRABBING_NON_COLLIDING = 9; +var STATE_NEAR_TRIGGER = 6; +var STATE_CONTINUE_NEAR_TRIGGER = 7; +var STATE_FAR_TRIGGER = 8; +var STATE_CONTINUE_FAR_TRIGGER = 9; var STATE_RELEASE = 10; @@ -122,14 +122,14 @@ function stateToName(state) { return "near_grabbing"; case STATE_CONTINUE_NEAR_GRABBING: return "continue_near_grabbing"; - case STATE_NEAR_GRABBING_NON_COLLIDING: - return "near_grabbing_non_colliding"; - case STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING: - return "continue_near_grabbing_non_colliding"; - case STATE_FAR_GRABBING_NON_COLLIDING: - return "far_grabbing_non_colliding"; - case STATE_CONTINUE_FAR_GRABBING_NON_COLLIDING: - return "continue_far_grabbing_non_colliding"; + case STATE_NEAR_TRIGGER: + return "near_trigger"; + case STATE_CONTINUE_NEAR_TRIGGER: + return "continue_near_trigger"; + case STATE_FAR_TRIGGER: + return "far_trigger"; + case STATE_CONTINUE_FAR_TRIGGER: + return "continue_far_trigger"; case STATE_RELEASE: return "release"; } @@ -212,17 +212,17 @@ function MyController(hand) { case STATE_CONTINUE_NEAR_GRABBING: this.continueNearGrabbing(); break; - case STATE_NEAR_GRABBING_NON_COLLIDING: - this.nearGrabbingNonColliding(); + case STATE_NEAR_TRIGGER: + this.nearTrigger(); break; - case STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING: - this.continueNearGrabbingNonColliding(); + case STATE_CONTINUE_NEAR_TRIGGER: + this.continueNearTrigger(); break; - case STATE_FAR_GRABBING_NON_COLLIDING: - this.farGrabbingNonColliding(); + case STATE_FAR_TRIGGER: + this.farTrigger(); break; - case STATE_CONTINUE_FAR_GRABBING_NON_COLLIDING: - this.continueFarGrabbingNonColliding(); + case STATE_CONTINUE_FAR_TRIGGER: + this.continueFarTrigger(); break; case STATE_RELEASE: this.release(); @@ -394,7 +394,7 @@ function MyController(hand) { // the hand is very close to the intersected object. go into close-grabbing mode. if (grabbableData.wantsTrigger) { this.grabbedEntity = intersection.entityID; - this.setState(STATE_NEAR_GRABBING_NON_COLLIDING); + this.setState(STATE_NEAR_TRIGGER); return; } else if (!intersection.properties.locked) { this.grabbedEntity = intersection.entityID; @@ -411,7 +411,7 @@ function MyController(hand) { return; } else if (grabbableData.wantsTrigger) { this.grabbedEntity = intersection.entityID; - this.setState(STATE_FAR_GRABBING_NON_COLLIDING); + this.setState(STATE_FAR_TRIGGER); return; } } @@ -483,7 +483,7 @@ function MyController(hand) { return; } if (grabbableData.wantsTrigger) { - this.setState(STATE_NEAR_GRABBING_NON_COLLIDING); + this.setState(STATE_NEAR_TRIGGER); return; } else if (!props.locked) { this.setState(STATE_NEAR_GRABBING); @@ -538,6 +538,7 @@ function MyController(hand) { this.continueDistanceHolding = function() { if (this.triggerSmoothedReleased()) { this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); return; } @@ -631,6 +632,7 @@ function MyController(hand) { if (this.triggerSmoothedReleased()) { this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); return; } @@ -698,6 +700,7 @@ function MyController(hand) { this.continueNearGrabbing = function() { if (this.triggerSmoothedReleased()) { this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); return; } @@ -733,9 +736,10 @@ function MyController(hand) { } }; - this.nearGrabbingNonColliding = function() { + this.nearTrigger = function() { if (this.triggerSmoothedReleased()) { this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); return; } if (this.hand === RIGHT_HAND) { @@ -743,13 +747,14 @@ function MyController(hand) { } else { Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); } - Entities.callEntityMethod(this.grabbedEntity, "startNearGrabNonColliding"); - this.setState(STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING); + Entities.callEntityMethod(this.grabbedEntity, "startNearTrigger"); + this.setState(STATE_CONTINUE_NEAR_TRIGGER); }; - this.farGrabbingNonColliding = function() { + this.farTrigger = function() { if (this.triggerSmoothedReleased()) { this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); return; } @@ -758,22 +763,24 @@ function MyController(hand) { } else { Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); } - Entities.callEntityMethod(this.grabbedEntity, "startFarGrabNonColliding"); - this.setState(STATE_CONTINUE_FAR_GRABBING_NON_COLLIDING); + Entities.callEntityMethod(this.grabbedEntity, "startFarTrigger"); + this.setState(STATE_CONTINUE_FAR_TRIGGER); }; - this.continueNearGrabbingNonColliding = function() { + this.continueNearTrigger = function() { if (this.triggerSmoothedReleased()) { this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); return; } - Entities.callEntityMethod(this.grabbedEntity, "continueNearGrabbingNonColliding"); + Entities.callEntityMethod(this.grabbedEntity, "continueNearTrigger"); }; - this.continueFarGrabbingNonColliding = function() { + this.continueFarTrigger = function() { if (this.triggerSmoothedReleased()) { this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); return; } @@ -789,12 +796,13 @@ function MyController(hand) { this.lastPickTime = now; if (intersection.entityID != this.grabbedEntity) { this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); return; } } this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); - Entities.callEntityMethod(this.grabbedEntity, "continueFarGrabbingNonColliding"); + Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); }; _this.allTouchedIDs = {}; @@ -876,7 +884,6 @@ function MyController(hand) { if (this.actionID !== null) { Entities.deleteAction(this.grabbedEntity, this.actionID); } - Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); } this.deactivateEntity(this.grabbedEntity); diff --git a/examples/painting/whiteboard/colorSelectorEntityScript.js b/examples/painting/whiteboard/colorSelectorEntityScript.js index f1105604c7..3c07527d02 100644 --- a/examples/painting/whiteboard/colorSelectorEntityScript.js +++ b/examples/painting/whiteboard/colorSelectorEntityScript.js @@ -20,7 +20,7 @@ ColorSelector.prototype = { - startFarGrabNonColliding: function() { + startFarTrigger: function() { this.selectColor(); }, @@ -46,4 +46,4 @@ // entity scripts always need to return a newly constructed object of our type return new ColorSelector(); -}); \ No newline at end of file +}); diff --git a/examples/painting/whiteboard/eraseBoardEntityScript.js b/examples/painting/whiteboard/eraseBoardEntityScript.js index 14679c625b..dd36242a6d 100644 --- a/examples/painting/whiteboard/eraseBoardEntityScript.js +++ b/examples/painting/whiteboard/eraseBoardEntityScript.js @@ -20,7 +20,7 @@ BoardEraser.prototype = { - startFarGrabNonColliding: function() { + startFarTrigger: function() { this.eraseBoard(); }, @@ -42,4 +42,4 @@ // entity scripts always need to return a newly constructed object of our type return new BoardEraser(); -}); \ No newline at end of file +}); diff --git a/examples/painting/whiteboard/whiteboardEntityScript.js b/examples/painting/whiteboard/whiteboardEntityScript.js index c10a8c23fe..d2b2c386ef 100644 --- a/examples/painting/whiteboard/whiteboardEntityScript.js +++ b/examples/painting/whiteboard/whiteboardEntityScript.js @@ -43,7 +43,7 @@ this.hand = LEFT_HAND; }, - startFarGrabNonColliding: function() { + startFarTrigger: function() { if (this.painting) { return; } @@ -62,7 +62,7 @@ }); }, - continueFarGrabbingNonColliding: function() { + continueFarTrigger: function() { var handPosition = this.getHandPosition(); var pickRay = { origin: handPosition, @@ -183,7 +183,7 @@ }, - releaseGrab: function() { + stopFarTrigger: function() { if(this.hand !== this.whichHand) { return; } @@ -249,4 +249,4 @@ // entity scripts always need to return a newly constructed object of our type return new Whiteboard(); -}); \ No newline at end of file +}); diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js index 701112e1a8..3411061074 100644 --- a/examples/painting/whiteboard/whiteboardSpawner.js +++ b/examples/painting/whiteboard/whiteboardSpawner.js @@ -74,6 +74,9 @@ var drawingSurface = Entities.addEntity({ userData: JSON.stringify({ color: { currentColor: colors[0] + }, + "grabbableKey": { + wantsTrigger:true } }) @@ -211,4 +214,4 @@ function cleanup() { // Uncomment this line to delete whiteboard and all associated entity on script close -// Script.scriptEnding.connect(cleanup); \ No newline at end of file +// Script.scriptEnding.connect(cleanup); diff --git a/examples/toybox/lights/lightSwitch.js b/examples/toybox/lights/lightSwitch.js index fbd314a9af..5d6497fccb 100644 --- a/examples/toybox/lights/lightSwitch.js +++ b/examples/toybox/lights/lightSwitch.js @@ -33,7 +33,7 @@ this.toggleLights(); }, - startNearGrabNonColliding: function () { + startNearTrigger: function () { this.toggleLights(); }, @@ -61,7 +61,8 @@ setEntityCustomData(this.resetKey, this.entityID, { on: on, type: lightType, - resetMe: true + resetMe: true, + grabbableKey: {wantsTrigger:true} }); }, @@ -89,4 +90,4 @@ // entity scripts always need to return a newly constructed object of our type return new LightSwitch(); -}); \ No newline at end of file +}); diff --git a/unpublishedScripts/basketballsResetter.js b/unpublishedScripts/basketballsResetter.js index 6335312d57..4d02296e8e 100644 --- a/unpublishedScripts/basketballsResetter.js +++ b/unpublishedScripts/basketballsResetter.js @@ -17,7 +17,7 @@ var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; Resetter.prototype = { - startNearGrabNonColliding: function() { + startNearTrigger: function() { this.resetObjects(); }, @@ -108,4 +108,4 @@ var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; }; return new Resetter(); -}); \ No newline at end of file +}); diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index f56c705ce4..d343c52497 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -39,7 +39,7 @@ }, - startNearGrabNonColliding: function() { + startNearTrigger: function() { this.triggerReset(); }, @@ -1259,4 +1259,4 @@ }; // entity scripts always need to return a newly constructed object of our type return new ResetSwitch(); -}); \ No newline at end of file +}); diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index b138db163d..364807f42f 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -247,7 +247,8 @@ MasterReset = function() { resetMe: true }, grabbableKey: { - grabbable: false + grabbable: false, + wantsTrigger:true } }) }); @@ -1237,4 +1238,4 @@ MasterReset = function() { Script.scriptEnding.connect(cleanup); } -}; \ No newline at end of file +}; diff --git a/unpublishedScripts/targetsResetter.js b/unpublishedScripts/targetsResetter.js index a522c19593..326c0ce1be 100644 --- a/unpublishedScripts/targetsResetter.js +++ b/unpublishedScripts/targetsResetter.js @@ -17,7 +17,7 @@ Resetter.prototype = { - startNearGrabNonColliding: function() { + startNearTrigger: function() { this.resetObjects(); }, @@ -125,4 +125,4 @@ }; return new Resetter(); -}); \ No newline at end of file +}); From c898d9a47483609d1fabe68367792291343082b6 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 5 Nov 2015 10:48:16 -0800 Subject: [PATCH 23/29] set wantstrigger correctly on lightswitch --- examples/toybox/lights/lightSwitch.js | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/examples/toybox/lights/lightSwitch.js b/examples/toybox/lights/lightSwitch.js index 5d6497fccb..6051b7c0ae 100644 --- a/examples/toybox/lights/lightSwitch.js +++ b/examples/toybox/lights/lightSwitch.js @@ -15,35 +15,35 @@ /*global LightSwitch */ -(function () { +(function() { var _this; var utilitiesScript = Script.resolvePath("../../libraries/utils.js"); Script.include(utilitiesScript); - LightSwitch = function () { + LightSwitch = function() { _this = this; this.switchSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/lamp_switch_2.wav"); }; LightSwitch.prototype = { - clickReleaseOnEntity: function (entityID, mouseEvent) { + clickReleaseOnEntity: function(entityID, mouseEvent) { if (!mouseEvent.isLeftButton) { return; } this.toggleLights(); }, - startNearTrigger: function () { + startNearTrigger: function() { this.toggleLights(); }, - toggleLights: function () { + toggleLights: function() { var lightData = getEntityCustomData(this.resetKey, this.entityID, {}); var on = !lightData.on; var lightType = lightData.type; var lights = Entities.findEntities(this.position, 20); - lights.forEach(function (light) { + lights.forEach(function(light) { var type = getEntityCustomData(_this.resetKey, light, {}).type; if (type === lightType && JSON.stringify(light) !== JSON.stringify(_this.entityID)) { Entities.editEntity(light, { @@ -61,12 +61,15 @@ setEntityCustomData(this.resetKey, this.entityID, { on: on, type: lightType, - resetMe: true, - grabbableKey: {wantsTrigger:true} + resetMe: true + }); + + setEntityCustomData('grabbableKey', this.entityID, { + wantsTrigger: true }); }, - flipSwitch: function () { + flipSwitch: function() { var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; var axis = { x: 0, @@ -80,7 +83,7 @@ rotation: rotation }); }, - preload: function (entityID) { + preload: function(entityID) { this.entityID = entityID; this.resetKey = "resetMe"; //The light switch is static, so just cache its position once @@ -90,4 +93,4 @@ // entity scripts always need to return a newly constructed object of our type return new LightSwitch(); -}); +}); \ No newline at end of file From 50e8f49f5241820f364e9beeb783ab6731d160af Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 5 Nov 2015 10:54:50 -0800 Subject: [PATCH 24/29] SpacemouseManager Moved stub init into cpp file. This should fix the windows build. For some reason the linker was having a problem resolving this. --- .../input-plugins/src/input-plugins/SpacemouseManager.cpp | 3 +++ libraries/input-plugins/src/input-plugins/SpacemouseManager.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/input-plugins/src/input-plugins/SpacemouseManager.cpp b/libraries/input-plugins/src/input-plugins/SpacemouseManager.cpp index 9c1307a18e..43e6ee48a8 100644 --- a/libraries/input-plugins/src/input-plugins/SpacemouseManager.cpp +++ b/libraries/input-plugins/src/input-plugins/SpacemouseManager.cpp @@ -130,6 +130,9 @@ void SpacemouseManager::ManagerFocusOutEvent() { instance->focusOutEvent(); } +void SpacemouseManager::init() { +} + #ifdef HAVE_3DCONNEXIONCLIENT #ifdef Q_OS_WIN diff --git a/libraries/input-plugins/src/input-plugins/SpacemouseManager.h b/libraries/input-plugins/src/input-plugins/SpacemouseManager.h index e444b73d9f..08ac954c94 100644 --- a/libraries/input-plugins/src/input-plugins/SpacemouseManager.h +++ b/libraries/input-plugins/src/input-plugins/SpacemouseManager.h @@ -25,7 +25,7 @@ class SpacemouseManager : public QObject { public: static SpacemouseManager& getInstance(); void ManagerFocusOutEvent(); - void init() {}; + void init(); void destroy() {}; bool Is3dmouseAttached() { return false; }; public slots: From 50370479e475fa1c3f54695a674e230f21c905e4 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 5 Nov 2015 11:03:32 -0800 Subject: [PATCH 25/29] Application.h: coding standard fixes --- interface/src/Application.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.h b/interface/src/Application.h index 5a5d5a015c..39e3879707 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -414,7 +414,7 @@ private: bool _dependencyManagerIsSetup; - OffscreenGlCanvas* _offscreenContext {nullptr}; + OffscreenGlCanvas* _offscreenContext { nullptr }; DisplayPluginPointer _displayPlugin; InputPluginList _activeInputPlugins; @@ -548,7 +548,7 @@ private: quint64 _lastSimsPerSecondUpdate = 0; bool _isForeground = true; // starts out assumed to be in foreground bool _inPaint = false; - bool _isGLInitialized {false}; + bool _isGLInitialized { false }; }; #endif // hifi_Application_h From 8f65ee87bcc77a6cbecb9b287a118086e9415695 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 5 Nov 2015 13:19:29 -0800 Subject: [PATCH 26/29] Clean up script, go away when putting HMD (not just on startup), and clear stopper properly. --- examples/away.js | 55 ++++++++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/examples/away.js b/examples/away.js index 516365218c..8cc3790200 100644 --- a/examples/away.js +++ b/examples/away.js @@ -32,6 +32,7 @@ function playAwayAnimation() { } if (stopper) { Script.clearTimeout(stopper); + stopper = false; MyAvatar.removeAnimationStateHandler(activeAnimationHandlerId); // do it now, before making new assignment } awayAnimationHandlerId = MyAvatar.addAnimationStateHandler(animateAway, null); @@ -79,8 +80,8 @@ hideOverlay(); // MAIN CONTROL var wasMuted, isAway; -function goAway(event) { - if (isAway || event.isAutoRepeat) { // isAutoRepeat is true when held down (or when Windows feels like it) +function goAway() { + if (isAway) { return; } isAway = true; @@ -93,24 +94,36 @@ function goAway(event) { playAwayAnimation(); // animation is still seen by others showOverlay(); } -function switchActiveState(event) { - if (!isAway || event.isAutoRepeat) { - if (event.text === '.') { - goAway(event); - } - } else { - isAway = false; - print('going "active"'); - if (!wasMuted) { - AudioDevice.toggleMute(); - } - MyAvatar.setEnableMeshVisible(true); // IWBNI we respected Developer->Avatar->Draw Mesh setting. - stopAwayAnimation(); - hideOverlay(); +function goActive() { + if (!isAway) { + return; } + isAway = false; + print('going "active"'); + if (!wasMuted) { + AudioDevice.toggleMute(); + } + MyAvatar.setEnableMeshVisible(true); // IWBNI we respected Developer->Avatar->Draw Mesh setting. + stopAwayAnimation(); + hideOverlay(); } -Controller.keyPressEvent.connect(switchActiveState); -Script.scriptEnding.connect(switchActiveState); -if (HMD.active) { - goAway({}); // give a dummy event object -} +Script.scriptEnding.connect(goActive); +Controller.keyPressEvent.connect(function (event) { + if (event.isAutoRepeat) { // isAutoRepeat is true when held down (or when Windows feels like it) + return; + } + if (!isAway && (event.text === '.')) { + goAway(); + } else { + goActive(); + } +}); +var wasHmdActive = false; +Script.update.connect(function () { + if (HMD.active !== wasHmdActive) { + wasHmdActive = !wasHmdActive; + if (wasHmdActive) { + goAway(); + } + } +}); From c4194f23597850945b68b81d3a17b729d49200b4 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 5 Nov 2015 13:26:23 -0800 Subject: [PATCH 27/29] don't try to grab polylines. set wantTrigger on various whiteboard parts --- examples/controllers/handControllerGrab.js | 4 ++++ examples/painting/whiteboard/whiteboardSpawner.js | 12 ++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 6ea08e5a43..5035f2e5a4 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -455,6 +455,10 @@ function MyController(hand) { continue; } + if (propsForCandidate.type == 'PolyLine') { + continue; + } + if (propsForCandidate.type == 'Zone') { continue; } diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js index 3411061074..53bb7158d5 100644 --- a/examples/painting/whiteboard/whiteboardSpawner.js +++ b/examples/painting/whiteboard/whiteboardSpawner.js @@ -75,8 +75,8 @@ var drawingSurface = Entities.addEntity({ color: { currentColor: colors[0] }, - "grabbableKey": { - wantsTrigger:true + grabbableKey: { + wantsTrigger: true } }) @@ -156,7 +156,10 @@ function setUp() { color: { currentColor: colors[0] }, - colorIndicator: colorIndicatorBox + colorIndicator: colorIndicatorBox, + grabbableKey: { + wantsTrigger: true + } }) }); @@ -189,7 +192,8 @@ function setUp() { script: scriptURL, userData: JSON.stringify({ whiteboard: drawingSurface, - colorIndicator: colorIndicatorBox + colorIndicator: colorIndicatorBox, + grabbableKey: {wantsTrigger: true} }) }); colorBoxes.push(colorBox); From f8de01a856c3e5e85da6e2e2a322b32669eec911 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 5 Nov 2015 14:14:49 -0800 Subject: [PATCH 28/29] Fixed bug where eraser wouldn't erase --- .../painting/whiteboard/whiteboardSpawner.js | 49 +++++++++++++++---- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js index 53bb7158d5..56ead143e4 100644 --- a/examples/painting/whiteboard/whiteboardSpawner.js +++ b/examples/painting/whiteboard/whiteboardSpawner.js @@ -87,12 +87,24 @@ var light = Entities.addEntity({ type: 'Light', name: 'whiteboard light', position: lightPosition, - dimensions: {x: 10, y: 10, z: 10}, + dimensions: { + x: 10, + y: 10, + z: 10 + }, intensity: 2, - color: {red: 255, green: 255, blue: 255} + color: { + red: 255, + green: 255, + blue: 255 + } }); -var eraserPosition = Vec3.sum(center, {x: 0, y: 2.05, z: 0 }); +var eraserPosition = Vec3.sum(center, { + x: 0, + y: 2.05, + z: 0 +}); eraserPosition = Vec3.sum(eraserPosition, Vec3.multiply(-0.1, rotation)); scriptURL = Script.resolvePath("eraseBoardEntityScript.js"); var eraser = Entities.addEntity({ @@ -103,7 +115,10 @@ var eraser = Entities.addEntity({ script: scriptURL, rotation: rotation, userData: JSON.stringify({ - whiteboard: drawingSurface + whiteboard: drawingSurface, + grabbableKey: { + wantsTrigger: true + } }) }); @@ -115,20 +130,32 @@ Script.setTimeout(function() { function setUp() { - var blockerPosition = Vec3.sum(center, {x: 0, y: -1, z: 0 }); + var blockerPosition = Vec3.sum(center, { + x: 0, + y: -1, + z: 0 + }); blockerPosition = Vec3.sum(blockerPosition, Vec3.multiply(-1, Quat.getFront(rotation))); blocker = Entities.addEntity({ type: "Box", rotation: rotation, position: blockerPosition, - dimensions: {x: whiteboardDimensions.x, y: 1, z: 0.1}, + dimensions: { + x: whiteboardDimensions.x, + y: 1, + z: 0.1 + }, shapeType: "box", visible: false }); var eraseModelDimensions = Entities.getEntityProperties(eraser, "naturalDimensions").naturalDimensions; - Entities.editEntity(eraser, {dimensions: eraseModelDimensions}); - Entities.editEntity(colorIndicatorBorder, {dimensions: colorIndicatorBorderDimensions}); + Entities.editEntity(eraser, { + dimensions: eraseModelDimensions + }); + Entities.editEntity(colorIndicatorBorder, { + dimensions: colorIndicatorBorderDimensions + }); scriptURL = Script.resolvePath("colorIndicatorEntityScript.js"); var colorIndicatorPosition = Vec3.sum(center, { @@ -193,7 +220,9 @@ function setUp() { userData: JSON.stringify({ whiteboard: drawingSurface, colorIndicator: colorIndicatorBox, - grabbableKey: {wantsTrigger: true} + grabbableKey: { + wantsTrigger: true + } }) }); colorBoxes.push(colorBox); @@ -218,4 +247,4 @@ function cleanup() { // Uncomment this line to delete whiteboard and all associated entity on script close -// Script.scriptEnding.connect(cleanup); +// Script.scriptEnding.connect(cleanup); \ No newline at end of file From aa1289bd7c0760bbc8219b599ba2a59b34edcb61 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 5 Nov 2015 15:53:46 -0800 Subject: [PATCH 29/29] Update agent's outgoing avatar data packet with sequenceNumber as is now used in interface's MyAvatar. --- assignment-client/src/Agent.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index d9109703cb..063bf24de8 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -267,7 +267,10 @@ void Agent::processAgentAvatarAndAudio(float deltaTime) { QByteArray avatarByteArray = _avatarData->toByteArray(true, randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO); _avatarData->doneEncoding(true); - auto avatarPacket = NLPacket::create(PacketType::AvatarData, avatarByteArray.size()); + + static AvatarDataSequenceNumber sequenceNumber = 0; + auto avatarPacket = NLPacket::create(PacketType::AvatarData, avatarByteArray.size() + sizeof(sequenceNumber)); + avatarPacket->writePrimitive(sequenceNumber++); avatarPacket->write(avatarByteArray);