From c9b296693c793bcb5d2feea4b3b18c38a336bf95 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Sun, 3 May 2015 15:45:19 -0700 Subject: [PATCH 1/9] bringing the UserInputMapper to the application --- interface/src/Application.cpp | 101 +++++-- interface/src/Application.h | 5 + interface/src/ui/UserInputMapper.cpp | 348 +++++++++++++++++++++++ interface/src/ui/UserInputMapper.h | 263 +++++++++++++++++ libraries/script-engine/src/TouchEvent.h | 1 + 5 files changed, 690 insertions(+), 28 deletions(-) create mode 100755 interface/src/ui/UserInputMapper.cpp create mode 100755 interface/src/ui/UserInputMapper.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bfda9629a0..be92b59343 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -547,6 +547,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : connect(&_myAvatar->getSkeletonModel(), &SkeletonModel::skeletonLoaded, this, &Application::checkSkeleton, Qt::QueuedConnection); + // Setup the userInputMapper with the actions + _userInputMapper.assignDefaulActionUnitScales(); + // Setup the keyboardMouseDevice and the user input mapper with the default bindings + _keyboardMouseDevice.registerToUserInputMapper(_userInputMapper); + _keyboardMouseDevice.assignDefaultInputMapping(_userInputMapper); + // check first run... if (_firstRun.get()) { qCDebug(interfaceapp) << "This is a first run..."; @@ -1087,6 +1093,8 @@ void Application::keyPressEvent(QKeyEvent* event) { } if (activeWindow() == _window) { + _keyboardMouseDevice.keyPressEvent(event); + bool isShifted = event->modifiers().testFlag(Qt::ShiftModifier); bool isMeta = event->modifiers().testFlag(Qt::ControlModifier); bool isOption = event->modifiers().testFlag(Qt::AltModifier); @@ -1109,7 +1117,7 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_E: case Qt::Key_PageUp: - _myAvatar->setDriveKeys(UP, 1.0f); + // _myAvatar->setDriveKeys(UP, 1.0f); break; case Qt::Key_F: { @@ -1123,14 +1131,14 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_C: case Qt::Key_PageDown: - _myAvatar->setDriveKeys(DOWN, 1.0f); + // _myAvatar->setDriveKeys(DOWN, 1.0f); break; case Qt::Key_W: if (isOption && !isShifted && !isMeta) { Menu::getInstance()->triggerOption(MenuOption::Wireframe); } else { - _myAvatar->setDriveKeys(FWD, 1.0f); + // _myAvatar->setDriveKeys(FWD, 1.0f); } break; @@ -1142,7 +1150,7 @@ void Application::keyPressEvent(QKeyEvent* event) { } else if (!isOption && !isShifted && isMeta) { takeSnapshot(); } else { - _myAvatar->setDriveKeys(BACK, 1.0f); + // _myAvatar->setDriveKeys(BACK, 1.0f); } break; @@ -1154,13 +1162,13 @@ void Application::keyPressEvent(QKeyEvent* event) { if (isShifted) { Menu::getInstance()->triggerOption(MenuOption::Atmosphere); } else if (!isMeta) { - _myAvatar->setDriveKeys(ROT_LEFT, 1.0f); + // _myAvatar->setDriveKeys(ROT_LEFT, 1.0f); } break; case Qt::Key_D: if (!isMeta) { - _myAvatar->setDriveKeys(ROT_RIGHT, 1.0f); + // _myAvatar->setDriveKeys(ROT_RIGHT, 1.0f); } break; @@ -1176,7 +1184,7 @@ void Application::keyPressEvent(QKeyEvent* event) { _raiseMirror += 0.05f; } } else { - _myAvatar->setDriveKeys(isShifted ? UP : FWD, 1.0f); + // _myAvatar->setDriveKeys(isShifted ? UP : FWD, 1.0f); } break; @@ -1188,7 +1196,7 @@ void Application::keyPressEvent(QKeyEvent* event) { _raiseMirror -= 0.05f; } } else { - _myAvatar->setDriveKeys(isShifted ? DOWN : BACK, 1.0f); + // _myAvatar->setDriveKeys(isShifted ? DOWN : BACK, 1.0f); } break; @@ -1196,7 +1204,7 @@ void Application::keyPressEvent(QKeyEvent* event) { if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { _rotateMirror += PI / 20.0f; } else { - _myAvatar->setDriveKeys(isShifted ? LEFT : ROT_LEFT, 1.0f); + // _myAvatar->setDriveKeys(isShifted ? LEFT : ROT_LEFT, 1.0f); } break; @@ -1204,7 +1212,7 @@ void Application::keyPressEvent(QKeyEvent* event) { if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { _rotateMirror -= PI / 20.0f; } else { - _myAvatar->setDriveKeys(isShifted ? RIGHT : ROT_RIGHT, 1.0f); + // _myAvatar->setDriveKeys(isShifted ? RIGHT : ROT_RIGHT, 1.0f); } break; @@ -1341,64 +1349,65 @@ void Application::keyReleaseEvent(QKeyEvent* event) { _keysPressed.remove(event->key()); _controllerScriptingInterface.emitKeyReleaseEvent(event); // send events to any registered scripts - + // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface.isKeyCaptured(event)) { return; } + _keyboardMouseDevice.keyReleaseEvent(event); switch (event->key()) { case Qt::Key_E: case Qt::Key_PageUp: - _myAvatar->setDriveKeys(UP, 0.0f); + // _myAvatar->setDriveKeys(UP, 0.0f); break; case Qt::Key_C: case Qt::Key_PageDown: - _myAvatar->setDriveKeys(DOWN, 0.0f); + // _myAvatar->setDriveKeys(DOWN, 0.0f); break; case Qt::Key_W: - _myAvatar->setDriveKeys(FWD, 0.0f); + // _myAvatar->setDriveKeys(FWD, 0.0f); break; case Qt::Key_S: - _myAvatar->setDriveKeys(BACK, 0.0f); + // _myAvatar->setDriveKeys(BACK, 0.0f); break; case Qt::Key_A: - _myAvatar->setDriveKeys(ROT_LEFT, 0.0f); + // _myAvatar->setDriveKeys(ROT_LEFT, 0.0f); break; case Qt::Key_D: - _myAvatar->setDriveKeys(ROT_RIGHT, 0.0f); + // _myAvatar->setDriveKeys(ROT_RIGHT, 0.0f); break; case Qt::Key_Up: - _myAvatar->setDriveKeys(FWD, 0.0f); - _myAvatar->setDriveKeys(UP, 0.0f); + // _myAvatar->setDriveKeys(FWD, 0.0f); + // _myAvatar->setDriveKeys(UP, 0.0f); break; case Qt::Key_Down: - _myAvatar->setDriveKeys(BACK, 0.0f); - _myAvatar->setDriveKeys(DOWN, 0.0f); + // _myAvatar->setDriveKeys(BACK, 0.0f); + // _myAvatar->setDriveKeys(DOWN, 0.0f); break; case Qt::Key_Left: - _myAvatar->setDriveKeys(LEFT, 0.0f); - _myAvatar->setDriveKeys(ROT_LEFT, 0.0f); + // _myAvatar->setDriveKeys(LEFT, 0.0f); + // _myAvatar->setDriveKeys(ROT_LEFT, 0.0f); break; case Qt::Key_Right: - _myAvatar->setDriveKeys(RIGHT, 0.0f); - _myAvatar->setDriveKeys(ROT_RIGHT, 0.0f); + // _myAvatar->setDriveKeys(RIGHT, 0.0f); + // _myAvatar->setDriveKeys(ROT_RIGHT, 0.0f); break; case Qt::Key_Control: case Qt::Key_Shift: case Qt::Key_Meta: case Qt::Key_Alt: - _myAvatar->clearDriveKeys(); + // _myAvatar->clearDriveKeys(); break; case Qt::Key_Space: { if (!event->isAutoRepeat()) { @@ -1463,6 +1472,8 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { if (_controllerScriptingInterface.isMouseCaptured()) { return; } + + _keyboardMouseDevice.mouseMoveEvent(event, deviceID); } @@ -1483,7 +1494,10 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { if (activeWindow() == _window) { - if (event->button() == Qt::LeftButton) { + + _keyboardMouseDevice.mousePressEvent(event); + + if (event->button() == Qt::LeftButton) { _mouseDragStartedX = getTrueMouseX(); _mouseDragStartedY = getTrueMouseY(); _mousePressed = true; @@ -1524,7 +1538,10 @@ void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { return; } + _keyboardMouseDevice.mousePressEvent(event); + if (activeWindow() == _window) { + if (event->button() == Qt::LeftButton) { _mousePressed = false; @@ -1545,6 +1562,7 @@ void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { void Application::touchUpdateEvent(QTouchEvent* event) { _altPressed = false; + if (event->type() == QEvent::TouchUpdate) { TouchEvent thisEvent(*event, _lastTouchEvent); _controllerScriptingInterface.emitTouchUpdateEvent(thisEvent); // send events to any registered scripts @@ -1556,6 +1574,8 @@ void Application::touchUpdateEvent(QTouchEvent* event) { return; } + _keyboardMouseDevice.touchUpdateEvent(event); + bool validTouch = false; if (activeWindow() == _window) { const QList& tPoints = event->touchPoints(); @@ -1592,6 +1612,8 @@ void Application::touchBeginEvent(QTouchEvent* event) { return; } + _keyboardMouseDevice.touchBeginEvent(event); + } void Application::touchEndEvent(QTouchEvent* event) { @@ -1604,6 +1626,9 @@ void Application::touchEndEvent(QTouchEvent* event) { if (_controllerScriptingInterface.isTouchCaptured()) { return; } + + _keyboardMouseDevice.touchEndEvent(event); + // put any application specific touch behavior below here.. _touchDragStartedAvgX = _touchAvgX; _touchDragStartedAvgY = _touchAvgY; @@ -1619,6 +1644,8 @@ void Application::wheelEvent(QWheelEvent* event) { if (_controllerScriptingInterface.isWheelCaptured()) { return; } + + _keyboardMouseDevice.wheelEvent(event); } void Application::dropEvent(QDropEvent *event) { @@ -2355,6 +2382,7 @@ void Application::update(float deltaTime) { updateLOD(); updateMouseRay(); // check what's under the mouse and update the mouse voxel + { PerformanceTimer perfTimer("devices"); DeviceTracker::updateAll(); @@ -2365,10 +2393,27 @@ void Application::update(float deltaTime) { SixenseManager::getInstance().update(deltaTime); JoystickScriptingInterface::getInstance().update(); } - + + _userInputMapper.update(deltaTime); + _keyboardMouseDevice.resetDeltas(); // Probably should be a update call , the place where the deltas are cleaned for th enew loop + // Dispatch input events _controllerScriptingInterface.updateInputControllers(); + // Transfer the user inputs to the driveKeys + _myAvatar->clearDriveKeys(); + _myAvatar->setDriveKeys(FWD, _userInputMapper.getActionState(UserInputMapper::LONGITUDINAL_FORWARD)); + _myAvatar->setDriveKeys(BACK, _userInputMapper.getActionState(UserInputMapper::LONGITUDINAL_BACKWARD)); + _myAvatar->setDriveKeys(UP, _userInputMapper.getActionState(UserInputMapper::VERTICAL_UP)); + _myAvatar->setDriveKeys(DOWN, _userInputMapper.getActionState(UserInputMapper::VERTICAL_DOWN)); + _myAvatar->setDriveKeys(LEFT, _userInputMapper.getActionState(UserInputMapper::LATERAL_LEFT)); + _myAvatar->setDriveKeys(RIGHT, _userInputMapper.getActionState(UserInputMapper::LATERAL_RIGHT)); + _myAvatar->setDriveKeys(ROT_UP, _userInputMapper.getActionState(UserInputMapper::PITCH_UP)); + _myAvatar->setDriveKeys(ROT_DOWN, _userInputMapper.getActionState(UserInputMapper::PITCH_DOWN)); + _myAvatar->setDriveKeys(ROT_LEFT, _userInputMapper.getActionState(UserInputMapper::YAW_LEFT)); + _myAvatar->setDriveKeys(ROT_RIGHT, _userInputMapper.getActionState(UserInputMapper::YAW_RIGHT)); + + updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... DependencyManager::get()->updateOtherAvatars(deltaTime); //loop through all the other avatars and simulate them... diff --git a/interface/src/Application.h b/interface/src/Application.h index 9f87d05711..60a5fbf929 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -69,6 +69,7 @@ #include "ui/ApplicationOverlay.h" #include "ui/RunningScriptsWidget.h" #include "ui/ToolWindow.h" +#include "ui/UserInputMapper.h" #include "octree/OctreeFade.h" #include "octree/OctreePacketProcessor.h" #include "UndoStackScriptingInterface.h" @@ -517,6 +518,10 @@ private: OctreeQuery _octreeQuery; // NodeData derived class for querying octee cells from octree servers + KeyboardMouseDevice _keyboardMouseDevice; // Default input device, the good old keyboard mouse and maybe touchpad + + UserInputMapper _userInputMapper; // User input mapper allowing to mapp different real devices to the action channels that the application has to offer + MyAvatar* _myAvatar; // TODO: move this and relevant code to AvatarManager (or MyAvatar as the case may be) Camera _myCamera; // My view onto the world diff --git a/interface/src/ui/UserInputMapper.cpp b/interface/src/ui/UserInputMapper.cpp new file mode 100755 index 0000000000..8a86e3b3bf --- /dev/null +++ b/interface/src/ui/UserInputMapper.cpp @@ -0,0 +1,348 @@ +// +// UserInputMapper.cpp +// interface/src/ui +// +// Created by Sam Gateau on 4/27/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 "UserInputMapper.h" +#include + + +void KeyboardMouseDevice::keyPressEvent(QKeyEvent* event) { + auto input = makeInput((Qt::Key) event->key()); + auto result = _buttonPressedMap.insert(input.getChannel()); + if (!result.second) { + // key pressed again ? without catching the release event ? + } +} +void KeyboardMouseDevice::keyReleaseEvent(QKeyEvent* event) { + auto input = makeInput((Qt::Key) event->key()); + _buttonPressedMap.erase(input.getChannel()); +} + +void KeyboardMouseDevice::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { + auto input = makeInput((Qt::MouseButton) event->button()); + auto result = _buttonPressedMap.insert(input.getChannel()); + if (!result.second) { + // key pressed again ? without catching the release event ? + } + _lastCursor = event->pos(); +} +void KeyboardMouseDevice::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { + auto input = makeInput((Qt::MouseButton) event->button()); + _buttonPressedMap.erase(input.getChannel()); +} +void KeyboardMouseDevice::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { + QPoint currentPos = event->pos(); + QPoint currentMove = currentPos - _lastCursor; + + _axisStateMap[makeInput(MOUSE_AXIS_X_POS).getChannel()] = (currentMove.x() > 0 ? currentMove.x() : 0.0f); + _axisStateMap[makeInput(MOUSE_AXIS_X_NEG).getChannel()] = (currentMove.x() < 0 ? -currentMove.x() : 0.0f); + // Y mouse is inverted positive is pointing up the screen + _axisStateMap[makeInput(MOUSE_AXIS_Y_POS).getChannel()] = (currentMove.y() < 0 ? -currentMove.y() : 0.0f); + _axisStateMap[makeInput(MOUSE_AXIS_Y_NEG).getChannel()] = (currentMove.y() > 0 ? currentMove.y() : 0.0f); + + _lastCursor = currentPos; +} +void KeyboardMouseDevice::wheelEvent(QWheelEvent* event) { + auto currentMove = event->angleDelta() / 120.0f; + + _axisStateMap[makeInput(MOUSE_AXIS_WHEEL_X_POS).getChannel()] = (currentMove.x() > 0 ? currentMove.x() : 0.0f); + _axisStateMap[makeInput(MOUSE_AXIS_WHEEL_X_NEG).getChannel()] = (currentMove.x() < 0 ? -currentMove.x() : 0.0f); + _axisStateMap[makeInput(MOUSE_AXIS_WHEEL_Y_POS).getChannel()] = (currentMove.y() > 0 ? currentMove.y() : 0.0f); + _axisStateMap[makeInput(MOUSE_AXIS_WHEEL_Y_NEG).getChannel()] = (currentMove.y() < 0 ? -currentMove.y() : 0.0f); +} + +glm::vec2 KeyboardMouseDevice::evalAverageTouchPoints(const QList& points) const { + glm::vec2 averagePoint(0.0f); + if (points.count() > 0) { + for (auto& point : points) { + averagePoint += glm::vec2(point.pos().x(), point.pos().y()); + } + averagePoint /= (float)(points.count()); + } + return averagePoint; +} + + +void KeyboardMouseDevice::touchBeginEvent(const QTouchEvent* event) { + _isTouching = event->touchPointStates().testFlag(Qt::TouchPointPressed); + + _lastTouch = evalAverageTouchPoints(event->touchPoints()); +} +void KeyboardMouseDevice::touchEndEvent(const QTouchEvent* event) { + _isTouching = false; + _lastTouch = evalAverageTouchPoints(event->touchPoints()); +} +void KeyboardMouseDevice::touchUpdateEvent(const QTouchEvent* event) { + auto currentPos = evalAverageTouchPoints(event->touchPoints()); + + if (!_isTouching) { + _isTouching = event->touchPointStates().testFlag(Qt::TouchPointPressed); + } else { + auto currentMove = currentPos - _lastTouch; + + _axisStateMap[makeInput(TOUCH_AXIS_X_POS).getChannel()] = (currentMove.x > 0 ? currentMove.x : 0.0f); + _axisStateMap[makeInput(TOUCH_AXIS_X_NEG).getChannel()] = (currentMove.x < 0 ? -currentMove.x : 0.0f); + // Y mouse is inverted positive is pointing up the screen + _axisStateMap[makeInput(TOUCH_AXIS_Y_POS).getChannel()] = (currentMove.y < 0 ? -currentMove.y : 0.0f); + _axisStateMap[makeInput(TOUCH_AXIS_Y_NEG).getChannel()] = (currentMove.y > 0 ? currentMove.y : 0.0f); + } + + _lastTouch = currentPos; +} + +UserInputMapper::Input KeyboardMouseDevice::makeInput(Qt::Key code) { + return UserInputMapper::Input(DEFAULT_DESKTOP_DEVICE, code & KEYBOARD_MASK, UserInputMapper::ChannelType::BUTTON); +} +UserInputMapper::Input KeyboardMouseDevice::makeInput(Qt::MouseButton code) { + switch (code) { + case Qt::LeftButton: + return UserInputMapper::Input(DEFAULT_DESKTOP_DEVICE, MOUSE_BUTTON_LEFT, UserInputMapper::ChannelType::BUTTON); + case Qt::RightButton: + return UserInputMapper::Input(DEFAULT_DESKTOP_DEVICE, MOUSE_BUTTON_RIGHT, UserInputMapper::ChannelType::BUTTON); + case Qt::MiddleButton: + return UserInputMapper::Input(DEFAULT_DESKTOP_DEVICE, MOUSE_BUTTON_MIDDLE, UserInputMapper::ChannelType::BUTTON); + default: + return UserInputMapper::Input(); + }; +} +UserInputMapper::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::MouseAxisChannel axis) { + return UserInputMapper::Input(DEFAULT_DESKTOP_DEVICE, axis, UserInputMapper::ChannelType::AXIS); +} +UserInputMapper::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchAxisChannel axis) { + return UserInputMapper::Input(DEFAULT_DESKTOP_DEVICE, axis, UserInputMapper::ChannelType::AXIS); +} +UserInputMapper::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchButtonChannel button) { + return UserInputMapper::Input(DEFAULT_DESKTOP_DEVICE, button, UserInputMapper::ChannelType::BUTTON); +} + +void KeyboardMouseDevice::registerToUserInputMapper(UserInputMapper& mapper) { + auto proxy = UserInputMapper::DeviceProxy::Pointer(new UserInputMapper::DeviceProxy()); + proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input._channel); }; + proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input._channel); }; + mapper.registerDevice(DEFAULT_DESKTOP_DEVICE, proxy); // HARDCODED!, the KeyboardMouseDevice always take the DeviceID = 1 +} + +void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) { + const float BUTTON_MOVE_SPEED = 1.0f; + const float BUTTON_ROTATION_SPEED = 30.0f; + const float MOUSE_ROTATION_SPEED = 0.25f; + const float BUTTON_BOOM_SPEED = 0.1f; + + // AWSD keys mapping + mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(Qt::Key_S), BUTTON_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(Qt::Key_W), BUTTON_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(Qt::Key_A), BUTTON_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(Qt::Key_D), BUTTON_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(Qt::Key_C), BUTTON_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(Qt::Key_E), BUTTON_MOVE_SPEED); + + mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(Qt::Key_W), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); + mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(Qt::Key_S), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(Qt::Key_A), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(Qt::Key_D), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(Qt::Key_C), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(Qt::Key_E), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); + + // Arrow keys mapping + mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(Qt::Key_Down), BUTTON_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(Qt::Key_Up), BUTTON_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(Qt::Key_Left), BUTTON_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(Qt::Key_Right), BUTTON_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(Qt::Key_PageDown), BUTTON_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(Qt::Key_PageUp), BUTTON_MOVE_SPEED); + + mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(Qt::Key_Up), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); + mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(Qt::Key_Down), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(Qt::Key_PageDown), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(Qt::Key_PageUp), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); + + // Mouse move + mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(MOUSE_AXIS_Y_NEG), makeInput(Qt::RightButton), MOUSE_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(MOUSE_AXIS_Y_POS), makeInput(Qt::RightButton), MOUSE_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(MOUSE_AXIS_X_NEG), makeInput(Qt::RightButton), MOUSE_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(MOUSE_AXIS_X_POS), makeInput(Qt::RightButton), MOUSE_ROTATION_SPEED); + + +#ifdef Q_OS_MAC + // wheel event modifier on Mac collide with the touchpad scroll event + mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), MOUSE_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), MOUSE_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), MOUSE_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), MOUSE_ROTATION_SPEED); +#else + // Touch pad yaw pitch + mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), MOUSE_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), MOUSE_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), MOUSE_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), MOUSE_ROTATION_SPEED); + + // Wheel move + mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(MOUSE_AXIS_WHEEL_Y_NEG), BUTTON_BOOM_SPEED); + mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(MOUSE_AXIS_WHEEL_Y_POS), BUTTON_BOOM_SPEED); + mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(MOUSE_AXIS_WHEEL_X_NEG), BUTTON_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(MOUSE_AXIS_WHEEL_X_POS), BUTTON_ROTATION_SPEED); + +#endif + +} + +float KeyboardMouseDevice::getButton(int channel) const { + if (!_buttonPressedMap.empty()) { + if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) { + return 1.0f; + } else { + return 0.0f; + } + } + return 0.0f; +} +float KeyboardMouseDevice::getAxis(int channel) const { + auto axis = _axisStateMap.find(channel); + if (axis != _axisStateMap.end()) { + return (*axis).second; + } else { + return 0.f; + } +} + + +// UserInputMapper Class +bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy){ + _registeredDevices[deviceID] = proxy; + return true; +} + +UserInputMapper::DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) { + auto device = _registeredDevices.find(input.getDevice()); + if (device != _registeredDevices.end()) { + return (device->second); + } else { + return DeviceProxy::Pointer(); + } +} +bool UserInputMapper::addInputChannel(Action action, const Input& input, float scale) { + return addInputChannel(action, input, Input(), scale); +} + +bool UserInputMapper::addInputChannel(Action action, const Input& input, const Input& modifier, float scale) { + // Check that the device is registered + if (!getDeviceProxy(input)) { + qDebug() << "UserInputMapper::addInputChannel: The input comes from a device #" << input.getDevice() << "is unknown. no inputChannel mapped."; + return false; + } + + auto inputChannel = InputChannel(input, modifier, action, scale); + + // Insert or replace the input to modifiers + if (inputChannel.hasModifier()) { + auto& modifiers = _inputToModifiersMap[input.getID()]; + modifiers.push_back(inputChannel._modifier); + std::sort(modifiers.begin(), modifiers.end()); + } + + // Now update the action To Inputs side of things + _actionToInputsMap.insert(ActionToInputsMap::value_type(action, inputChannel)); + + return true; +} + +int UserInputMapper::addInputChannels(const InputChannels& channels) { + int nbAdded = 0; + for (auto& channel : channels) { + nbAdded += addInputChannel(channel._action, channel._input, channel._modifier, channel._scale); + } + return nbAdded; +} + +int UserInputMapper::getInputChannels(InputChannels& channels) const { + for (auto& channel : _actionToInputsMap) { + channels.push_back(channel.second); + } + + return _actionToInputsMap.size(); +} + +void UserInputMapper::update(float deltaTime) { + + // Reset the axis state for next loop + for (auto& channel : _actionStates) { + channel = 0.0f; + } + + int currentTimestamp = 0; + + for (auto& channelInput : _actionToInputsMap) { + auto& inputMapping = channelInput.second; + auto& inputID = inputMapping._input; + bool enabled = true; + + // Check if this input channel has modifiers and collect the possibilities + auto modifiersIt = _inputToModifiersMap.find(inputID.getID()); + if (modifiersIt != _inputToModifiersMap.end()) { + Modifiers validModifiers; + bool isActiveModifier = false; + for (auto& modifier : modifiersIt->second) { + auto deviceProxy = getDeviceProxy(modifier); + if (deviceProxy->getButton(modifier, currentTimestamp)) { + validModifiers.push_back(modifier); + isActiveModifier |= (modifier.getID() == inputMapping._modifier.getID()); + } + } + enabled = (validModifiers.empty() && !inputMapping.hasModifier()) || isActiveModifier; + } + + // if enabled: default input or all modifiers on + if (enabled) { + auto deviceProxy = getDeviceProxy(inputID); + switch (inputMapping._input.getType()) { + case ChannelType::BUTTON: { + _actionStates[channelInput.first] += inputMapping._scale * float(deviceProxy->getButton(inputID, currentTimestamp)) * deltaTime; + break; + } + case ChannelType::AXIS: { + _actionStates[channelInput.first] += inputMapping._scale * deviceProxy->getAxis(inputID, currentTimestamp); + break; + } + case ChannelType::JOINT: { + // _channelStates[channelInput.first].jointVal = deviceProxy->getJoint(inputID, currentTimestamp); + break; + } + default: { + break; //silence please + } + } + } else{ + // Channel input not enabled + enabled = false; + } + } + + // Scale all the channel step with the the unit scale and the time + for (auto i = 0; i < NUM_ACTIONS; i++) { + _actionStates[i] *= _actionUnitScales[i]; + } +} + + +void UserInputMapper::assignDefaulActionUnitScales() { + _actionUnitScales[LONGITUDINAL_BACKWARD] = 1.0f; // 1m per unit + _actionUnitScales[LONGITUDINAL_FORWARD] = 1.0f; // 1m per unit + _actionUnitScales[LATERAL_LEFT] = 1.0f; // 1m per unit + _actionUnitScales[LATERAL_RIGHT] = 1.0f; // 1m per unit + _actionUnitScales[VERTICAL_DOWN] = 1.0f; // 1m per unit + _actionUnitScales[VERTICAL_UP] = 1.0f; // 1m per unit + _actionUnitScales[YAW_LEFT] = glm::radians(1.0f); // 3 degree per unit + _actionUnitScales[YAW_RIGHT] = glm::radians(1.0f); // 3 degree per unit + _actionUnitScales[PITCH_DOWN] = glm::radians(1.0f); // 3 degree per unit + _actionUnitScales[PITCH_UP] = glm::radians(1.0f); // 3 degree per unit + _actionUnitScales[BOOM_IN] = 1.0f; // 1m per unit + _actionUnitScales[BOOM_OUT] = 1.0f; // 1m per unit +} diff --git a/interface/src/ui/UserInputMapper.h b/interface/src/ui/UserInputMapper.h new file mode 100755 index 0000000000..33eb4c656c --- /dev/null +++ b/interface/src/ui/UserInputMapper.h @@ -0,0 +1,263 @@ +// +// UserInputMapper.h +// interface/src/ui +// +// Created by Sam Gateau on 4/27/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_UserInputMapper_h +#define hifi_UserInputMapper_h + +#include +#include +#include + +#include +#include +#include + + +class UserInputMapper : public QObject { + Q_OBJECT +public: + typedef unsigned short uint16; + typedef unsigned int uint32; + + enum class ChannelType { + UNKNOWN = 0, + BUTTON = 1, + AXIS, + JOINT, + }; + + // Input is the unique identifier to find a n input channel of a particular device + // Devices are responsible for registering to the UseInputMapper so their input channels can be sued and mapped + // to the Action channels + class Input { + public: + union { + struct { + uint16 _device; // Up to 64K possible devices + uint16 _channel : 14; // 2^14 possible channel per Device + uint16 _type : 2; // 2 bits to store the Type directly in the ID + }; + uint32 _id = 0; // by default Input is 0 meaning invalid + }; + + bool isValid() const { return (_id != 0); } + + uint16 getDevice() const { return _device; } + uint16 getChannel() const { return _channel; } + uint32 getID() const { return _id; } + + ChannelType getType() const { return (ChannelType) _type; } + bool isButton() const { return getType() == ChannelType::BUTTON; } + bool isAxis() const { return getType() == ChannelType::AXIS; } + bool isJoint() const { return getType() == ChannelType::JOINT; } + + explicit Input() {} + explicit Input(uint32 id) : _id(id) {} + explicit Input(uint16 device, uint16 channel, ChannelType type) : _device(device), _channel(channel), _type(uint16(type)) {} + Input(const Input& src) : _id(src._id) {} + Input& operator = (const Input& src) { _id = src._id; return (*this); } + bool operator < (const Input& src) const { return _id < src._id; } + }; + + // Modifiers are just button inputID + typedef std::vector< Input > Modifiers; + + class JointValue { + public: + glm::vec3 translation{ 0.0f }; + glm::quat rotation; + + JointValue() {}; + JointValue(const JointValue&) = default; + JointValue& operator = (const JointValue&) = default; + }; + + typedef std::function ButtonGetter; + typedef std::function AxisGetter; + typedef std::function JointGetter; + + class DeviceProxy { + public: + DeviceProxy() {} + + ButtonGetter getButton = [] (const Input& input, int timestamp) -> bool { return false; }; + AxisGetter getAxis = [] (const Input& input, int timestamp) -> bool { return 0.0f; }; + JointGetter getJoint = [] (const Input& input, int timestamp) -> JointValue { return JointValue(); }; + + typedef std::shared_ptr Pointer; + }; + bool registerDevice(uint16 deviceID, const DeviceProxy::Pointer& device); + DeviceProxy::Pointer getDeviceProxy(const Input& input); + + + // Actions are the output channels of the Mapper, that's what the InputChannel map to + // For now the Actions are hardcoded, this is bad, but we will fix that in the near future + enum Action { + LONGITUDINAL_BACKWARD = 0, + LONGITUDINAL_FORWARD, + + LATERAL_LEFT, + LATERAL_RIGHT, + + VERTICAL_DOWN, + VERTICAL_UP, + + YAW_LEFT, + YAW_RIGHT, + + PITCH_DOWN, + PITCH_UP, + + BOOM_IN, + BOOM_OUT, + + NUM_ACTIONS, + }; + + float getActionState(Action action) const { return _actionStates[action]; } + void assignDefaulActionUnitScales(); + + // Add input channel to the mapper and check that all the used channels are registered. + // Return true if theinput channel is created correctly, false either + bool addInputChannel(Action action, const Input& input, float scale = 1.0f); + bool addInputChannel(Action action, const Input& input, const Input& modifer, float scale = 1.0f); + + // Under the hood, the input channels are organized in map sorted on the _output + // The InputChannel class is just the full values describing the input channel in one object + class InputChannel { + public: + Input _input; + Input _modifier = Input(); // make it invalid by default, meaning no modifier + Action _action = LONGITUDINAL_BACKWARD; + float _scale = 0.0f; + + InputChannel() {} + InputChannel(const Input& input, const Input& modifier, Action action, float scale = 1.0f) : + _input(input), _modifier(modifier), _action(action), _scale(scale) {} + InputChannel(const InputChannel& src) : InputChannel(src._input, src._modifier, src._action, src._scale) {} + InputChannel& operator = (const InputChannel& src) { _input = src._input; _modifier = src._modifier; _action = src._action; _scale = src._scale; return (*this); } + + bool hasModifier() { return _modifier.isValid(); } + }; + typedef std::vector< InputChannel > InputChannels; + + // Add a bunch of input channels, return the true number of channels that successfully were added + int addInputChannels(const InputChannels& channels); + //Grab all the input channels currently in use, return the number + int getInputChannels(InputChannels& channels) const; + + // Update means go grab all the device input channels and update the output channel values + void update(float deltaTime); + + // Default contruct allocate the poutput size with the current hardcoded action channels + UserInputMapper() { assignDefaulActionUnitScales(); } + +protected: + typedef std::map DevicesMap; + DevicesMap _registeredDevices; + + typedef std::map InputToMoModifiersMap; + InputToMoModifiersMap _inputToModifiersMap; + + typedef std::multimap ActionToInputsMap; + ActionToInputsMap _actionToInputsMap; + + std::vector _actionStates = std::vector(NUM_ACTIONS, 0.0f); + std::vector _actionUnitScales = std::vector(NUM_ACTIONS, 1.0f); +}; + + +class KeyboardMouseDevice { +public: + + enum KeyboardChannel { + KEYBOARD_FIRST = 0, + KEYBOARD_LAST = 255, + KEYBOARD_MASK = 0x00FF, + }; + + enum MouseButtonChannel { + MOUSE_BUTTON_LEFT = KEYBOARD_LAST + 1, + MOUSE_BUTTON_RIGHT, + MOUSE_BUTTON_MIDDLE, + }; + + enum MouseAxisChannel { + MOUSE_AXIS_X_POS = MOUSE_BUTTON_MIDDLE + 1, + MOUSE_AXIS_X_NEG, + MOUSE_AXIS_Y_POS, + MOUSE_AXIS_Y_NEG, + MOUSE_AXIS_WHEEL_Y_POS, + MOUSE_AXIS_WHEEL_Y_NEG, + MOUSE_AXIS_WHEEL_X_POS, + MOUSE_AXIS_WHEEL_X_NEG, + }; + + enum TouchAxisChannel { + TOUCH_AXIS_X_POS = MOUSE_AXIS_WHEEL_X_NEG + 1, + TOUCH_AXIS_X_NEG, + TOUCH_AXIS_Y_POS, + TOUCH_AXIS_Y_NEG, + }; + + enum TouchButtonChannel { + TOUCH_BUTTON_PRESS = TOUCH_AXIS_Y_NEG + 1, + }; + + typedef std::unordered_set ButtonPressedMap; + typedef std::map AxisStateMap; // 8 axes + + void keyPressEvent(QKeyEvent* event); + void keyReleaseEvent(QKeyEvent* event); + + void mouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0); + void mousePressEvent(QMouseEvent* event, unsigned int deviceID = 0); + void mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0); + + void touchBeginEvent(const QTouchEvent* event); + void touchEndEvent(const QTouchEvent* event); + void touchUpdateEvent(const QTouchEvent* event); + + void wheelEvent(QWheelEvent* event); + + ButtonPressedMap _buttonPressedMap; + mutable AxisStateMap _axisStateMap; + + QPoint _lastCursor; + glm::vec2 _lastTouch; + bool _isTouching = false; + + float getButton(int channel) const; + float getAxis(int channel) const; + + // Reserverd device ID for the standard keyboard and mouse + const static UserInputMapper::uint16 DEFAULT_DESKTOP_DEVICE = 1; + + // Let's make it easy for Qt because we assume we love Qt forever + static UserInputMapper::Input makeInput(Qt::Key code); + static UserInputMapper::Input makeInput(Qt::MouseButton code); + static UserInputMapper::Input makeInput(KeyboardMouseDevice::MouseAxisChannel axis); + static UserInputMapper::Input makeInput(KeyboardMouseDevice::TouchAxisChannel axis); + static UserInputMapper::Input makeInput(KeyboardMouseDevice::TouchButtonChannel button); + + KeyboardMouseDevice() {} + + void registerToUserInputMapper(UserInputMapper& mapper); + void assignDefaultInputMapping(UserInputMapper& mapper); + + void resetDeltas() { + _axisStateMap.clear(); + } + + glm::vec2 evalAverageTouchPoints(const QList& points) const; +}; + +#endif // hifi_UserInputMapper_h \ No newline at end of file diff --git a/libraries/script-engine/src/TouchEvent.h b/libraries/script-engine/src/TouchEvent.h index 9c1147fecf..d9eedf50d0 100644 --- a/libraries/script-engine/src/TouchEvent.h +++ b/libraries/script-engine/src/TouchEvent.h @@ -13,6 +13,7 @@ #define hifi_TouchEvent_h #include +#include class TouchEvent { public: From d2e61dba05c1091ee61fdc854ade34d416819234 Mon Sep 17 00:00:00 2001 From: samcake Date: Sun, 3 May 2015 17:34:39 -0700 Subject: [PATCH 2/9] Make the nw mapper work for th einputs --- interface/src/Application.cpp | 2 +- interface/src/ui/UserInputMapper.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index be92b59343..24261d978c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1538,7 +1538,7 @@ void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { return; } - _keyboardMouseDevice.mousePressEvent(event); + _keyboardMouseDevice.mouseReleaseEvent(event); if (activeWindow() == _window) { diff --git a/interface/src/ui/UserInputMapper.cpp b/interface/src/ui/UserInputMapper.cpp index 8a86e3b3bf..22683173df 100755 --- a/interface/src/ui/UserInputMapper.cpp +++ b/interface/src/ui/UserInputMapper.cpp @@ -339,10 +339,10 @@ void UserInputMapper::assignDefaulActionUnitScales() { _actionUnitScales[LATERAL_RIGHT] = 1.0f; // 1m per unit _actionUnitScales[VERTICAL_DOWN] = 1.0f; // 1m per unit _actionUnitScales[VERTICAL_UP] = 1.0f; // 1m per unit - _actionUnitScales[YAW_LEFT] = glm::radians(1.0f); // 3 degree per unit - _actionUnitScales[YAW_RIGHT] = glm::radians(1.0f); // 3 degree per unit - _actionUnitScales[PITCH_DOWN] = glm::radians(1.0f); // 3 degree per unit - _actionUnitScales[PITCH_UP] = glm::radians(1.0f); // 3 degree per unit + _actionUnitScales[YAW_LEFT] = 1.0f;//glm::radians(1.0f); // 3 degree per unit + _actionUnitScales[YAW_RIGHT] = 1.0f;//glm::radians(1.0f); // 3 degree per unit + _actionUnitScales[PITCH_DOWN] = 1.0f;//glm::radians(1.0f); // 3 degree per unit + _actionUnitScales[PITCH_UP] = 1.0f;//glm::radians(1.0f); // 3 degree per unit _actionUnitScales[BOOM_IN] = 1.0f; // 1m per unit _actionUnitScales[BOOM_OUT] = 1.0f; // 1m per unit } From ae14396fd7b90035c88a5cf179cd8e9cac2ea1e1 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Sun, 3 May 2015 18:03:27 -0700 Subject: [PATCH 3/9] adjust the key mapping for mac book and the scales --- interface/src/ui/UserInputMapper.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/interface/src/ui/UserInputMapper.cpp b/interface/src/ui/UserInputMapper.cpp index 22683173df..2f7575d663 100755 --- a/interface/src/ui/UserInputMapper.cpp +++ b/interface/src/ui/UserInputMapper.cpp @@ -131,7 +131,7 @@ void KeyboardMouseDevice::registerToUserInputMapper(UserInputMapper& mapper) { void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) { const float BUTTON_MOVE_SPEED = 1.0f; const float BUTTON_ROTATION_SPEED = 30.0f; - const float MOUSE_ROTATION_SPEED = 0.25f; + const float MOUSE_ROTATION_SPEED = 1.0f; const float BUTTON_BOOM_SPEED = 0.1f; // AWSD keys mapping @@ -142,8 +142,8 @@ void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) { mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(Qt::Key_C), BUTTON_MOVE_SPEED); mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(Qt::Key_E), BUTTON_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(Qt::Key_W), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); - mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(Qt::Key_S), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); + // mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(Qt::Key_W), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); + // mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(Qt::Key_S), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(Qt::Key_A), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(Qt::Key_D), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(Qt::Key_C), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); @@ -157,12 +157,12 @@ void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) { mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(Qt::Key_PageDown), BUTTON_MOVE_SPEED); mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(Qt::Key_PageUp), BUTTON_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(Qt::Key_Up), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); - mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(Qt::Key_Down), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); + // mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(Qt::Key_Up), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); + // mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(Qt::Key_Down), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(Qt::Key_PageDown), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(Qt::Key_PageUp), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(Qt::Key_Down), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(Qt::Key_Up), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); // Mouse move mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(MOUSE_AXIS_Y_NEG), makeInput(Qt::RightButton), MOUSE_ROTATION_SPEED); From 116e29ae570be89ee308dd8d662da00ba3ca1f08 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Sun, 3 May 2015 18:40:55 -0700 Subject: [PATCH 4/9] adjust the timer for touch event to work around the missing touch begin / touch end --- interface/src/ui/UserInputMapper.cpp | 11 ++++++++++- interface/src/ui/UserInputMapper.h | 4 +++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/UserInputMapper.cpp b/interface/src/ui/UserInputMapper.cpp index 2f7575d663..4b75b8ad96 100755 --- a/interface/src/ui/UserInputMapper.cpp +++ b/interface/src/ui/UserInputMapper.cpp @@ -73,16 +73,25 @@ void KeyboardMouseDevice::touchBeginEvent(const QTouchEvent* event) { _isTouching = event->touchPointStates().testFlag(Qt::TouchPointPressed); _lastTouch = evalAverageTouchPoints(event->touchPoints()); + _lastTouchTime = _clock.now(); } void KeyboardMouseDevice::touchEndEvent(const QTouchEvent* event) { _isTouching = false; _lastTouch = evalAverageTouchPoints(event->touchPoints()); + _lastTouchTime = _clock.now(); } void KeyboardMouseDevice::touchUpdateEvent(const QTouchEvent* event) { auto currentPos = evalAverageTouchPoints(event->touchPoints()); + auto currentTime = _clock.now(); + auto sinceLastTouch = std::chrono::duration_cast(currentTime - _lastTouchTime); + if (sinceLastTouch.count() > 50) { + _isTouching = false; + } + if (!_isTouching) { _isTouching = event->touchPointStates().testFlag(Qt::TouchPointPressed); + _lastTouchTime = _clock.now(); } else { auto currentMove = currentPos - _lastTouch; @@ -131,7 +140,7 @@ void KeyboardMouseDevice::registerToUserInputMapper(UserInputMapper& mapper) { void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) { const float BUTTON_MOVE_SPEED = 1.0f; const float BUTTON_ROTATION_SPEED = 30.0f; - const float MOUSE_ROTATION_SPEED = 1.0f; + const float MOUSE_ROTATION_SPEED = 0.5f; const float BUTTON_BOOM_SPEED = 0.1f; // AWSD keys mapping diff --git a/interface/src/ui/UserInputMapper.h b/interface/src/ui/UserInputMapper.h index 33eb4c656c..e1dc181299 100755 --- a/interface/src/ui/UserInputMapper.h +++ b/interface/src/ui/UserInputMapper.h @@ -19,7 +19,7 @@ #include #include #include - +#include class UserInputMapper : public QObject { Q_OBJECT @@ -258,6 +258,8 @@ public: } glm::vec2 evalAverageTouchPoints(const QList& points) const; + std::chrono::high_resolution_clock _clock; + std::chrono::high_resolution_clock::time_point _lastTouchTime; }; #endif // hifi_UserInputMapper_h \ No newline at end of file From 8e65ce34d121bb3dfc316437760acebbca945bc9 Mon Sep 17 00:00:00 2001 From: samcake Date: Sun, 3 May 2015 23:47:43 -0700 Subject: [PATCH 5/9] FINe tune the scales for the Mac Book --- interface/src/Application.cpp | 3 +- interface/src/ui/UserInputMapper.cpp | 114 +++++++++++++++------------ interface/src/ui/UserInputMapper.h | 28 ++++--- 3 files changed, 79 insertions(+), 66 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 24261d978c..62af97c5ae 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -548,7 +548,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : this, &Application::checkSkeleton, Qt::QueuedConnection); // Setup the userInputMapper with the actions - _userInputMapper.assignDefaulActionUnitScales(); // Setup the keyboardMouseDevice and the user input mapper with the default bindings _keyboardMouseDevice.registerToUserInputMapper(_userInputMapper); _keyboardMouseDevice.assignDefaultInputMapping(_userInputMapper); @@ -2395,7 +2394,7 @@ void Application::update(float deltaTime) { } _userInputMapper.update(deltaTime); - _keyboardMouseDevice.resetDeltas(); // Probably should be a update call , the place where the deltas are cleaned for th enew loop + _keyboardMouseDevice.update(); // Dispatch input events _controllerScriptingInterface.updateInputControllers(); diff --git a/interface/src/ui/UserInputMapper.cpp b/interface/src/ui/UserInputMapper.cpp index 4b75b8ad96..7c1f2f8d4b 100755 --- a/interface/src/ui/UserInputMapper.cpp +++ b/interface/src/ui/UserInputMapper.cpp @@ -11,6 +11,21 @@ #include "UserInputMapper.h" #include +void KeyboardMouseDevice::update() { + _axisStateMap.clear(); + + // For touch event, we need to check that the last event is not too long ago + // Maybe it's a Qt issue, but the touch event sequence (begin, update, end) is not always called properly + // The following is a workaround to detect that the touch sequence is over in case we didn;t see the end event + if (_isTouching) { + const auto TOUCH_EVENT_MAXIMUM_WAIT = 100; //ms + auto currentTime = _clock.now(); + auto sinceLastTouch = std::chrono::duration_cast(currentTime - _lastTouchTime); + if (sinceLastTouch.count() > TOUCH_EVENT_MAXIMUM_WAIT) { + _isTouching = false; + } + } +} void KeyboardMouseDevice::keyPressEvent(QKeyEvent* event) { auto input = makeInput((Qt::Key) event->key()); @@ -71,7 +86,6 @@ glm::vec2 KeyboardMouseDevice::evalAverageTouchPoints(const QListtouchPointStates().testFlag(Qt::TouchPointPressed); - _lastTouch = evalAverageTouchPoints(event->touchPoints()); _lastTouchTime = _clock.now(); } @@ -82,16 +96,10 @@ void KeyboardMouseDevice::touchEndEvent(const QTouchEvent* event) { } void KeyboardMouseDevice::touchUpdateEvent(const QTouchEvent* event) { auto currentPos = evalAverageTouchPoints(event->touchPoints()); - - auto currentTime = _clock.now(); - auto sinceLastTouch = std::chrono::duration_cast(currentTime - _lastTouchTime); - if (sinceLastTouch.count() > 50) { - _isTouching = false; - } - + _lastTouchTime = _clock.now(); + if (!_isTouching) { _isTouching = event->touchPointStates().testFlag(Qt::TouchPointPressed); - _lastTouchTime = _clock.now(); } else { auto currentMove = currentPos - _lastTouch; @@ -139,9 +147,13 @@ void KeyboardMouseDevice::registerToUserInputMapper(UserInputMapper& mapper) { void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) { const float BUTTON_MOVE_SPEED = 1.0f; - const float BUTTON_ROTATION_SPEED = 30.0f; - const float MOUSE_ROTATION_SPEED = 0.5f; - const float BUTTON_BOOM_SPEED = 0.1f; + const float BUTTON_YAW_SPEED = 0.75f; + const float BUTTON_PITCH_SPEED = 0.5f; + const float MOUSE_YAW_SPEED = 0.5f; + const float MOUSE_PITCH_SPEED = 0.25f; + const float TOUCH_YAW_SPEED = 0.5f; + const float TOUCH_PITCH_SPEED = 0.25f; + //const float BUTTON_BOOM_SPEED = 0.1f; // AWSD keys mapping mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(Qt::Key_S), BUTTON_MOVE_SPEED); @@ -153,10 +165,10 @@ void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) { // mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(Qt::Key_W), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); // mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(Qt::Key_S), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(Qt::Key_A), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(Qt::Key_D), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(Qt::Key_C), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(Qt::Key_E), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(Qt::Key_A), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(Qt::Key_D), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(Qt::Key_C), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(Qt::Key_E), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED); // Arrow keys mapping mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(Qt::Key_Down), BUTTON_MOVE_SPEED); @@ -168,36 +180,36 @@ void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) { // mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(Qt::Key_Up), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); // mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(Qt::Key_Down), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(Qt::Key_Down), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(Qt::Key_Up), makeInput(Qt::Key_Shift), BUTTON_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(Qt::Key_Down), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(Qt::Key_Up), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED); // Mouse move - mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(MOUSE_AXIS_Y_NEG), makeInput(Qt::RightButton), MOUSE_ROTATION_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(MOUSE_AXIS_Y_POS), makeInput(Qt::RightButton), MOUSE_ROTATION_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(MOUSE_AXIS_X_NEG), makeInput(Qt::RightButton), MOUSE_ROTATION_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(MOUSE_AXIS_X_POS), makeInput(Qt::RightButton), MOUSE_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(MOUSE_AXIS_Y_NEG), makeInput(Qt::RightButton), MOUSE_PITCH_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(MOUSE_AXIS_Y_POS), makeInput(Qt::RightButton), MOUSE_PITCH_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(MOUSE_AXIS_X_NEG), makeInput(Qt::RightButton), MOUSE_YAW_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(MOUSE_AXIS_X_POS), makeInput(Qt::RightButton), MOUSE_YAW_SPEED); #ifdef Q_OS_MAC // wheel event modifier on Mac collide with the touchpad scroll event - mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), MOUSE_ROTATION_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), MOUSE_ROTATION_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), MOUSE_ROTATION_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), MOUSE_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), TOUCH_PITCH_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), TOUCH_PITCH_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), TOUCH_YAW_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), TOUCH_YAW_SPEED); #else // Touch pad yaw pitch - mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), MOUSE_ROTATION_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), MOUSE_ROTATION_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), MOUSE_ROTATION_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), MOUSE_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), TOUCH_PITCH_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), TOUCH_PITCH_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), TOUCH_YAW_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), TOUCH_YAW_SPEED); // Wheel move mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(MOUSE_AXIS_WHEEL_Y_NEG), BUTTON_BOOM_SPEED); mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(MOUSE_AXIS_WHEEL_Y_POS), BUTTON_BOOM_SPEED); - mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(MOUSE_AXIS_WHEEL_X_NEG), BUTTON_ROTATION_SPEED); - mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(MOUSE_AXIS_WHEEL_X_POS), BUTTON_ROTATION_SPEED); + mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(MOUSE_AXIS_WHEEL_X_NEG), BUTTON_YAW_SPEED); + mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(MOUSE_AXIS_WHEEL_X_POS), BUTTON_YAW_SPEED); #endif @@ -218,7 +230,7 @@ float KeyboardMouseDevice::getAxis(int channel) const { if (axis != _axisStateMap.end()) { return (*axis).second; } else { - return 0.f; + return 0.0f; } } @@ -313,7 +325,7 @@ void UserInputMapper::update(float deltaTime) { auto deviceProxy = getDeviceProxy(inputID); switch (inputMapping._input.getType()) { case ChannelType::BUTTON: { - _actionStates[channelInput.first] += inputMapping._scale * float(deviceProxy->getButton(inputID, currentTimestamp)) * deltaTime; + _actionStates[channelInput.first] += inputMapping._scale * float(deviceProxy->getButton(inputID, currentTimestamp));// * deltaTime; // weight the impulse by the deltaTime break; } case ChannelType::AXIS: { @@ -334,24 +346,24 @@ void UserInputMapper::update(float deltaTime) { } } - // Scale all the channel step with the the unit scale and the time + // Scale all the channel step with the scale for (auto i = 0; i < NUM_ACTIONS; i++) { - _actionStates[i] *= _actionUnitScales[i]; + _actionStates[i] *= _actionScales[i]; } } -void UserInputMapper::assignDefaulActionUnitScales() { - _actionUnitScales[LONGITUDINAL_BACKWARD] = 1.0f; // 1m per unit - _actionUnitScales[LONGITUDINAL_FORWARD] = 1.0f; // 1m per unit - _actionUnitScales[LATERAL_LEFT] = 1.0f; // 1m per unit - _actionUnitScales[LATERAL_RIGHT] = 1.0f; // 1m per unit - _actionUnitScales[VERTICAL_DOWN] = 1.0f; // 1m per unit - _actionUnitScales[VERTICAL_UP] = 1.0f; // 1m per unit - _actionUnitScales[YAW_LEFT] = 1.0f;//glm::radians(1.0f); // 3 degree per unit - _actionUnitScales[YAW_RIGHT] = 1.0f;//glm::radians(1.0f); // 3 degree per unit - _actionUnitScales[PITCH_DOWN] = 1.0f;//glm::radians(1.0f); // 3 degree per unit - _actionUnitScales[PITCH_UP] = 1.0f;//glm::radians(1.0f); // 3 degree per unit - _actionUnitScales[BOOM_IN] = 1.0f; // 1m per unit - _actionUnitScales[BOOM_OUT] = 1.0f; // 1m per unit +void UserInputMapper::assignDefaulActionScales() { + _actionScales[LONGITUDINAL_BACKWARD] = 1.0f; // 1m per unit + _actionScales[LONGITUDINAL_FORWARD] = 1.0f; // 1m per unit + _actionScales[LATERAL_LEFT] = 1.0f; // 1m per unit + _actionScales[LATERAL_RIGHT] = 1.0f; // 1m per unit + _actionScales[VERTICAL_DOWN] = 1.0f; // 1m per unit + _actionScales[VERTICAL_UP] = 1.0f; // 1m per unit + _actionScales[YAW_LEFT] = 1.0f; // 1 degree per unit + _actionScales[YAW_RIGHT] = 1.0f; // 1 degree per unit + _actionScales[PITCH_DOWN] = 1.0f; // 1 degree per unit + _actionScales[PITCH_UP] = 1.0f; // 1 degree per unit + _actionScales[BOOM_IN] = 1.0f; // 1m per unit + _actionScales[BOOM_OUT] = 1.0f; // 1m per unit } diff --git a/interface/src/ui/UserInputMapper.h b/interface/src/ui/UserInputMapper.h index e1dc181299..86f7936742 100755 --- a/interface/src/ui/UserInputMapper.h +++ b/interface/src/ui/UserInputMapper.h @@ -123,7 +123,7 @@ public: }; float getActionState(Action action) const { return _actionStates[action]; } - void assignDefaulActionUnitScales(); + void assignDefaulActionScales(); // Add input channel to the mapper and check that all the used channels are registered. // Return true if theinput channel is created correctly, false either @@ -158,7 +158,7 @@ public: void update(float deltaTime); // Default contruct allocate the poutput size with the current hardcoded action channels - UserInputMapper() { assignDefaulActionUnitScales(); } + UserInputMapper() { assignDefaulActionScales(); } protected: typedef std::map DevicesMap; @@ -171,7 +171,7 @@ protected: ActionToInputsMap _actionToInputsMap; std::vector _actionStates = std::vector(NUM_ACTIONS, 0.0f); - std::vector _actionUnitScales = std::vector(NUM_ACTIONS, 1.0f); + std::vector _actionScales = std::vector(NUM_ACTIONS, 1.0f); }; @@ -228,13 +228,7 @@ public: void wheelEvent(QWheelEvent* event); - ButtonPressedMap _buttonPressedMap; - mutable AxisStateMap _axisStateMap; - - QPoint _lastCursor; - glm::vec2 _lastTouch; - bool _isTouching = false; - + // Get current state for each channels float getButton(int channel) const; float getAxis(int channel) const; @@ -253,10 +247,18 @@ public: void registerToUserInputMapper(UserInputMapper& mapper); void assignDefaultInputMapping(UserInputMapper& mapper); - void resetDeltas() { - _axisStateMap.clear(); - } + // Update call MUST be called once per simulation loop + // It takes care of updating the action states and deltas + void update(); +protected: + ButtonPressedMap _buttonPressedMap; + AxisStateMap _axisStateMap; + + QPoint _lastCursor; + glm::vec2 _lastTouch; + bool _isTouching = false; + glm::vec2 evalAverageTouchPoints(const QList& points) const; std::chrono::high_resolution_clock _clock; std::chrono::high_resolution_clock::time_point _lastTouchTime; From b7bacccce770da50e88297581eec8b9ac22dedd4 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 4 May 2015 00:54:54 -0700 Subject: [PATCH 6/9] Fine tunning on windows --- interface/src/Application.cpp | 83 +--------------------------- interface/src/ui/UserInputMapper.cpp | 27 +++++---- interface/src/ui/UserInputMapper.h | 23 ++++---- 3 files changed, 32 insertions(+), 101 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 62af97c5ae..37e213855b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1114,11 +1114,6 @@ void Application::keyPressEvent(QKeyEvent* event) { } break; - case Qt::Key_E: - case Qt::Key_PageUp: - // _myAvatar->setDriveKeys(UP, 1.0f); - break; - case Qt::Key_F: { _physicsEngine.dumpNextStats(); break; @@ -1128,16 +1123,9 @@ void Application::keyPressEvent(QKeyEvent* event) { Menu::getInstance()->triggerOption(MenuOption::Stars); break; - case Qt::Key_C: - case Qt::Key_PageDown: - // _myAvatar->setDriveKeys(DOWN, 1.0f); - break; - case Qt::Key_W: if (isOption && !isShifted && !isMeta) { Menu::getInstance()->triggerOption(MenuOption::Wireframe); - } else { - // _myAvatar->setDriveKeys(FWD, 1.0f); } break; @@ -1148,8 +1136,6 @@ void Application::keyPressEvent(QKeyEvent* event) { Menu::getInstance()->triggerOption(MenuOption::ScriptEditor); } else if (!isOption && !isShifted && isMeta) { takeSnapshot(); - } else { - // _myAvatar->setDriveKeys(BACK, 1.0f); } break; @@ -1160,14 +1146,6 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_A: if (isShifted) { Menu::getInstance()->triggerOption(MenuOption::Atmosphere); - } else if (!isMeta) { - // _myAvatar->setDriveKeys(ROT_LEFT, 1.0f); - } - break; - - case Qt::Key_D: - if (!isMeta) { - // _myAvatar->setDriveKeys(ROT_RIGHT, 1.0f); } break; @@ -1182,8 +1160,6 @@ void Application::keyPressEvent(QKeyEvent* event) { } else { _raiseMirror += 0.05f; } - } else { - // _myAvatar->setDriveKeys(isShifted ? UP : FWD, 1.0f); } break; @@ -1194,24 +1170,18 @@ void Application::keyPressEvent(QKeyEvent* event) { } else { _raiseMirror -= 0.05f; } - } else { - // _myAvatar->setDriveKeys(isShifted ? DOWN : BACK, 1.0f); } break; case Qt::Key_Left: if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { _rotateMirror += PI / 20.0f; - } else { - // _myAvatar->setDriveKeys(isShifted ? LEFT : ROT_LEFT, 1.0f); } break; case Qt::Key_Right: if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { _rotateMirror -= PI / 20.0f; - } else { - // _myAvatar->setDriveKeys(isShifted ? RIGHT : ROT_RIGHT, 1.0f); } break; @@ -1357,57 +1327,6 @@ void Application::keyReleaseEvent(QKeyEvent* event) { _keyboardMouseDevice.keyReleaseEvent(event); switch (event->key()) { - case Qt::Key_E: - case Qt::Key_PageUp: - // _myAvatar->setDriveKeys(UP, 0.0f); - break; - - case Qt::Key_C: - case Qt::Key_PageDown: - // _myAvatar->setDriveKeys(DOWN, 0.0f); - break; - - case Qt::Key_W: - // _myAvatar->setDriveKeys(FWD, 0.0f); - break; - - case Qt::Key_S: - // _myAvatar->setDriveKeys(BACK, 0.0f); - break; - - case Qt::Key_A: - // _myAvatar->setDriveKeys(ROT_LEFT, 0.0f); - break; - - case Qt::Key_D: - // _myAvatar->setDriveKeys(ROT_RIGHT, 0.0f); - break; - - case Qt::Key_Up: - // _myAvatar->setDriveKeys(FWD, 0.0f); - // _myAvatar->setDriveKeys(UP, 0.0f); - break; - - case Qt::Key_Down: - // _myAvatar->setDriveKeys(BACK, 0.0f); - // _myAvatar->setDriveKeys(DOWN, 0.0f); - break; - - case Qt::Key_Left: - // _myAvatar->setDriveKeys(LEFT, 0.0f); - // _myAvatar->setDriveKeys(ROT_LEFT, 0.0f); - break; - - case Qt::Key_Right: - // _myAvatar->setDriveKeys(RIGHT, 0.0f); - // _myAvatar->setDriveKeys(ROT_RIGHT, 0.0f); - break; - case Qt::Key_Control: - case Qt::Key_Shift: - case Qt::Key_Meta: - case Qt::Key_Alt: - // _myAvatar->clearDriveKeys(); - break; case Qt::Key_Space: { if (!event->isAutoRepeat()) { // this ends the HFActionEvent @@ -1433,6 +1352,8 @@ void Application::keyReleaseEvent(QKeyEvent* event) { } void Application::focusOutEvent(QFocusEvent* event) { + _keyboardMouseDevice.focusOutEvent(event); + // synthesize events for keys currently pressed, since we may not get their release events foreach (int key, _keysPressed) { QKeyEvent event(QEvent::KeyRelease, key, Qt::NoModifier); diff --git a/interface/src/ui/UserInputMapper.cpp b/interface/src/ui/UserInputMapper.cpp index 7c1f2f8d4b..601071a5d9 100755 --- a/interface/src/ui/UserInputMapper.cpp +++ b/interface/src/ui/UserInputMapper.cpp @@ -27,6 +27,10 @@ void KeyboardMouseDevice::update() { } } +void KeyboardMouseDevice::focusOutEvent(QFocusEvent* event) { + _buttonPressedMap.clear(); +}; + void KeyboardMouseDevice::keyPressEvent(QKeyEvent* event) { auto input = makeInput((Qt::Key) event->key()); auto result = _buttonPressedMap.insert(input.getChannel()); @@ -114,35 +118,38 @@ void KeyboardMouseDevice::touchUpdateEvent(const QTouchEvent* event) { } UserInputMapper::Input KeyboardMouseDevice::makeInput(Qt::Key code) { - return UserInputMapper::Input(DEFAULT_DESKTOP_DEVICE, code & KEYBOARD_MASK, UserInputMapper::ChannelType::BUTTON); + return UserInputMapper::Input(_deviceID, code & KEYBOARD_MASK, UserInputMapper::ChannelType::BUTTON); } UserInputMapper::Input KeyboardMouseDevice::makeInput(Qt::MouseButton code) { switch (code) { case Qt::LeftButton: - return UserInputMapper::Input(DEFAULT_DESKTOP_DEVICE, MOUSE_BUTTON_LEFT, UserInputMapper::ChannelType::BUTTON); + return UserInputMapper::Input(_deviceID, MOUSE_BUTTON_LEFT, UserInputMapper::ChannelType::BUTTON); case Qt::RightButton: - return UserInputMapper::Input(DEFAULT_DESKTOP_DEVICE, MOUSE_BUTTON_RIGHT, UserInputMapper::ChannelType::BUTTON); + return UserInputMapper::Input(_deviceID, MOUSE_BUTTON_RIGHT, UserInputMapper::ChannelType::BUTTON); case Qt::MiddleButton: - return UserInputMapper::Input(DEFAULT_DESKTOP_DEVICE, MOUSE_BUTTON_MIDDLE, UserInputMapper::ChannelType::BUTTON); + return UserInputMapper::Input(_deviceID, MOUSE_BUTTON_MIDDLE, UserInputMapper::ChannelType::BUTTON); default: return UserInputMapper::Input(); }; } UserInputMapper::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::MouseAxisChannel axis) { - return UserInputMapper::Input(DEFAULT_DESKTOP_DEVICE, axis, UserInputMapper::ChannelType::AXIS); + return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS); } UserInputMapper::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchAxisChannel axis) { - return UserInputMapper::Input(DEFAULT_DESKTOP_DEVICE, axis, UserInputMapper::ChannelType::AXIS); + return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS); } UserInputMapper::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchButtonChannel button) { - return UserInputMapper::Input(DEFAULT_DESKTOP_DEVICE, button, UserInputMapper::ChannelType::BUTTON); + return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON); } void KeyboardMouseDevice::registerToUserInputMapper(UserInputMapper& mapper) { + // Grab the current free device ID + _deviceID = mapper.getFreeDeviceID(); + auto proxy = UserInputMapper::DeviceProxy::Pointer(new UserInputMapper::DeviceProxy()); proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input._channel); }; proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input._channel); }; - mapper.registerDevice(DEFAULT_DESKTOP_DEVICE, proxy); // HARDCODED!, the KeyboardMouseDevice always take the DeviceID = 1 + mapper.registerDevice(_deviceID, proxy); } void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) { @@ -206,8 +213,8 @@ void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) { mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), TOUCH_YAW_SPEED); // Wheel move - mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(MOUSE_AXIS_WHEEL_Y_NEG), BUTTON_BOOM_SPEED); - mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(MOUSE_AXIS_WHEEL_Y_POS), BUTTON_BOOM_SPEED); + //mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(MOUSE_AXIS_WHEEL_Y_NEG), BUTTON_BOOM_SPEED); + //mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(MOUSE_AXIS_WHEEL_Y_POS), BUTTON_BOOM_SPEED); mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(MOUSE_AXIS_WHEEL_X_NEG), BUTTON_YAW_SPEED); mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(MOUSE_AXIS_WHEEL_X_POS), BUTTON_YAW_SPEED); diff --git a/interface/src/ui/UserInputMapper.h b/interface/src/ui/UserInputMapper.h index 86f7936742..dabafd5edb 100755 --- a/interface/src/ui/UserInputMapper.h +++ b/interface/src/ui/UserInputMapper.h @@ -84,7 +84,7 @@ public: typedef std::function AxisGetter; typedef std::function JointGetter; - class DeviceProxy { + class DeviceProxy { public: DeviceProxy() {} @@ -94,6 +94,8 @@ public: typedef std::shared_ptr Pointer; }; + // GetFreeDeviceID should be called before registering a device to use an ID not used by a different device. + uint16 getFreeDeviceID() { return _nextFreeDeviceID++; } bool registerDevice(uint16 deviceID, const DeviceProxy::Pointer& device); DeviceProxy::Pointer getDeviceProxy(const Input& input); @@ -163,7 +165,8 @@ public: protected: typedef std::map DevicesMap; DevicesMap _registeredDevices; - + uint16 _nextFreeDeviceID = 1; + typedef std::map InputToMoModifiersMap; InputToMoModifiersMap _inputToModifiersMap; @@ -215,6 +218,8 @@ public: typedef std::unordered_set ButtonPressedMap; typedef std::map AxisStateMap; // 8 axes + void focusOutEvent(QFocusEvent* event); + void keyPressEvent(QKeyEvent* event); void keyReleaseEvent(QKeyEvent* event); @@ -232,15 +237,12 @@ public: float getButton(int channel) const; float getAxis(int channel) const; - // Reserverd device ID for the standard keyboard and mouse - const static UserInputMapper::uint16 DEFAULT_DESKTOP_DEVICE = 1; - // Let's make it easy for Qt because we assume we love Qt forever - static UserInputMapper::Input makeInput(Qt::Key code); - static UserInputMapper::Input makeInput(Qt::MouseButton code); - static UserInputMapper::Input makeInput(KeyboardMouseDevice::MouseAxisChannel axis); - static UserInputMapper::Input makeInput(KeyboardMouseDevice::TouchAxisChannel axis); - static UserInputMapper::Input makeInput(KeyboardMouseDevice::TouchButtonChannel button); + UserInputMapper::Input makeInput(Qt::Key code); + UserInputMapper::Input makeInput(Qt::MouseButton code); + UserInputMapper::Input makeInput(KeyboardMouseDevice::MouseAxisChannel axis); + UserInputMapper::Input makeInput(KeyboardMouseDevice::TouchAxisChannel axis); + UserInputMapper::Input makeInput(KeyboardMouseDevice::TouchButtonChannel button); KeyboardMouseDevice() {} @@ -255,6 +257,7 @@ protected: ButtonPressedMap _buttonPressedMap; AxisStateMap _axisStateMap; + int _deviceID = 0; QPoint _lastCursor; glm::vec2 _lastTouch; bool _isTouching = false; From 3921156978061ad3ed71de84403cab4206eeccc3 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 4 May 2015 01:09:25 -0700 Subject: [PATCH 7/9] fix end of line --- interface/src/ui/UserInputMapper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/UserInputMapper.h b/interface/src/ui/UserInputMapper.h index dabafd5edb..6546645640 100755 --- a/interface/src/ui/UserInputMapper.h +++ b/interface/src/ui/UserInputMapper.h @@ -267,4 +267,4 @@ protected: std::chrono::high_resolution_clock::time_point _lastTouchTime; }; -#endif // hifi_UserInputMapper_h \ No newline at end of file +#endif // hifi_UserInputMapper_h From c7153bcc14b69e67d0b5c0ee91f1e13e952d5643 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 4 May 2015 10:40:11 -0700 Subject: [PATCH 8/9] fixing commetns from review --- interface/src/Application.cpp | 6 +- interface/src/Application.h | 1 + interface/src/ui/UserInputMapper.cpp | 230 --------------------------- interface/src/ui/UserInputMapper.h | 92 ----------- 4 files changed, 3 insertions(+), 326 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 37e213855b..c6d8fe7c9b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1414,10 +1414,9 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { if (activeWindow() == _window) { - _keyboardMouseDevice.mousePressEvent(event); - if (event->button() == Qt::LeftButton) { + if (event->button() == Qt::LeftButton) { _mouseDragStartedX = getTrueMouseX(); _mouseDragStartedY = getTrueMouseY(); _mousePressed = true; @@ -1458,9 +1457,8 @@ void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { return; } - _keyboardMouseDevice.mouseReleaseEvent(event); - if (activeWindow() == _window) { + _keyboardMouseDevice.mouseReleaseEvent(event); if (event->button() == Qt::LeftButton) { _mousePressed = false; diff --git a/interface/src/Application.h b/interface/src/Application.h index 60a5fbf929..7ae96de193 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -70,6 +70,7 @@ #include "ui/RunningScriptsWidget.h" #include "ui/ToolWindow.h" #include "ui/UserInputMapper.h" +#include "devices/KeyboardMouseDevice.h" #include "octree/OctreeFade.h" #include "octree/OctreePacketProcessor.h" #include "UndoStackScriptingInterface.h" diff --git a/interface/src/ui/UserInputMapper.cpp b/interface/src/ui/UserInputMapper.cpp index 601071a5d9..c1f9577efe 100755 --- a/interface/src/ui/UserInputMapper.cpp +++ b/interface/src/ui/UserInputMapper.cpp @@ -11,236 +11,6 @@ #include "UserInputMapper.h" #include -void KeyboardMouseDevice::update() { - _axisStateMap.clear(); - - // For touch event, we need to check that the last event is not too long ago - // Maybe it's a Qt issue, but the touch event sequence (begin, update, end) is not always called properly - // The following is a workaround to detect that the touch sequence is over in case we didn;t see the end event - if (_isTouching) { - const auto TOUCH_EVENT_MAXIMUM_WAIT = 100; //ms - auto currentTime = _clock.now(); - auto sinceLastTouch = std::chrono::duration_cast(currentTime - _lastTouchTime); - if (sinceLastTouch.count() > TOUCH_EVENT_MAXIMUM_WAIT) { - _isTouching = false; - } - } -} - -void KeyboardMouseDevice::focusOutEvent(QFocusEvent* event) { - _buttonPressedMap.clear(); -}; - -void KeyboardMouseDevice::keyPressEvent(QKeyEvent* event) { - auto input = makeInput((Qt::Key) event->key()); - auto result = _buttonPressedMap.insert(input.getChannel()); - if (!result.second) { - // key pressed again ? without catching the release event ? - } -} -void KeyboardMouseDevice::keyReleaseEvent(QKeyEvent* event) { - auto input = makeInput((Qt::Key) event->key()); - _buttonPressedMap.erase(input.getChannel()); -} - -void KeyboardMouseDevice::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { - auto input = makeInput((Qt::MouseButton) event->button()); - auto result = _buttonPressedMap.insert(input.getChannel()); - if (!result.second) { - // key pressed again ? without catching the release event ? - } - _lastCursor = event->pos(); -} -void KeyboardMouseDevice::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { - auto input = makeInput((Qt::MouseButton) event->button()); - _buttonPressedMap.erase(input.getChannel()); -} -void KeyboardMouseDevice::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { - QPoint currentPos = event->pos(); - QPoint currentMove = currentPos - _lastCursor; - - _axisStateMap[makeInput(MOUSE_AXIS_X_POS).getChannel()] = (currentMove.x() > 0 ? currentMove.x() : 0.0f); - _axisStateMap[makeInput(MOUSE_AXIS_X_NEG).getChannel()] = (currentMove.x() < 0 ? -currentMove.x() : 0.0f); - // Y mouse is inverted positive is pointing up the screen - _axisStateMap[makeInput(MOUSE_AXIS_Y_POS).getChannel()] = (currentMove.y() < 0 ? -currentMove.y() : 0.0f); - _axisStateMap[makeInput(MOUSE_AXIS_Y_NEG).getChannel()] = (currentMove.y() > 0 ? currentMove.y() : 0.0f); - - _lastCursor = currentPos; -} -void KeyboardMouseDevice::wheelEvent(QWheelEvent* event) { - auto currentMove = event->angleDelta() / 120.0f; - - _axisStateMap[makeInput(MOUSE_AXIS_WHEEL_X_POS).getChannel()] = (currentMove.x() > 0 ? currentMove.x() : 0.0f); - _axisStateMap[makeInput(MOUSE_AXIS_WHEEL_X_NEG).getChannel()] = (currentMove.x() < 0 ? -currentMove.x() : 0.0f); - _axisStateMap[makeInput(MOUSE_AXIS_WHEEL_Y_POS).getChannel()] = (currentMove.y() > 0 ? currentMove.y() : 0.0f); - _axisStateMap[makeInput(MOUSE_AXIS_WHEEL_Y_NEG).getChannel()] = (currentMove.y() < 0 ? -currentMove.y() : 0.0f); -} - -glm::vec2 KeyboardMouseDevice::evalAverageTouchPoints(const QList& points) const { - glm::vec2 averagePoint(0.0f); - if (points.count() > 0) { - for (auto& point : points) { - averagePoint += glm::vec2(point.pos().x(), point.pos().y()); - } - averagePoint /= (float)(points.count()); - } - return averagePoint; -} - - -void KeyboardMouseDevice::touchBeginEvent(const QTouchEvent* event) { - _isTouching = event->touchPointStates().testFlag(Qt::TouchPointPressed); - _lastTouch = evalAverageTouchPoints(event->touchPoints()); - _lastTouchTime = _clock.now(); -} -void KeyboardMouseDevice::touchEndEvent(const QTouchEvent* event) { - _isTouching = false; - _lastTouch = evalAverageTouchPoints(event->touchPoints()); - _lastTouchTime = _clock.now(); -} -void KeyboardMouseDevice::touchUpdateEvent(const QTouchEvent* event) { - auto currentPos = evalAverageTouchPoints(event->touchPoints()); - _lastTouchTime = _clock.now(); - - if (!_isTouching) { - _isTouching = event->touchPointStates().testFlag(Qt::TouchPointPressed); - } else { - auto currentMove = currentPos - _lastTouch; - - _axisStateMap[makeInput(TOUCH_AXIS_X_POS).getChannel()] = (currentMove.x > 0 ? currentMove.x : 0.0f); - _axisStateMap[makeInput(TOUCH_AXIS_X_NEG).getChannel()] = (currentMove.x < 0 ? -currentMove.x : 0.0f); - // Y mouse is inverted positive is pointing up the screen - _axisStateMap[makeInput(TOUCH_AXIS_Y_POS).getChannel()] = (currentMove.y < 0 ? -currentMove.y : 0.0f); - _axisStateMap[makeInput(TOUCH_AXIS_Y_NEG).getChannel()] = (currentMove.y > 0 ? currentMove.y : 0.0f); - } - - _lastTouch = currentPos; -} - -UserInputMapper::Input KeyboardMouseDevice::makeInput(Qt::Key code) { - return UserInputMapper::Input(_deviceID, code & KEYBOARD_MASK, UserInputMapper::ChannelType::BUTTON); -} -UserInputMapper::Input KeyboardMouseDevice::makeInput(Qt::MouseButton code) { - switch (code) { - case Qt::LeftButton: - return UserInputMapper::Input(_deviceID, MOUSE_BUTTON_LEFT, UserInputMapper::ChannelType::BUTTON); - case Qt::RightButton: - return UserInputMapper::Input(_deviceID, MOUSE_BUTTON_RIGHT, UserInputMapper::ChannelType::BUTTON); - case Qt::MiddleButton: - return UserInputMapper::Input(_deviceID, MOUSE_BUTTON_MIDDLE, UserInputMapper::ChannelType::BUTTON); - default: - return UserInputMapper::Input(); - }; -} -UserInputMapper::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::MouseAxisChannel axis) { - return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS); -} -UserInputMapper::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchAxisChannel axis) { - return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS); -} -UserInputMapper::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchButtonChannel button) { - return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON); -} - -void KeyboardMouseDevice::registerToUserInputMapper(UserInputMapper& mapper) { - // Grab the current free device ID - _deviceID = mapper.getFreeDeviceID(); - - auto proxy = UserInputMapper::DeviceProxy::Pointer(new UserInputMapper::DeviceProxy()); - proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input._channel); }; - proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input._channel); }; - mapper.registerDevice(_deviceID, proxy); -} - -void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) { - const float BUTTON_MOVE_SPEED = 1.0f; - const float BUTTON_YAW_SPEED = 0.75f; - const float BUTTON_PITCH_SPEED = 0.5f; - const float MOUSE_YAW_SPEED = 0.5f; - const float MOUSE_PITCH_SPEED = 0.25f; - const float TOUCH_YAW_SPEED = 0.5f; - const float TOUCH_PITCH_SPEED = 0.25f; - //const float BUTTON_BOOM_SPEED = 0.1f; - - // AWSD keys mapping - mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(Qt::Key_S), BUTTON_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(Qt::Key_W), BUTTON_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(Qt::Key_A), BUTTON_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(Qt::Key_D), BUTTON_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(Qt::Key_C), BUTTON_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(Qt::Key_E), BUTTON_MOVE_SPEED); - - // mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(Qt::Key_W), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); - // mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(Qt::Key_S), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(Qt::Key_A), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(Qt::Key_D), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(Qt::Key_C), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(Qt::Key_E), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED); - - // Arrow keys mapping - mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(Qt::Key_Down), BUTTON_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(Qt::Key_Up), BUTTON_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(Qt::Key_Left), BUTTON_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(Qt::Key_Right), BUTTON_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(Qt::Key_PageDown), BUTTON_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(Qt::Key_PageUp), BUTTON_MOVE_SPEED); - - // mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(Qt::Key_Up), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); - // mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(Qt::Key_Down), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(Qt::Key_Down), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(Qt::Key_Up), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED); - - // Mouse move - mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(MOUSE_AXIS_Y_NEG), makeInput(Qt::RightButton), MOUSE_PITCH_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(MOUSE_AXIS_Y_POS), makeInput(Qt::RightButton), MOUSE_PITCH_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(MOUSE_AXIS_X_NEG), makeInput(Qt::RightButton), MOUSE_YAW_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(MOUSE_AXIS_X_POS), makeInput(Qt::RightButton), MOUSE_YAW_SPEED); - - -#ifdef Q_OS_MAC - // wheel event modifier on Mac collide with the touchpad scroll event - mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), TOUCH_PITCH_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), TOUCH_PITCH_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), TOUCH_YAW_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), TOUCH_YAW_SPEED); -#else - // Touch pad yaw pitch - mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), TOUCH_PITCH_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), TOUCH_PITCH_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), TOUCH_YAW_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), TOUCH_YAW_SPEED); - - // Wheel move - //mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(MOUSE_AXIS_WHEEL_Y_NEG), BUTTON_BOOM_SPEED); - //mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(MOUSE_AXIS_WHEEL_Y_POS), BUTTON_BOOM_SPEED); - mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(MOUSE_AXIS_WHEEL_X_NEG), BUTTON_YAW_SPEED); - mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(MOUSE_AXIS_WHEEL_X_POS), BUTTON_YAW_SPEED); - -#endif - -} - -float KeyboardMouseDevice::getButton(int channel) const { - if (!_buttonPressedMap.empty()) { - if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) { - return 1.0f; - } else { - return 0.0f; - } - } - return 0.0f; -} -float KeyboardMouseDevice::getAxis(int channel) const { - auto axis = _axisStateMap.find(channel); - if (axis != _axisStateMap.end()) { - return (*axis).second; - } else { - return 0.0f; - } -} - // UserInputMapper Class bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy){ diff --git a/interface/src/ui/UserInputMapper.h b/interface/src/ui/UserInputMapper.h index 6546645640..32a1782419 100755 --- a/interface/src/ui/UserInputMapper.h +++ b/interface/src/ui/UserInputMapper.h @@ -12,14 +12,12 @@ #ifndef hifi_UserInputMapper_h #define hifi_UserInputMapper_h -#include #include #include #include #include #include -#include class UserInputMapper : public QObject { Q_OBJECT @@ -177,94 +175,4 @@ protected: std::vector _actionScales = std::vector(NUM_ACTIONS, 1.0f); }; - -class KeyboardMouseDevice { -public: - - enum KeyboardChannel { - KEYBOARD_FIRST = 0, - KEYBOARD_LAST = 255, - KEYBOARD_MASK = 0x00FF, - }; - - enum MouseButtonChannel { - MOUSE_BUTTON_LEFT = KEYBOARD_LAST + 1, - MOUSE_BUTTON_RIGHT, - MOUSE_BUTTON_MIDDLE, - }; - - enum MouseAxisChannel { - MOUSE_AXIS_X_POS = MOUSE_BUTTON_MIDDLE + 1, - MOUSE_AXIS_X_NEG, - MOUSE_AXIS_Y_POS, - MOUSE_AXIS_Y_NEG, - MOUSE_AXIS_WHEEL_Y_POS, - MOUSE_AXIS_WHEEL_Y_NEG, - MOUSE_AXIS_WHEEL_X_POS, - MOUSE_AXIS_WHEEL_X_NEG, - }; - - enum TouchAxisChannel { - TOUCH_AXIS_X_POS = MOUSE_AXIS_WHEEL_X_NEG + 1, - TOUCH_AXIS_X_NEG, - TOUCH_AXIS_Y_POS, - TOUCH_AXIS_Y_NEG, - }; - - enum TouchButtonChannel { - TOUCH_BUTTON_PRESS = TOUCH_AXIS_Y_NEG + 1, - }; - - typedef std::unordered_set ButtonPressedMap; - typedef std::map AxisStateMap; // 8 axes - - void focusOutEvent(QFocusEvent* event); - - void keyPressEvent(QKeyEvent* event); - void keyReleaseEvent(QKeyEvent* event); - - void mouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0); - void mousePressEvent(QMouseEvent* event, unsigned int deviceID = 0); - void mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0); - - void touchBeginEvent(const QTouchEvent* event); - void touchEndEvent(const QTouchEvent* event); - void touchUpdateEvent(const QTouchEvent* event); - - void wheelEvent(QWheelEvent* event); - - // Get current state for each channels - float getButton(int channel) const; - float getAxis(int channel) const; - - // Let's make it easy for Qt because we assume we love Qt forever - UserInputMapper::Input makeInput(Qt::Key code); - UserInputMapper::Input makeInput(Qt::MouseButton code); - UserInputMapper::Input makeInput(KeyboardMouseDevice::MouseAxisChannel axis); - UserInputMapper::Input makeInput(KeyboardMouseDevice::TouchAxisChannel axis); - UserInputMapper::Input makeInput(KeyboardMouseDevice::TouchButtonChannel button); - - KeyboardMouseDevice() {} - - void registerToUserInputMapper(UserInputMapper& mapper); - void assignDefaultInputMapping(UserInputMapper& mapper); - - // Update call MUST be called once per simulation loop - // It takes care of updating the action states and deltas - void update(); - -protected: - ButtonPressedMap _buttonPressedMap; - AxisStateMap _axisStateMap; - - int _deviceID = 0; - QPoint _lastCursor; - glm::vec2 _lastTouch; - bool _isTouching = false; - - glm::vec2 evalAverageTouchPoints(const QList& points) const; - std::chrono::high_resolution_clock _clock; - std::chrono::high_resolution_clock::time_point _lastTouchTime; -}; - #endif // hifi_UserInputMapper_h From fad623ae48c2da5a9d9098dde925480c03658f1e Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 4 May 2015 10:47:33 -0700 Subject: [PATCH 9/9] ANd really add the 2 files we need --- interface/src/devices/KeyboardMouseDevice.cpp | 253 ++++++++++++++++++ interface/src/devices/KeyboardMouseDevice.h | 108 ++++++++ interface/src/ui/UserInputMapper.cpp | 2 +- 3 files changed, 362 insertions(+), 1 deletion(-) create mode 100755 interface/src/devices/KeyboardMouseDevice.cpp create mode 100755 interface/src/devices/KeyboardMouseDevice.h diff --git a/interface/src/devices/KeyboardMouseDevice.cpp b/interface/src/devices/KeyboardMouseDevice.cpp new file mode 100755 index 0000000000..94994462c3 --- /dev/null +++ b/interface/src/devices/KeyboardMouseDevice.cpp @@ -0,0 +1,253 @@ + +// +// KeyboardMouseDevice.cpp +// interface/src/devices +// +// Created by Sam Gateau on 4/27/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 "KeyboardMouseDevice.h" + +void KeyboardMouseDevice::update() { + _axisStateMap.clear(); + + // For touch event, we need to check that the last event is not too long ago + // Maybe it's a Qt issue, but the touch event sequence (begin, update, end) is not always called properly + // The following is a workaround to detect that the touch sequence is over in case we didn;t see the end event + if (_isTouching) { + const auto TOUCH_EVENT_MAXIMUM_WAIT = 100; //ms + auto currentTime = _clock.now(); + auto sinceLastTouch = std::chrono::duration_cast(currentTime - _lastTouchTime); + if (sinceLastTouch.count() > TOUCH_EVENT_MAXIMUM_WAIT) { + _isTouching = false; + } + } +} + +void KeyboardMouseDevice::focusOutEvent(QFocusEvent* event) { + _buttonPressedMap.clear(); +}; + +void KeyboardMouseDevice::keyPressEvent(QKeyEvent* event) { + auto input = makeInput((Qt::Key) event->key()); + auto result = _buttonPressedMap.insert(input.getChannel()); + if (!result.second) { + // key pressed again ? without catching the release event ? + } +} + +void KeyboardMouseDevice::keyReleaseEvent(QKeyEvent* event) { + auto input = makeInput((Qt::Key) event->key()); + _buttonPressedMap.erase(input.getChannel()); +} + +void KeyboardMouseDevice::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { + auto input = makeInput((Qt::MouseButton) event->button()); + auto result = _buttonPressedMap.insert(input.getChannel()); + if (!result.second) { + // key pressed again ? without catching the release event ? + } + _lastCursor = event->pos(); +} + +void KeyboardMouseDevice::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { + auto input = makeInput((Qt::MouseButton) event->button()); + _buttonPressedMap.erase(input.getChannel()); +} + +void KeyboardMouseDevice::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { + QPoint currentPos = event->pos(); + QPoint currentMove = currentPos - _lastCursor; + + _axisStateMap[makeInput(MOUSE_AXIS_X_POS).getChannel()] = (currentMove.x() > 0 ? currentMove.x() : 0.0f); + _axisStateMap[makeInput(MOUSE_AXIS_X_NEG).getChannel()] = (currentMove.x() < 0 ? -currentMove.x() : 0.0f); + // Y mouse is inverted positive is pointing up the screen + _axisStateMap[makeInput(MOUSE_AXIS_Y_POS).getChannel()] = (currentMove.y() < 0 ? -currentMove.y() : 0.0f); + _axisStateMap[makeInput(MOUSE_AXIS_Y_NEG).getChannel()] = (currentMove.y() > 0 ? currentMove.y() : 0.0f); + + _lastCursor = currentPos; +} + +void KeyboardMouseDevice::wheelEvent(QWheelEvent* event) { + auto currentMove = event->angleDelta() / 120.0f; + + _axisStateMap[makeInput(MOUSE_AXIS_WHEEL_X_POS).getChannel()] = (currentMove.x() > 0 ? currentMove.x() : 0.0f); + _axisStateMap[makeInput(MOUSE_AXIS_WHEEL_X_NEG).getChannel()] = (currentMove.x() < 0 ? -currentMove.x() : 0.0f); + _axisStateMap[makeInput(MOUSE_AXIS_WHEEL_Y_POS).getChannel()] = (currentMove.y() > 0 ? currentMove.y() : 0.0f); + _axisStateMap[makeInput(MOUSE_AXIS_WHEEL_Y_NEG).getChannel()] = (currentMove.y() < 0 ? -currentMove.y() : 0.0f); +} + +glm::vec2 KeyboardMouseDevice::evalAverageTouchPoints(const QList& points) const { + glm::vec2 averagePoint(0.0f); + if (points.count() > 0) { + for (auto& point : points) { + averagePoint += glm::vec2(point.pos().x(), point.pos().y()); + } + averagePoint /= (float)(points.count()); + } + return averagePoint; +} + +void KeyboardMouseDevice::touchBeginEvent(const QTouchEvent* event) { + _isTouching = event->touchPointStates().testFlag(Qt::TouchPointPressed); + _lastTouch = evalAverageTouchPoints(event->touchPoints()); + _lastTouchTime = _clock.now(); +} + +void KeyboardMouseDevice::touchEndEvent(const QTouchEvent* event) { + _isTouching = false; + _lastTouch = evalAverageTouchPoints(event->touchPoints()); + _lastTouchTime = _clock.now(); +} + +void KeyboardMouseDevice::touchUpdateEvent(const QTouchEvent* event) { + auto currentPos = evalAverageTouchPoints(event->touchPoints()); + _lastTouchTime = _clock.now(); + + if (!_isTouching) { + _isTouching = event->touchPointStates().testFlag(Qt::TouchPointPressed); + } else { + auto currentMove = currentPos - _lastTouch; + + _axisStateMap[makeInput(TOUCH_AXIS_X_POS).getChannel()] = (currentMove.x > 0 ? currentMove.x : 0.0f); + _axisStateMap[makeInput(TOUCH_AXIS_X_NEG).getChannel()] = (currentMove.x < 0 ? -currentMove.x : 0.0f); + // Y mouse is inverted positive is pointing up the screen + _axisStateMap[makeInput(TOUCH_AXIS_Y_POS).getChannel()] = (currentMove.y < 0 ? -currentMove.y : 0.0f); + _axisStateMap[makeInput(TOUCH_AXIS_Y_NEG).getChannel()] = (currentMove.y > 0 ? currentMove.y : 0.0f); + } + + _lastTouch = currentPos; +} + +UserInputMapper::Input KeyboardMouseDevice::makeInput(Qt::Key code) { + return UserInputMapper::Input(_deviceID, code & KEYBOARD_MASK, UserInputMapper::ChannelType::BUTTON); +} + +UserInputMapper::Input KeyboardMouseDevice::makeInput(Qt::MouseButton code) { + switch (code) { + case Qt::LeftButton: + return UserInputMapper::Input(_deviceID, MOUSE_BUTTON_LEFT, UserInputMapper::ChannelType::BUTTON); + case Qt::RightButton: + return UserInputMapper::Input(_deviceID, MOUSE_BUTTON_RIGHT, UserInputMapper::ChannelType::BUTTON); + case Qt::MiddleButton: + return UserInputMapper::Input(_deviceID, MOUSE_BUTTON_MIDDLE, UserInputMapper::ChannelType::BUTTON); + default: + return UserInputMapper::Input(); + }; +} + +UserInputMapper::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::MouseAxisChannel axis) { + return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS); +} + +UserInputMapper::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchAxisChannel axis) { + return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS); +} + +UserInputMapper::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchButtonChannel button) { + return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON); +} + +void KeyboardMouseDevice::registerToUserInputMapper(UserInputMapper& mapper) { + // Grab the current free device ID + _deviceID = mapper.getFreeDeviceID(); + + auto proxy = UserInputMapper::DeviceProxy::Pointer(new UserInputMapper::DeviceProxy()); + proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input._channel); }; + proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input._channel); }; + mapper.registerDevice(_deviceID, proxy); +} + +void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) { + const float BUTTON_MOVE_SPEED = 1.0f; + const float BUTTON_YAW_SPEED = 0.75f; + const float BUTTON_PITCH_SPEED = 0.5f; + const float MOUSE_YAW_SPEED = 0.5f; + const float MOUSE_PITCH_SPEED = 0.25f; + const float TOUCH_YAW_SPEED = 0.5f; + const float TOUCH_PITCH_SPEED = 0.25f; + //const float BUTTON_BOOM_SPEED = 0.1f; + + // AWSD keys mapping + mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(Qt::Key_S), BUTTON_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(Qt::Key_W), BUTTON_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(Qt::Key_A), BUTTON_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(Qt::Key_D), BUTTON_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(Qt::Key_C), BUTTON_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(Qt::Key_E), BUTTON_MOVE_SPEED); + + // mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(Qt::Key_W), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); + // mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(Qt::Key_S), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(Qt::Key_A), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(Qt::Key_D), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(Qt::Key_C), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(Qt::Key_E), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED); + + // Arrow keys mapping + mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(Qt::Key_Down), BUTTON_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(Qt::Key_Up), BUTTON_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(Qt::Key_Left), BUTTON_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(Qt::Key_Right), BUTTON_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(Qt::Key_PageDown), BUTTON_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(Qt::Key_PageUp), BUTTON_MOVE_SPEED); + + // mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(Qt::Key_Up), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); + // mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(Qt::Key_Down), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(Qt::Key_Down), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(Qt::Key_Up), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED); + + // Mouse move + mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(MOUSE_AXIS_Y_NEG), makeInput(Qt::RightButton), MOUSE_PITCH_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(MOUSE_AXIS_Y_POS), makeInput(Qt::RightButton), MOUSE_PITCH_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(MOUSE_AXIS_X_NEG), makeInput(Qt::RightButton), MOUSE_YAW_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(MOUSE_AXIS_X_POS), makeInput(Qt::RightButton), MOUSE_YAW_SPEED); + + +#ifdef Q_OS_MAC + // wheel event modifier on Mac collide with the touchpad scroll event + mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), TOUCH_PITCH_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), TOUCH_PITCH_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), TOUCH_YAW_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), TOUCH_YAW_SPEED); +#else + // Touch pad yaw pitch + mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), TOUCH_PITCH_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), TOUCH_PITCH_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), TOUCH_YAW_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), TOUCH_YAW_SPEED); + + // Wheel move + //mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(MOUSE_AXIS_WHEEL_Y_NEG), BUTTON_BOOM_SPEED); + //mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(MOUSE_AXIS_WHEEL_Y_POS), BUTTON_BOOM_SPEED); + mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(MOUSE_AXIS_WHEEL_X_NEG), BUTTON_YAW_SPEED); + mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(MOUSE_AXIS_WHEEL_X_POS), BUTTON_YAW_SPEED); + +#endif + +} + +float KeyboardMouseDevice::getButton(int channel) const { + if (!_buttonPressedMap.empty()) { + if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) { + return 1.0f; + } else { + return 0.0f; + } + } + return 0.0f; +} + +float KeyboardMouseDevice::getAxis(int channel) const { + auto axis = _axisStateMap.find(channel); + if (axis != _axisStateMap.end()) { + return (*axis).second; + } else { + return 0.0f; + } +} + diff --git a/interface/src/devices/KeyboardMouseDevice.h b/interface/src/devices/KeyboardMouseDevice.h new file mode 100755 index 0000000000..ce044b2a13 --- /dev/null +++ b/interface/src/devices/KeyboardMouseDevice.h @@ -0,0 +1,108 @@ +// +// KeyboardMouseDevice.h +// interface/src/devices +// +// Created by Sam Gateau on 4/27/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_KeyboardMouseDevice_h +#define hifi_KeyboardMouseDevice_h + +#include +#include +#include "ui/UserInputMapper.h" + +class KeyboardMouseDevice { +public: + + enum KeyboardChannel { + KEYBOARD_FIRST = 0, + KEYBOARD_LAST = 255, + KEYBOARD_MASK = 0x00FF, + }; + + enum MouseButtonChannel { + MOUSE_BUTTON_LEFT = KEYBOARD_LAST + 1, + MOUSE_BUTTON_RIGHT, + MOUSE_BUTTON_MIDDLE, + }; + + enum MouseAxisChannel { + MOUSE_AXIS_X_POS = MOUSE_BUTTON_MIDDLE + 1, + MOUSE_AXIS_X_NEG, + MOUSE_AXIS_Y_POS, + MOUSE_AXIS_Y_NEG, + MOUSE_AXIS_WHEEL_Y_POS, + MOUSE_AXIS_WHEEL_Y_NEG, + MOUSE_AXIS_WHEEL_X_POS, + MOUSE_AXIS_WHEEL_X_NEG, + }; + + enum TouchAxisChannel { + TOUCH_AXIS_X_POS = MOUSE_AXIS_WHEEL_X_NEG + 1, + TOUCH_AXIS_X_NEG, + TOUCH_AXIS_Y_POS, + TOUCH_AXIS_Y_NEG, + }; + + enum TouchButtonChannel { + TOUCH_BUTTON_PRESS = TOUCH_AXIS_Y_NEG + 1, + }; + + typedef std::unordered_set ButtonPressedMap; + typedef std::map AxisStateMap; // 8 axes + + void focusOutEvent(QFocusEvent* event); + + void keyPressEvent(QKeyEvent* event); + void keyReleaseEvent(QKeyEvent* event); + + void mouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0); + void mousePressEvent(QMouseEvent* event, unsigned int deviceID = 0); + void mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0); + + void touchBeginEvent(const QTouchEvent* event); + void touchEndEvent(const QTouchEvent* event); + void touchUpdateEvent(const QTouchEvent* event); + + void wheelEvent(QWheelEvent* event); + + // Get current state for each channels + float getButton(int channel) const; + float getAxis(int channel) const; + + // Let's make it easy for Qt because we assume we love Qt forever + UserInputMapper::Input makeInput(Qt::Key code); + UserInputMapper::Input makeInput(Qt::MouseButton code); + UserInputMapper::Input makeInput(KeyboardMouseDevice::MouseAxisChannel axis); + UserInputMapper::Input makeInput(KeyboardMouseDevice::TouchAxisChannel axis); + UserInputMapper::Input makeInput(KeyboardMouseDevice::TouchButtonChannel button); + + KeyboardMouseDevice() {} + + void registerToUserInputMapper(UserInputMapper& mapper); + void assignDefaultInputMapping(UserInputMapper& mapper); + + // Update call MUST be called once per simulation loop + // It takes care of updating the action states and deltas + void update(); + +protected: + ButtonPressedMap _buttonPressedMap; + AxisStateMap _axisStateMap; + + int _deviceID = 0; + QPoint _lastCursor; + glm::vec2 _lastTouch; + bool _isTouching = false; + + glm::vec2 evalAverageTouchPoints(const QList& points) const; + std::chrono::high_resolution_clock _clock; + std::chrono::high_resolution_clock::time_point _lastTouchTime; +}; + +#endif // hifi_KeyboardMouseDevice_h diff --git a/interface/src/ui/UserInputMapper.cpp b/interface/src/ui/UserInputMapper.cpp index c1f9577efe..892ab6a9b6 100755 --- a/interface/src/ui/UserInputMapper.cpp +++ b/interface/src/ui/UserInputMapper.cpp @@ -26,6 +26,7 @@ UserInputMapper::DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Inpu return DeviceProxy::Pointer(); } } + bool UserInputMapper::addInputChannel(Action action, const Input& input, float scale) { return addInputChannel(action, input, Input(), scale); } @@ -129,7 +130,6 @@ void UserInputMapper::update(float deltaTime) { } } - void UserInputMapper::assignDefaulActionScales() { _actionScales[LONGITUDINAL_BACKWARD] = 1.0f; // 1m per unit _actionScales[LONGITUDINAL_FORWARD] = 1.0f; // 1m per unit