From 8b8b99c7e02817d67bd2d7f2c5ade098814a9467 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 17 Feb 2016 21:19:01 -0800 Subject: [PATCH] HMD mouse checkpoint --- interface/src/Application.cpp | 107 +++++++++++++----- interface/src/Application.h | 15 ++- .../ControllerScriptingInterface.cpp | 8 +- .../scripting/ControllerScriptingInterface.h | 16 +-- interface/src/ui/ApplicationCompositor.cpp | 94 ++++++++++++++- interface/src/ui/ApplicationCompositor.h | 35 +++--- .../src/EntityTreeRenderer.cpp | 64 +++++------ .../src/EntityTreeRenderer.h | 14 +-- .../src/RenderableWebEntityItem.cpp | 2 +- .../src/input-plugins/KeyboardMouseDevice.cpp | 6 +- .../src/input-plugins/KeyboardMouseDevice.h | 6 +- libraries/script-engine/src/MouseEvent.cpp | 4 +- libraries/script-engine/src/MouseEvent.h | 3 +- 13 files changed, 260 insertions(+), 114 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 144f8ad405..9235f20a89 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -786,8 +786,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : } if (action == controller::toInt(controller::Action::RETICLE_CLICK)) { - auto globalPos = QCursor::pos(); - auto localPos = _glWidget->mapFromGlobal(globalPos); + auto reticlePos = _compositor.getReticlePosition(); + QPoint globalPos(reticlePos.x, reticlePos.y); + + // FIXME - it would be nice if this was self contained in the _compositor or Reticle class + auto localPos = isHMDMode() ? globalPos : _glWidget->mapFromGlobal(globalPos); if (state) { QMouseEvent mousePress(QEvent::MouseButtonPress, localPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); sendEvent(_glWidget, &mousePress); @@ -809,9 +812,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : auto reticlePosition = _compositor.getReticlePosition(); offscreenUi->toggleMenu(_glWidget->mapFromGlobal(QPoint(reticlePosition.x, reticlePosition.y))); } else if (action == controller::toInt(controller::Action::RETICLE_X)) { + qDebug() << "Action::RETICLE_X..."; auto oldPos = _compositor.getReticlePosition(); _compositor.setReticlePosition({ oldPos.x + state, oldPos.y }); } else if (action == controller::toInt(controller::Action::RETICLE_Y)) { + qDebug() << "Action::RETICLE_Y..."; auto oldPos = _compositor.getReticlePosition(); _compositor.setReticlePosition({ oldPos.x, oldPos.y + state }); } @@ -955,7 +960,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : // If the user clicks somewhere where there is NO entity at all, we will release focus connect(getEntities(), &EntityTreeRenderer::mousePressOffEntity, - [=](const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId) { + [=](const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event) { _keyboardFocusedItem = UNKNOWN_ENTITY_ID; if (_keyboardFocusHighlight) { _keyboardFocusHighlight->setVisible(false); @@ -1261,7 +1266,8 @@ void Application::initializeUi() { QPointF result = pt; auto displayPlugin = getActiveDisplayPlugin(); if (displayPlugin->isHmd()) { - auto resultVec = _compositor.screenToOverlay(toGlm(pt)); + auto fakeScreen = _compositor.getReticlePosition(); + auto resultVec = _compositor.screenToOverlay(fakeScreen); // toGlm(pt)); result = QPointF(resultVec.x, resultVec.y); } return result.toPoint(); @@ -1736,6 +1742,7 @@ bool Application::event(QEvent* event) { switch (event->type()) { case QEvent::MouseMove: + qDebug() << __FUNCTION__ << "(QEvent::MouseMove)... line:" << __LINE__; mouseMoveEvent((QMouseEvent*)event); return true; case QEvent::MouseButtonPress: @@ -1772,6 +1779,9 @@ bool Application::event(QEvent* event) { case QEvent::Drop: dropEvent(static_cast(event)); return true; + case QEvent::Leave: + qDebug() << __FUNCTION__ << "().... QEvent::Leave"; + break; // fall through default: break; } @@ -1800,6 +1810,12 @@ bool Application::event(QEvent* event) { } bool Application::eventFilter(QObject* object, QEvent* event) { + + if (event->type() == QEvent::Leave) { + qDebug() << __FUNCTION__ << "().... QEvent::Leave"; + _compositor.handleLeaveEvent(); + } + if (event->type() == QEvent::ShortcutOverride) { if (DependencyManager::get()->shouldSwallowShortcut(event)) { event->accept(); @@ -2152,13 +2168,7 @@ void Application::focusOutEvent(QFocusEvent* event) { _keysPressed.clear(); } -void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { - PROFILE_RANGE(__FUNCTION__); - - if (_aboutToQuit) { - return; - } - +void Application::maybeToggleMenuVisible(QMouseEvent* event) { #ifndef Q_OS_MAC // If in full screen, and our main windows menu bar is hidden, and we're close to the top of the QMainWindow // then show the menubar. @@ -2170,7 +2180,7 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { if (event->pos().y() <= MENU_TOGGLE_AREA) { menuBar->setVisible(true); } - } else { + } else { if (event->pos().y() > MENU_TOGGLE_AREA) { menuBar->setVisible(false); } @@ -2178,9 +2188,38 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { } } #endif +} + +/// called by ApplicationCompositor when in HMD mode and we're faking our mouse movement +void Application::fakeMouseEvent(QMouseEvent* event) { + _fakedMouseEvent = true; + sendEvent(_glWidget, event); + _fakedMouseEvent = false; +} + +void Application::mouseMoveEvent(QMouseEvent* event) { + PROFILE_RANGE(__FUNCTION__); + + if (_aboutToQuit) { + return; + } + qDebug() << __FUNCTION__ << "line:" << __LINE__ << "event:" << event << "_fakedMouseEvent:" << _fakedMouseEvent; + + maybeToggleMenuVisible(event); + + // if this is a real mouse event, and we're in HMD mode, then we should use it to move the + // compositor reticle + if (!_fakedMouseEvent && isHMDMode()) { + _compositor.handleRealMouseMoveEvent(event); + return; // bail + } + if (!_fakedMouseEvent) { + _compositor.trackRealMouseMoveEvent(event); // FIXME - super janky + } auto offscreenUi = DependencyManager::get(); - QPointF transformedPos = offscreenUi->mapToVirtualScreen(event->localPos(), _glWidget); + auto eventPosition = _compositor.getMouseEventPosition(event); + QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition, _glWidget); auto button = event->button(); auto buttons = event->buttons(); // Determine if the ReticleClick Action is 1 and if so, fake include the LeftMouseButton @@ -2196,21 +2235,21 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { event->screenPos(), button, buttons, event->modifiers()); - getEntities()->mouseMoveEvent(&mappedEvent, deviceID); - _controllerScriptingInterface->emitMouseMoveEvent(&mappedEvent, deviceID); // send events to any registered scripts + getEntities()->mouseMoveEvent(&mappedEvent); + _controllerScriptingInterface->emitMouseMoveEvent(&mappedEvent); // send events to any registered scripts // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isMouseCaptured()) { return; } - if (deviceID == 0 && Menu::getInstance()->isOptionChecked(KeyboardMouseDevice::NAME)) { - _keyboardMouseDevice->mouseMoveEvent(event, deviceID); + if (Menu::getInstance()->isOptionChecked(KeyboardMouseDevice::NAME)) { + _keyboardMouseDevice->mouseMoveEvent(event); } } -void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { +void Application::mousePressEvent(QMouseEvent* event) { // Inhibit the menu if the user is using alt-mouse dragging _altPressed = false; @@ -2220,14 +2259,21 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { // keyboard shortcuts not to be swallowed by them. In particular, WebEngineViews // will consume all keyboard events. offscreenUi->unfocusWindows(); - QPointF transformedPos = offscreenUi->mapToVirtualScreen(event->localPos(), _glWidget); + qDebug() << __FUNCTION__ << "event:" << event; + + auto eventPosition = _compositor.getMouseEventPosition(event); + QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition, _glWidget); + + qDebug() << __FUNCTION__ << " eventPosition:" << eventPosition; + qDebug() << __FUNCTION__ << "transformedPos:" << transformedPos; + QMouseEvent mappedEvent(event->type(), transformedPos, event->screenPos(), event->button(), event->buttons(), event->modifiers()); if (!_aboutToQuit) { - getEntities()->mousePressEvent(&mappedEvent, deviceID); + getEntities()->mousePressEvent(&mappedEvent); } _controllerScriptingInterface->emitMousePressEvent(&mappedEvent); // send events to any registered scripts @@ -2239,7 +2285,7 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { if (hasFocus()) { - if (deviceID == 0 && Menu::getInstance()->isOptionChecked(KeyboardMouseDevice::NAME)) { + if (Menu::getInstance()->isOptionChecked(KeyboardMouseDevice::NAME)) { _keyboardMouseDevice->mousePressEvent(event); } @@ -2253,7 +2299,7 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { } } -void Application::mouseDoublePressEvent(QMouseEvent* event, unsigned int deviceID) { +void Application::mouseDoublePressEvent(QMouseEvent* event) { // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isMouseCaptured()) { return; @@ -2262,17 +2308,18 @@ void Application::mouseDoublePressEvent(QMouseEvent* event, unsigned int deviceI _controllerScriptingInterface->emitMouseDoublePressEvent(event); } -void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { +void Application::mouseReleaseEvent(QMouseEvent* event) { auto offscreenUi = DependencyManager::get(); - QPointF transformedPos = offscreenUi->mapToVirtualScreen(event->localPos(), _glWidget); + auto eventPosition = _compositor.getMouseEventPosition(event); + QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition, _glWidget); QMouseEvent mappedEvent(event->type(), transformedPos, event->screenPos(), event->button(), event->buttons(), event->modifiers()); if (!_aboutToQuit) { - getEntities()->mouseReleaseEvent(&mappedEvent, deviceID); + getEntities()->mouseReleaseEvent(&mappedEvent); } _controllerScriptingInterface->emitMouseReleaseEvent(&mappedEvent); // send events to any registered scripts @@ -2283,7 +2330,7 @@ void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { } if (hasFocus()) { - if (deviceID == 0 && Menu::getInstance()->isOptionChecked(KeyboardMouseDevice::NAME)) { + if (Menu::getInstance()->isOptionChecked(KeyboardMouseDevice::NAME)) { _keyboardMouseDevice->mouseReleaseEvent(event); } @@ -4689,6 +4736,14 @@ glm::uvec2 Application::getCanvasSize() const { return glm::uvec2(_glWidget->width(), _glWidget->height()); } +QRect Application::getApplicationGeometry() const { + auto geometry = _glWidget->geometry(); + auto topLeft = geometry.topLeft(); + auto topLeftScreen = _glWidget->mapToGlobal(topLeft); + geometry.moveTopLeft(topLeftScreen); + return geometry; +} + glm::uvec2 Application::getUiSize() const { return getActiveDisplayPlugin()->getRecommendedUiSize(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 1831f7171a..f05c5c6123 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -114,6 +114,8 @@ public: bool eventFilter(QObject* object, QEvent* event) override; glm::uvec2 getCanvasSize() const; + QRect getApplicationGeometry() const; + glm::uvec2 getUiSize() const; QSize getDeviceSize() const; bool hasFocus() const; @@ -219,6 +221,8 @@ public: float getAverageSimsPerSecond(); + void fakeMouseEvent(QMouseEvent* event); + signals: void svoImportRequested(const QString& url); @@ -368,10 +372,10 @@ private: void focusOutEvent(QFocusEvent* event); void focusInEvent(QFocusEvent* event); - void mouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0); - void mousePressEvent(QMouseEvent* event, unsigned int deviceID = 0); - void mouseDoublePressEvent(QMouseEvent* event, unsigned int deviceID = 0); - void mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0); + void mouseMoveEvent(QMouseEvent* event); + void mousePressEvent(QMouseEvent* event); + void mouseDoublePressEvent(QMouseEvent* event); + void mouseReleaseEvent(QMouseEvent* event); void touchBeginEvent(QTouchEvent* event); void touchEndEvent(QTouchEvent* event); @@ -381,6 +385,7 @@ private: void dropEvent(QDropEvent* event); void dragEnterEvent(QDragEnterEvent* event); + void maybeToggleMenuVisible(QMouseEvent* event); bool _dependencyManagerIsSetup; @@ -510,6 +515,8 @@ private: bool _settingsLoaded { false }; bool _pendingPaint { false }; QTimer* _idleTimer { nullptr }; + + bool _fakedMouseEvent { false }; }; #endif // hifi_Application_h diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp index 3bcf8bb311..9ca1e2c6c6 100644 --- a/interface/src/scripting/ControllerScriptingInterface.cpp +++ b/interface/src/scripting/ControllerScriptingInterface.cpp @@ -164,10 +164,10 @@ InputController::Key InputController::getKey() const { void ControllerScriptingInterface::emitKeyPressEvent(QKeyEvent* event) { emit keyPressEvent(KeyEvent(*event)); } void ControllerScriptingInterface::emitKeyReleaseEvent(QKeyEvent* event) { emit keyReleaseEvent(KeyEvent(*event)); } -void ControllerScriptingInterface::emitMouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { emit mouseMoveEvent(MouseEvent(*event, deviceID)); } -void ControllerScriptingInterface::emitMousePressEvent(QMouseEvent* event, unsigned int deviceID) { emit mousePressEvent(MouseEvent(*event, deviceID)); } -void ControllerScriptingInterface::emitMouseDoublePressEvent(QMouseEvent* event, unsigned int deviceID) { emit mouseDoublePressEvent(MouseEvent(*event, deviceID)); } -void ControllerScriptingInterface::emitMouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { emit mouseReleaseEvent(MouseEvent(*event, deviceID)); } +void ControllerScriptingInterface::emitMouseMoveEvent(QMouseEvent* event) { emit mouseMoveEvent(MouseEvent(*event)); } +void ControllerScriptingInterface::emitMousePressEvent(QMouseEvent* event) { emit mousePressEvent(MouseEvent(*event)); } +void ControllerScriptingInterface::emitMouseDoublePressEvent(QMouseEvent* event) { emit mouseDoublePressEvent(MouseEvent(*event)); } +void ControllerScriptingInterface::emitMouseReleaseEvent(QMouseEvent* event) { emit mouseReleaseEvent(MouseEvent(*event)); } void ControllerScriptingInterface::emitTouchBeginEvent(const TouchEvent& event) { emit touchBeginEvent(event); } void ControllerScriptingInterface::emitTouchEndEvent(const TouchEvent& event) { emit touchEndEvent(event); } diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h index 8bd698cfb2..43bb6987db 100644 --- a/interface/src/scripting/ControllerScriptingInterface.h +++ b/interface/src/scripting/ControllerScriptingInterface.h @@ -70,10 +70,10 @@ public: void handleMetaEvent(HFMetaEvent* event); - void emitMouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0); - void emitMousePressEvent(QMouseEvent* event, unsigned int deviceID = 0); - void emitMouseDoublePressEvent(QMouseEvent* event, unsigned int deviceID = 0); - void emitMouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0); + void emitMouseMoveEvent(QMouseEvent* event); + void emitMousePressEvent(QMouseEvent* event); + void emitMouseDoublePressEvent(QMouseEvent* event); + void emitMouseReleaseEvent(QMouseEvent* event); void emitTouchBeginEvent(const TouchEvent& event); void emitTouchEndEvent(const TouchEvent& event); @@ -111,10 +111,10 @@ signals: void backStartEvent(); void backEndEvent(); - void mouseMoveEvent(const MouseEvent& event, unsigned int deviceID = 0); - void mousePressEvent(const MouseEvent& event, unsigned int deviceID = 0); - void mouseDoublePressEvent(const MouseEvent& event, unsigned int deviceID = 0); - void mouseReleaseEvent(const MouseEvent& event, unsigned int deviceID = 0); + void mouseMoveEvent(const MouseEvent& event); + void mousePressEvent(const MouseEvent& event); + void mouseDoublePressEvent(const MouseEvent& event); + void mouseReleaseEvent(const MouseEvent& event); void touchBeginEvent(const TouchEvent& event); void touchEndEvent(const TouchEvent& event); diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index 961f9df0fe..806435a6c2 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -216,7 +216,7 @@ void ApplicationCompositor::displayOverlayTexture(RenderArgs* renderArgs) { //draw the mouse pointer // Get the mouse coordinates and convert to NDC [-1, 1] - vec2 canvasSize = qApp->getCanvasSize(); + vec2 canvasSize = qApp->getCanvasSize(); // desktop, use actual canvas... vec2 mousePosition = toNormalizedDeviceScale(vec2(qApp->getMouse()), canvasSize); // Invert the Y axis mousePosition.y *= -1.0f; @@ -246,7 +246,8 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int updateTooltips(); - vec2 canvasSize = qApp->getCanvasSize(); + glm::uvec2 screenSize { VIRTUAL_SCREEN_SIZE_X, VIRTUAL_SCREEN_SIZE_Y }; // = qApp->getCanvasSize(); // HMD use virtual screen size + vec2 canvasSize = screenSize; _textureAspectRatio = aspect(canvasSize); auto geometryCache = DependencyManager::get(); @@ -288,8 +289,9 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int glm::mat4 overlayXfm; _modelTransform.getMatrix(overlayXfm); - glm::vec2 projection = screenToSpherical(qApp->getTrueMouse()); - + auto reticlePosition = getReticlePosition(); + //qDebug() << "reticlePosition:" << reticlePosition; // FIXME - remove this debugging + glm::vec2 projection = screenToSpherical(reticlePosition); float cursorDepth = getReticleDepth(); mat4 pointerXfm = glm::scale(mat4(), vec3(cursorDepth)) * glm::mat4_cast(quat(vec3(-projection.y, projection.x, 0.0f))) * glm::translate(mat4(), vec3(0, 0, -1)); mat4 reticleXfm = overlayXfm * pointerXfm; @@ -300,6 +302,85 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int }); } +QPointF ApplicationCompositor::getMouseEventPosition(QMouseEvent* event) { + if (qApp->isHMDMode()) { + return QPointF(_reticlePositionInHMD.x, _reticlePositionInHMD.y); + } + return event->localPos(); +} + + +void ApplicationCompositor::handleLeaveEvent() { + if (qApp->isHMDMode()) { + auto applicationGeometry = qApp->getApplicationGeometry(); + qDebug() << "SENDING mouse back to center:" << applicationGeometry.center(); + _ignoreMouseMove = true; + auto sendToPos = applicationGeometry.center(); + QCursor::setPos(sendToPos); + _lastKnownRealMouse = sendToPos; + } +} + +void ApplicationCompositor::trackRealMouseMoveEvent(QMouseEvent* event) { + qDebug() << __FUNCTION__ << "() BEFORE _lastKnownRealMouse:" << _lastKnownRealMouse; + _lastKnownRealMouse = QCursor::pos(); + qDebug() << __FUNCTION__ << "() AFTER _lastKnownRealMouse:" << _lastKnownRealMouse; +} + +void ApplicationCompositor::handleRealMouseMoveEvent(QMouseEvent* event) { + qDebug() << __FUNCTION__ << "() event:" << event; + if (_ignoreMouseMove) { + qDebug() << __FUNCTION__ << "() IGNORE MOUSE MOVE!!!"; + _ignoreMouseMove = false; + return; + } + + auto applicationGeometry = qApp->getApplicationGeometry(); + qDebug() << ".... applicationGeometry:" << applicationGeometry; + + auto newPosition = QCursor::pos(); + auto changeInRealMouse = newPosition - _lastKnownRealMouse; + qDebug() << __FUNCTION__ << "() ..... _lastKnownRealMouse:" << _lastKnownRealMouse; + qDebug() << __FUNCTION__ << "() ............. newPosition:" << newPosition; + qDebug() << __FUNCTION__ << "() ....... changeInRealMouse:" << changeInRealMouse; + auto newReticlePosition = _reticlePositionInHMD + toGlm(changeInRealMouse); + _lastKnownRealMouse = newPosition; + + qDebug() << ".... about to call setReticlePosition() newReticlePosition:" << newReticlePosition; + setReticlePosition(newReticlePosition); +} + +glm::vec2 ApplicationCompositor::getReticlePosition() { + if (qApp->isHMDMode()) { + return _reticlePositionInHMD; + } + return toGlm(QCursor::pos()); +} +void ApplicationCompositor::setReticlePosition(glm::vec2 position) { + if (qApp->isHMDMode()) { + _reticlePositionInHMD = glm::clamp(position, vec2(0), vec2(VIRTUAL_SCREEN_SIZE_X, VIRTUAL_SCREEN_SIZE_Y)); + + // in HMD mode we need to fake our mouse moves... + QPoint globalPos(_reticlePositionInHMD.x, _reticlePositionInHMD.y); + QMouseEvent event(QEvent::MouseMove, globalPos, Qt::NoButton, Qt::NoButton, Qt::NoModifier); + + qDebug() << "about to call .... qApp->fakeMouseEvent(&event);"; + qApp->fakeMouseEvent(&event); + + } else { + // NOTE: This is some debugging code we will leave in while debugging various reticle movement strategies, + // remove it after we're done + const float REASONABLE_CHANGE = 50.0f; + glm::vec2 oldPos = toGlm(QCursor::pos()); + auto distance = glm::distance(oldPos, position); + if (distance > REASONABLE_CHANGE) { + qDebug() << "Contrller::ScriptingInterface ---- UNREASONABLE CHANGE! distance:" << distance << " oldPos:" << oldPos << " newPos:" << position; + } + + QCursor::setPos(position.x, position.y); + } +} + // FIXME - this probably is hella buggy and probably doesn't work correctly // we should kill it asap. @@ -460,7 +541,7 @@ void ApplicationCompositor::drawSphereSection(gpu::Batch& batch) { } glm::vec2 ApplicationCompositor::screenToSpherical(const glm::vec2& screenPos) { - auto screenSize = qApp->getCanvasSize(); + glm::uvec2 screenSize { VIRTUAL_SCREEN_SIZE_X, VIRTUAL_SCREEN_SIZE_Y }; // = qApp->getCanvasSize(); glm::vec2 result; result.x = -(screenPos.x / screenSize.x - 0.5f); result.y = (screenPos.y / screenSize.y - 0.5f); @@ -470,11 +551,12 @@ glm::vec2 ApplicationCompositor::screenToSpherical(const glm::vec2& screenPos) { } glm::vec2 ApplicationCompositor::sphericalToScreen(const glm::vec2& sphericalPos) { + glm::uvec2 screenSize { VIRTUAL_SCREEN_SIZE_X, VIRTUAL_SCREEN_SIZE_Y }; // = qApp->getCanvasSize(); glm::vec2 result = sphericalPos; result.x *= -1.0f; result /= MOUSE_RANGE; result += 0.5f; - result *= qApp->getCanvasSize(); + result *= screenSize; return result; } diff --git a/interface/src/ui/ApplicationCompositor.h b/interface/src/ui/ApplicationCompositor.h index fbac59a40c..8d8d7c62d5 100644 --- a/interface/src/ui/ApplicationCompositor.h +++ b/interface/src/ui/ApplicationCompositor.h @@ -10,6 +10,7 @@ #define hifi_ApplicationCompositor_h #include +#include #include #include #include @@ -25,6 +26,10 @@ class PalmData; class RenderArgs; class ReticleInterface; +const int VIRTUAL_SCREEN_SIZE_X = 4096; +const int VIRTUAL_SCREEN_SIZE_Y = 2160; + + const float MAGNIFY_WIDTH = 220.0f; const float MAGNIFY_HEIGHT = 100.0f; const float MAGNIFY_MULT = 2.0f; @@ -88,24 +93,16 @@ public: Q_INVOKABLE float getReticleDepth() { return _reticleDepth; } Q_INVOKABLE void setReticleDepth(float depth) { _reticleDepth = depth; } - Q_INVOKABLE glm::vec2 getReticlePosition() { - return toGlm(QCursor::pos()); - } - Q_INVOKABLE void setReticlePosition(glm::vec2 position) { - // NOTE: This is some debugging code we will leave in while debugging various reticle movement strategies, - // remove it after we're done - const float REASONABLE_CHANGE = 50.0f; - glm::vec2 oldPos = toGlm(QCursor::pos()); - auto distance = glm::distance(oldPos, position); - if (distance > REASONABLE_CHANGE) { - qDebug() << "Contrller::ScriptingInterface ---- UNREASONABLE CHANGE! distance:" << distance << " oldPos:" << oldPos << " newPos:" << position; - } - - QCursor::setPos(position.x, position.y); - } + Q_INVOKABLE glm::vec2 getReticlePosition(); + Q_INVOKABLE void setReticlePosition(glm::vec2 position); ReticleInterface* getReticleInterface() { return _reticleInterface; } + void handleRealMouseMoveEvent(QMouseEvent* event); + void trackRealMouseMoveEvent(QMouseEvent* event); + void handleLeaveEvent(); + QPointF getMouseEventPosition(QMouseEvent* event); + private: void displayOverlayTextureStereo(RenderArgs* renderArgs, float aspectRatio, float fov); @@ -146,6 +143,14 @@ private: bool _reticleVisible { true }; float _reticleDepth { 1.0f }; + // NOTE: when the compositor is running in HMD mode, it will control the reticle position as a custom + // application specific position, when it's in desktop mode, the reticle position will simply move + // the system mouse. + glm::vec2 _reticlePositionInHMD{ 0.0f, 0.0f }; + QPointF _lastKnownRealMouse; + QPoint _lastKnownCursorPos; + bool _ignoreMouseMove { false }; + ReticleInterface* _reticleInterface; }; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 1967e14d6e..85a4b13b29 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -492,16 +492,16 @@ RayToEntityIntersectionResult EntityTreeRenderer::findRayIntersectionWorker(cons void EntityTreeRenderer::connectSignalsToSlots(EntityScriptingInterface* entityScriptingInterface) { connect(this, &EntityTreeRenderer::mousePressOnEntity, entityScriptingInterface, - [=](const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId){ - entityScriptingInterface->mousePressOnEntity(intersection.entityID, MouseEvent(*event, deviceId)); + [=](const RayToEntityIntersectionResult& intersection, const QMouseEvent* event){ + entityScriptingInterface->mousePressOnEntity(intersection.entityID, MouseEvent(*event)); }); connect(this, &EntityTreeRenderer::mouseMoveOnEntity, entityScriptingInterface, - [=](const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId) { - entityScriptingInterface->mouseMoveOnEntity(intersection.entityID, MouseEvent(*event, deviceId)); + [=](const RayToEntityIntersectionResult& intersection, const QMouseEvent* event) { + entityScriptingInterface->mouseMoveOnEntity(intersection.entityID, MouseEvent(*event)); }); connect(this, &EntityTreeRenderer::mouseReleaseOnEntity, entityScriptingInterface, - [=](const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId) { - entityScriptingInterface->mouseReleaseOnEntity(intersection.entityID, MouseEvent(*event, deviceId)); + [=](const RayToEntityIntersectionResult& intersection, const QMouseEvent* event) { + entityScriptingInterface->mouseReleaseOnEntity(intersection.entityID, MouseEvent(*event)); }); connect(this, &EntityTreeRenderer::clickDownOnEntity, entityScriptingInterface, &EntityScriptingInterface::clickDownOnEntity); @@ -519,7 +519,7 @@ void EntityTreeRenderer::connectSignalsToSlots(EntityScriptingInterface* entityS connect(DependencyManager::get().data(), &SceneScriptingInterface::shouldRenderEntitiesChanged, this, &EntityTreeRenderer::updateEntityRenderStatus, Qt::QueuedConnection); } -void EntityTreeRenderer::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { +void EntityTreeRenderer::mousePressEvent(QMouseEvent* event) { // If we don't have a tree, or we're in the process of shutting down, then don't // process these events. if (!_tree || _shuttingDown) { @@ -540,20 +540,20 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event, unsigned int device } - emit mousePressOnEntity(rayPickResult, event, deviceID); - _entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mousePressOnEntity", MouseEvent(*event, deviceID)); + emit mousePressOnEntity(rayPickResult, event); + _entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mousePressOnEntity", MouseEvent(*event)); _currentClickingOnEntityID = rayPickResult.entityID; - emit clickDownOnEntity(_currentClickingOnEntityID, MouseEvent(*event, deviceID)); - _entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "clickDownOnEntity", MouseEvent(*event, deviceID)); + emit clickDownOnEntity(_currentClickingOnEntityID, MouseEvent(*event)); + _entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "clickDownOnEntity", MouseEvent(*event)); } else { - emit mousePressOffEntity(rayPickResult, event, deviceID); + emit mousePressOffEntity(rayPickResult, event); } - _lastMouseEvent = MouseEvent(*event, deviceID); + _lastMouseEvent = MouseEvent(*event); _lastMouseEventValid = true; } -void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { +void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) { // If we don't have a tree, or we're in the process of shutting down, then don't // process these events. if (!_tree || _shuttingDown) { @@ -565,24 +565,24 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event, unsigned int devi RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock, precisionPicking); if (rayPickResult.intersects) { //qCDebug(entitiesrenderer) << "mouseReleaseEvent over entity:" << rayPickResult.entityID; - emit mouseReleaseOnEntity(rayPickResult, event, deviceID); - _entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseReleaseOnEntity", MouseEvent(*event, deviceID)); + emit mouseReleaseOnEntity(rayPickResult, event); + _entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseReleaseOnEntity", MouseEvent(*event)); } // Even if we're no longer intersecting with an entity, if we started clicking on it, and now // we're releasing the button, then this is considered a clickOn event if (!_currentClickingOnEntityID.isInvalidID()) { - emit clickReleaseOnEntity(_currentClickingOnEntityID, MouseEvent(*event, deviceID)); - _entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "clickReleaseOnEntity", MouseEvent(*event, deviceID)); + emit clickReleaseOnEntity(_currentClickingOnEntityID, MouseEvent(*event)); + _entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "clickReleaseOnEntity", MouseEvent(*event)); } // makes it the unknown ID, we just released so we can't be clicking on anything _currentClickingOnEntityID = UNKNOWN_ENTITY_ID; - _lastMouseEvent = MouseEvent(*event, deviceID); + _lastMouseEvent = MouseEvent(*event); _lastMouseEventValid = true; } -void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { +void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) { // If we don't have a tree, or we're in the process of shutting down, then don't // process these events. if (!_tree || _shuttingDown) { @@ -596,28 +596,28 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking); if (rayPickResult.intersects) { - _entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseMoveEvent", MouseEvent(*event, deviceID)); - _entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseMoveOnEntity", MouseEvent(*event, deviceID)); + _entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseMoveEvent", MouseEvent(*event)); + _entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseMoveOnEntity", MouseEvent(*event)); // handle the hover logic... // if we were previously hovering over an entity, and this new entity is not the same as our previous entity // then we need to send the hover leave. if (!_currentHoverOverEntityID.isInvalidID() && rayPickResult.entityID != _currentHoverOverEntityID) { - emit hoverLeaveEntity(_currentHoverOverEntityID, MouseEvent(*event, deviceID)); - _entitiesScriptEngine->callEntityScriptMethod(_currentHoverOverEntityID, "hoverLeaveEntity", MouseEvent(*event, deviceID)); + emit hoverLeaveEntity(_currentHoverOverEntityID, MouseEvent(*event)); + _entitiesScriptEngine->callEntityScriptMethod(_currentHoverOverEntityID, "hoverLeaveEntity", MouseEvent(*event)); } // If the new hover entity does not match the previous hover entity then we are entering the new one // this is true if the _currentHoverOverEntityID is known or unknown if (rayPickResult.entityID != _currentHoverOverEntityID) { - _entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "hoverEnterEntity", MouseEvent(*event, deviceID)); + _entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "hoverEnterEntity", MouseEvent(*event)); } // and finally, no matter what, if we're intersecting an entity then we're definitely hovering over it, and // we should send our hover over event - emit hoverOverEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); - _entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "hoverOverEntity", MouseEvent(*event, deviceID)); + emit hoverOverEntity(rayPickResult.entityID, MouseEvent(*event)); + _entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "hoverOverEntity", MouseEvent(*event)); // remember what we're hovering over _currentHoverOverEntityID = rayPickResult.entityID; @@ -627,8 +627,8 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI // if we were previously hovering over an entity, and we're no longer hovering over any entity then we need to // send the hover leave for our previous entity if (!_currentHoverOverEntityID.isInvalidID()) { - emit hoverLeaveEntity(_currentHoverOverEntityID, MouseEvent(*event, deviceID)); - _entitiesScriptEngine->callEntityScriptMethod(_currentHoverOverEntityID, "hoverLeaveEntity", MouseEvent(*event, deviceID)); + emit hoverLeaveEntity(_currentHoverOverEntityID, MouseEvent(*event)); + _entitiesScriptEngine->callEntityScriptMethod(_currentHoverOverEntityID, "hoverLeaveEntity", MouseEvent(*event)); _currentHoverOverEntityID = UNKNOWN_ENTITY_ID; // makes it the unknown ID } } @@ -636,10 +636,10 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI // Even if we're no longer intersecting with an entity, if we started clicking on an entity and we have // not yet released the hold then this is still considered a holdingClickOnEntity event if (!_currentClickingOnEntityID.isInvalidID()) { - emit holdingClickOnEntity(_currentClickingOnEntityID, MouseEvent(*event, deviceID)); - _entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "holdingClickOnEntity", MouseEvent(*event, deviceID)); + emit holdingClickOnEntity(_currentClickingOnEntityID, MouseEvent(*event)); + _entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "holdingClickOnEntity", MouseEvent(*event)); } - _lastMouseEvent = MouseEvent(*event, deviceID); + _lastMouseEvent = MouseEvent(*event); _lastMouseEventValid = true; } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 2a3d688492..f0454b2ecf 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -74,9 +74,9 @@ public: void deleteReleasedModels(); // event handles which may generate entity related events - void mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID); - void mousePressEvent(QMouseEvent* event, unsigned int deviceID); - void mouseMoveEvent(QMouseEvent* event, unsigned int deviceID); + void mouseReleaseEvent(QMouseEvent* event); + void mousePressEvent(QMouseEvent* event); + void mouseMoveEvent(QMouseEvent* event); /// connect our signals to anEntityScriptingInterface for firing of events related clicking, /// hovering over, and entering entities @@ -86,10 +86,10 @@ public: QList& getEntitiesLastInScene() { return _entityIDsLastInScene; } signals: - void mousePressOnEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId); - void mousePressOffEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId); - void mouseMoveOnEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId); - void mouseReleaseOnEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId); + void mousePressOnEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event); + void mousePressOffEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event); + void mouseMoveOnEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event); + void mouseReleaseOnEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event); void clickDownOnEntity(const EntityItemID& entityItemID, const MouseEvent& event); void holdingClickOnEntity(const EntityItemID& entityItemID, const MouseEvent& event); diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index ce89197069..8140dd3312 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -85,7 +85,7 @@ void RenderableWebEntityItem::render(RenderArgs* args) { _texture = textureId; }); - auto forwardMouseEvent = [=](const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId) { + auto forwardMouseEvent = [=](const RayToEntityIntersectionResult& intersection, const QMouseEvent* event) { // Ignore mouse interaction if we're locked if (this->getLocked()) { return; diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp index c3d2f7c51c..0bf398cdec 100755 --- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp @@ -57,7 +57,7 @@ void KeyboardMouseDevice::keyReleaseEvent(QKeyEvent* event) { _inputDevice->_buttonPressedMap.erase(input.getChannel()); } -void KeyboardMouseDevice::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { +void KeyboardMouseDevice::mousePressEvent(QMouseEvent* event) { auto input = _inputDevice->makeInput((Qt::MouseButton) event->button()); auto result = _inputDevice->_buttonPressedMap.insert(input.getChannel()); if (!result.second) { @@ -70,7 +70,7 @@ void KeyboardMouseDevice::mousePressEvent(QMouseEvent* event, unsigned int devic eraseMouseClicked(); } -void KeyboardMouseDevice::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { +void KeyboardMouseDevice::mouseReleaseEvent(QMouseEvent* event) { auto input = _inputDevice->makeInput((Qt::MouseButton) event->button()); _inputDevice->_buttonPressedMap.erase(input.getChannel()); @@ -89,7 +89,7 @@ void KeyboardMouseDevice::eraseMouseClicked() { _inputDevice->_buttonPressedMap.erase(_inputDevice->makeInput(Qt::RightButton, true).getChannel()); } -void KeyboardMouseDevice::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { +void KeyboardMouseDevice::mouseMoveEvent(QMouseEvent* event) { QPoint currentPos = event->pos(); QPoint currentMove = currentPos - _lastCursor; diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h index 55ca9a1704..67d9ccb1b2 100644 --- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h +++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h @@ -75,9 +75,9 @@ public: 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 mouseMoveEvent(QMouseEvent* event); + void mousePressEvent(QMouseEvent* event); + void mouseReleaseEvent(QMouseEvent* event); void eraseMouseClicked(); void touchBeginEvent(const QTouchEvent* event); diff --git a/libraries/script-engine/src/MouseEvent.cpp b/libraries/script-engine/src/MouseEvent.cpp index 34b3eb693e..31bca8054d 100644 --- a/libraries/script-engine/src/MouseEvent.cpp +++ b/libraries/script-engine/src/MouseEvent.cpp @@ -29,10 +29,9 @@ MouseEvent::MouseEvent() : } -MouseEvent::MouseEvent(const QMouseEvent& event, const unsigned int deviceID) : +MouseEvent::MouseEvent(const QMouseEvent& event) : x(event.x()), y(event.y()), - deviceID(deviceID), isLeftButton(event.buttons().testFlag(Qt::LeftButton)), isRightButton(event.buttons().testFlag(Qt::RightButton)), isMiddleButton(event.buttons().testFlag(Qt::MiddleButton)), @@ -66,7 +65,6 @@ QScriptValue MouseEvent::toScriptValue(QScriptEngine* engine, const MouseEvent& obj.setProperty("x", event.x); obj.setProperty("y", event.y); obj.setProperty("button", event.button); - obj.setProperty("deviceID", event.deviceID); obj.setProperty("isLeftButton", event.isLeftButton); obj.setProperty("isRightButton", event.isRightButton); obj.setProperty("isMiddleButton", event.isMiddleButton); diff --git a/libraries/script-engine/src/MouseEvent.h b/libraries/script-engine/src/MouseEvent.h index 1936e6b58e..0fbc688e5f 100644 --- a/libraries/script-engine/src/MouseEvent.h +++ b/libraries/script-engine/src/MouseEvent.h @@ -17,7 +17,7 @@ class MouseEvent { public: MouseEvent(); - MouseEvent(const QMouseEvent& event, const unsigned int deviceID = 0); + MouseEvent(const QMouseEvent& event); static QScriptValue toScriptValue(QScriptEngine* engine, const MouseEvent& event); static void fromScriptValue(const QScriptValue& object, MouseEvent& event); @@ -26,7 +26,6 @@ public: int x; int y; - unsigned int deviceID; QString button; bool isLeftButton; bool isRightButton;