diff --git a/interface/resources/controllers/keyboardMouse.json b/interface/resources/controllers/keyboardMouse.json index 11c80a4dd2..9449d37f7d 100644 --- a/interface/resources/controllers/keyboardMouse.json +++ b/interface/resources/controllers/keyboardMouse.json @@ -213,6 +213,15 @@ ] }, + { "from": { "makeAxis" : ["Keyboard.MouseMoveLeft", "Keyboard.MouseMoveRight"] }, + "to": "Actions.DeltaYaw", + "when": "Application.CaptureMouse", + "filters": + [ + { "type": "scale", "scale": 0.2 } + ] + }, + { "from": { "makeAxis" : ["Keyboard.MouseMoveUp", "Keyboard.MouseMoveDown"] }, "when": ["!Application.CameraSelfie", "!Application.CameraLookAt", "Keyboard.RightMouseButton"], "to": "Actions.DeltaPitch", @@ -222,6 +231,15 @@ ] }, + { "from": { "makeAxis" : ["Keyboard.MouseMoveUp", "Keyboard.MouseMoveDown"] }, + "to": "Actions.DeltaPitch", + "when": "Application.CaptureMouse", + "filters": + [ + { "type": "scale", "scale": 0.2 } + ] + }, + { "from": { "makeAxis" : ["Keyboard.MouseMoveUp", "Keyboard.MouseMoveDown"] }, "when": ["Application.CameraLookAt", "Keyboard.RightMouseButton"], "to": "Actions.DeltaPitch", diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index cc2aed7f53..024df2343b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -680,6 +680,7 @@ private: * CameraIndependentnumbernumberThe camera is in independent mode. * CameraEntitynumbernumberThe camera is in entity mode. * InHMDnumbernumberThe user is in HMD mode. + * CaptureMousenumbernumberThe mouse is captured. * AdvancedMovementnumbernumberAdvanced movement (walking) controls are * enabled. * StrafeEnablednumbernumberStrafing is enabled @@ -715,6 +716,7 @@ static const QString STATE_PLATFORM_ANDROID = "PlatformAndroid"; static const QString STATE_LEFT_HAND_DOMINANT = "LeftHandDominant"; static const QString STATE_RIGHT_HAND_DOMINANT = "RightHandDominant"; static const QString STATE_STRAFE_ENABLED = "StrafeEnabled"; +static const QString STATE_CAMERA_CAPTURE_MOUSE = "CaptureMouse"; // Statically provided display and input plugins extern DisplayPluginList getDisplayPlugins(); @@ -918,7 +920,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); controller::StateController::setStateVariables({ { STATE_IN_HMD, STATE_CAMERA_FULL_SCREEN_MIRROR, STATE_CAMERA_FIRST_PERSON, STATE_CAMERA_FIRST_PERSON_LOOK_AT, STATE_CAMERA_THIRD_PERSON, - STATE_CAMERA_ENTITY, STATE_CAMERA_INDEPENDENT, STATE_CAMERA_LOOK_AT, STATE_CAMERA_SELFIE, + STATE_CAMERA_ENTITY, STATE_CAMERA_INDEPENDENT, STATE_CAMERA_LOOK_AT, STATE_CAMERA_SELFIE, STATE_CAMERA_CAPTURE_MOUSE, STATE_SNAP_TURN, STATE_ADVANCED_MOVEMENT_CONTROLS, STATE_GROUNDED, STATE_NAV_FOCUSED, STATE_PLATFORM_WINDOWS, STATE_PLATFORM_MAC, STATE_PLATFORM_ANDROID, STATE_LEFT_HAND_DOMINANT, STATE_RIGHT_HAND_DOMINANT, STATE_STRAFE_ENABLED } }); DependencyManager::set(); @@ -1891,6 +1893,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _applicationStateDevice->setInputVariant(STATE_CAMERA_INDEPENDENT, []() -> float { return qApp->getCamera().getMode() == CAMERA_MODE_INDEPENDENT ? 1 : 0; }); + _applicationStateDevice->setInputVariant(STATE_CAMERA_CAPTURE_MOUSE, []() -> float { + return qApp->getCamera().getCaptureMouse() ? 1 : 0; + }); _applicationStateDevice->setInputVariant(STATE_SNAP_TURN, []() -> float { return qApp->getMyAvatar()->getSnapTurn() ? 1 : 0; }); @@ -2406,6 +2411,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo updateSystemTabletMode(); connect(&_myCamera, &Camera::modeUpdated, this, &Application::cameraModeChanged); + connect(&_myCamera, &Camera::captureMouseUpdated, this, &Application::captureMouseChanged); DependencyManager::get()->setShouldPickHUDOperator([]() { return DependencyManager::get()->isHMDMode(); }); DependencyManager::get()->setCalculatePos2DFromHUDOperator([this](const glm::vec3& intersection) { @@ -5910,6 +5916,18 @@ void Application::cameraModeChanged() { cameraMenuChanged(); } +void Application::captureMouseChanged() { + if (_myCamera.getCaptureMouse()) { + // we want to grab the mouse here so that no other widgets get events, and also hide the mouse, but these don't work: + //_glWidget->grabMouse(); + //QCursor::setShape(Qt::CursorShape::BlankCursor); + } else { + // we want to release the mouse here so that other widgets get events, and also show the mouse, but these don't work: + //_glWidget->releaseMouse(); + //QCursor::setShape(Qt::CursorShape::ArrowCursor); + } +} + void Application::changeViewAsNeeded(float boomLength) { // Switch between first and third person views as needed // This is called when the boom length has changed diff --git a/interface/src/Application.h b/interface/src/Application.h index f42696cda0..50ae9860fa 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -430,6 +430,7 @@ public slots: void cycleCamera(); void cameraModeChanged(); void cameraMenuChanged(); + void captureMouseChanged(); void toggleOverlays(); void setOverlaysVisible(bool visible); Q_INVOKABLE void centerUI(); diff --git a/libraries/shared/src/shared/Camera.h b/libraries/shared/src/shared/Camera.h index 48cd814d86..2564a3f7c8 100644 --- a/libraries/shared/src/shared/Camera.h +++ b/libraries/shared/src/shared/Camera.h @@ -43,6 +43,7 @@ class Camera : public QObject { Q_PROPERTY(glm::quat orientation READ getOrientation WRITE setOrientation) Q_PROPERTY(QString mode READ getModeString WRITE setModeString NOTIFY modeUpdated) Q_PROPERTY(QVariantMap frustum READ getViewFrustum CONSTANT) + Q_PROPERTY(bool captureMouse READ getCaptureMouse WRITE setCaptureMouse NOTIFY captureMouseUpdated) public: Camera(); @@ -110,6 +111,20 @@ public slots: */ void setOrientation(const glm::quat& orientation); + /**jsdoc + * Gets the current mouse capture state. + * @function Camera.getMouseCapture + * @returns {boolean} The current mouse capture state. + */ + bool getCaptureMouse() const { return _captureMouse; } + + /**jsdoc + * Sets mouse capture state. + * @function Camera.setCaptureMouse + * @param {boolean} captureMouse - Whether or not to capture the mouse. + */ + void setCaptureMouse(bool captureMouse) { _captureMouse = captureMouse; } + /**jsdoc * Computes a {@link PickRay} based on the current camera configuration and the specified x, y position on the * screen. The {@link PickRay} can be used in functions such as {@link Entities.findRayIntersection} and @@ -181,6 +196,20 @@ signals: */ void modeUpdated(const QString& newMode); + /**jsdoc + * Triggered when the camera mouse capture state changes. + * @function Camera.captureMouseUpdated + * @param {boolean} newCaptureMouse - The new mouse capture state. + * @returns {Signal} + * @example Report mouse capture state changes. + * function onCaptureMouseUpdated(newCaptureMouse) { + * print("The mouse capture has changed to " + newCaptureMouse); + * } + * + * Camera.captureMouseUpdated.connect(onCaptureMouseUpdated); + */ + void captureMouseUpdated(bool newCaptureMouse); + private: void recompose(); void decompose(); @@ -194,6 +223,8 @@ private: glm::quat _orientation; bool _isKeepLookingAt{ false }; glm::vec3 _lookingAt; + + bool _captureMouse { false }; }; #endif // hifi_Camera_h