//// ControllerScriptingInterface.h// interface/src/scripting//// Created by Brad Hefta-Gaub on 12/17/13.// Copyright 2013 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_ControllerScriptingInterface_h#define hifi_ControllerScriptingInterface_h#include <QtCore/QObject>#include <controllers/UserInputMapper.h>#include <controllers/ScriptingInterface.h>#include <KeyEvent.h>#include <MouseEvent.h>#include <SpatialEvent.h>#include <TouchEvent.h>#include <WheelEvent.h>class ScriptEngine;/**jsdoc * The Controller API provides facilities to interact with computer and controller hardware. * * <h5>Functions</h5> * * <p>Properties</p> * <ul> * <li>{@link Controller.getActions|getActions}</li> * <li>{@link Controller.getHardware|getHardware}</li> * <li>{@link Controller.getStandard|getStandard}</li> * </ul> * * <p>Mappings</p> * <ul> * <li>{@link Controller.disableMapping|disableMapping}</li> * <li>{@link Controller.enableMapping|enableMapping}</li> * <li>{@link Controller.loadMapping|loadMapping}</li> * <li>{@link Controller.newMapping|newMapping}</li> * <li>{@link Controller.parseMapping|parseMapping}</li> * </ul> * * <p>Input, Hardware, and Action Reflection</p> * <ul> * <li>{@link Controller.findAction|findAction}</li> * <li>{@link Controller.findDevice|findDevice}</li> * <li>{@link Controller.getActionNames|getActionNames}</li> * <li>{@link Controller.getAllActions|getAllActions}</li> * <li>{@link Controller.getAvailableInputs|getAvailableInputs}</li> * <li>{@link Controller.getDeviceName|getDeviceName}</li> * <li>{@link Controller.getDeviceNames|getDeviceNames}</li> * </ul> * * <p>Input, Hardware, and Action Events</p> * <ul> * <li>{@link Controller.actionEvent|actionEvent}</li> * <li>{@link Controller.hardwareChanged|hardwareChanged}</li> * <li>{@link Controller.inputEvent|inputEvent}</li> * </ul> * * <p>Mouse, Keyboard, and Touch Events</p> * <ul> * <li>{@link Controller.keyPressEvent|keyPressEvent}</li> * <li>{@link Controller.keyReleaseEvent|keyReleaseEvent}</li> * <li>{@link Controller.mouseDoublePressEvent|mouseDoublePressEvent}</li> * <li>{@link Controller.mouseMoveEvent|mouseMoveEvent}</li> * <li>{@link Controller.mousePressEvent|mousePressEvent}</li> * <li>{@link Controller.mouseReleaseEvent|mouseReleaseEvent}</li> * <li>{@link Controller.touchBeginEvent|touchBeginEvent}</li> * <li>{@link Controller.touchEndEvent|touchEndEvent}</li> * <li>{@link Controller.touchUpdateEvent|touchUpdateEvent}</li> * <li>{@link Controller.wheelEvent|wheelEvent}</li> * </ul> * * <p>Control Capturing</p> * <ul> * <li>{@link Controller.captureMouseEvents|captureMouseEvents}</li> * <li>{@link Controller.captureTouchEvents|captureTouchEvents}</li> * <li>{@link Controller.captureWheelEvents|captureWheelEvents}</li> * <li>{@link Controller.releaseMouseEvents|releaseMouseEvents}</li> * <li>{@link Controller.releaseTouchEvents|releaseTouchEvents}</li> * <li>{@link Controller.releaseWheelEvents|releaseWheelEvents}</li> * </ul> * * <p>Action Capturing</p> * <ul> * <li>{@link Controller.captureActionEvents|captureActionEvents}</li> * <li>{@link Controller.captureEntityClickEvents|captureEntityClickEvents}</li> * <li>{@link Controller.captureJoystick|captureJoystick}</li> * <li>{@link Controller.captureKeyEvents|captureKeyEvents}</li> * <li>{@link Controller.releaseActionEvents|releaseActionEvents}</li> * <li>{@link Controller.releaseEntityClickEvents|releaseEntityClickEvents}</li> * <li>{@link Controller.releaseJoystick|releaseJoystick}</li> * <li>{@link Controller.releaseKeyEvents|releaseKeyEvents}</li> * </ul> * * <p>Controller and Action Values</p> * <ul> * <li>{@link Controller.getValue|getValue}</li> * <li>{@link Controller.getAxisValue|getAxisValue}</li> * <li>{@link Controller.getPoseValue|getgetPoseValue}</li> * <li>{@link Controller.getActionValue|getActionValue}</li> * </ul> * * <p>Haptics</p> * <ul> * <li>{@link Controller.triggerHapticPulse|triggerHapticPulse}</li> * <li>{@link Controller.triggerHapticPulseOnDevice|triggerHapticPulseOnDevice}</li> * <li>{@link Controller.triggerShortHapticPulse|triggerShortHapticPulse}</li> * <li>{@link Controller.triggerShortHapticPulseOnDevice|triggerShortHapticPulseOnDevice}</li> * </ul> * * <p>Display Information</p> * <ul> * <li>{@link Controller.getViewportDimensions|getViewportDimensions}</li> * <li>{@link Controller.getRecommendedHUDRect|getRecommendedHUDRect}</li> * </ul> * * <p>Virtual Game Pad</p> * <ul> * <li>{@link Controller.setVPadEnabled|setVPadEnabled}</li> * <li>{@link Controller.setVPadHidden|setVPadHidden}</li> * <li>{@link Controller.setVPadExtraBottomMargin|setVPadExtraBottomMargin}</li> * </ul> * * <p>Input Recordings</p> * <ul> * <li>{@link Controller.startInputRecording|startInputRecording}</li> * <li>{@link Controller.stopInputRecording|stopInputRecording}</li> * <li>{@link Controller.saveInputRecording|saveInputRecording}</li> * <li>{@link Controller.getInputRecorderSaveDirectory|getInputRecorderSaveDirectory}</li> * <li>{@link Controller.loadInputRecording|loadInputRecording}</li> * <li>{@link Controller.startInputPlayback|startInputPlayback}</li> * <li>{@link Controller.stopInputPlayback|stopInputPlayback}</li> * </ul> * * <h5>Entity Methods:</h5> * * <p>The default scripts implement hand controller actions that use {@link Entities.callEntityMethod} to call entity script * methods, if present in the entity being interacted with.</p> * * <table> * <thead> * <tr><th>Method Name</th><th>Description</th><th>Example</th></tr> * </thead> * <tbody> * <tr> * <td><code>startFarTrigger</code><br /><code>continueFarTrigger</code><br /><code>stopFarTrigger</code></td> * <td>These methods are called when a user is more than 0.3m away from the entity, the entity is triggerable, and the * user starts, continues, or stops squeezing the trigger.</td> * </td> * <td>A light switch that can be toggled on and off from a distance.</td> * </tr> * <tr> * <td><code>startNearTrigger</code><br /><code>continueNearTrigger</code><br /><code>stopNearTrigger</code></td> * <td>These methods are called when a user is less than 0.3m away from the entity, the entity is triggerable, and the * user starts, continues, or stops squeezing the trigger.</td> * <td>A doorbell that can be rung when a user is near.</td> * </tr> * <tr> * <td><code>startDistanceGrab</code><br /><code>continueDistanceGrab</code><br /></td> * <td>These methods are called when a user is more than 0.3m away from the entity, the entity is either cloneable, or * grabbable and not locked, and the user starts or continues to squeeze the trigger.</td> * <td>A comet that emits icy particle trails when a user is dragging it through the sky.</td> * </tr> * <tr> * <td><code>startNearGrab</code><br /><code>continueNearGrab</code><br /></td> * <td>These methods are called when a user is less than 0.3m away from the entity, the entity is either cloneable, or * grabbable and not locked, and the user starts or continues to squeeze the trigger.</td> * <td>A ball that glows when it's being held close.</td> * </tr> * <tr> * <td><code>releaseGrab</code></td> * <td>This method is called when a user releases the trigger when having been either distance or near grabbing an * entity.</td> * <td>Turn off the ball glow or comet trail with the user finishes grabbing it.</td> * </tr> * <tr> * <td><code>startEquip</code><br /><code>continueEquip</code><br /><code>releaseEquip</code></td> * <td>These methods are called when a user starts, continues, or stops equipping an entity.</td> * <td>A glass that stays in the user's hand after the trigger is clicked.</td> * </tr> * </tbody> * </table> * <p>All the entity methods are called with the following two arguments:</p> * <ul> * <li>The entity ID.</li> * <li>A string, <code>"hand,userID"</code> — where "hand" is <code>"left"</code> or <code>"right"</code>, and "userID" * is the user's {@link MyAvatar|MyAvatar.sessionUUID}.</li> * </ul> * * @namespace Controller * * @hifi-interface * @hifi-client-entity * * @property {Controller.Actions} Actions - Predefined actions on Interface and the user's avatar. These can be used as end * points in a {@link RouteObject} mapping. A synonym for <code>Controller.Hardware.Actions</code>. * <em>Read-only.</em><br /> * Default mappings are provided from the <code>Controller.Hardware.Keyboard</code> and <code>Controller.Standard</code> to * actions in * <a href="https://github.com/highfidelity/hifi/blob/master/interface/resources/controllers/keyboardMouse.json"> * keyboardMouse.json</a> and * <a href="https://github.com/highfidelity/hifi/blob/master/interface/resources/controllers/standard.json"> * standard.json</a>, respectively. * * @property {Controller.Hardware} Hardware - Standard and hardware-specific controller and computer outputs, plus predefined * actions on Interface and the user's avatar. The outputs can be mapped to <code>Actions</code> or functions in a * {@link RouteObject} mapping. Additionally, hardware-specific controller outputs can be mapped to <code>Standard</code> * controller outputs. <em>Read-only.</em> * * @property {Controller.Standard} Standard - Standard controller outputs that can be mapped to <code>Actions</code> or * functions in a {@link RouteObject} mapping. <em>Read-only.</em><br /> * Each hardware device has a mapping from its outputs to <code>Controller.Standard</code> items, specified in a JSON file. * For example, <a href="https://github.com/highfidelity/hifi/blob/master/interface/resources/controllers/leapmotion.json"> * leapmotion.json</a> and * <a href="https://github.com/highfidelity/hifi/blob/master/interface/resources/controllers/vive.json">vive.json</a>. *//// handles scripting of input controller commands from JSclass ControllerScriptingInterface : public controller::ScriptingInterface { Q_OBJECTpublic: virtual ~ControllerScriptingInterface() {} void emitKeyPressEvent(QKeyEvent* event); void emitKeyReleaseEvent(QKeyEvent* event); 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); void emitTouchUpdateEvent(const TouchEvent& event); void emitWheelEvent(QWheelEvent* event); bool isKeyCaptured(QKeyEvent* event) const; bool isKeyCaptured(const KeyEvent& event) const; bool isJoystickCaptured(int joystickIndex) const; bool areEntityClicksCaptured() const;public slots: /**jsdoc * Disable default Interface actions for a particular key event. * @function Controller.captureKeyEvents * @param {KeyEvent} event - Details of the key event to be captured. The <code>key</code> property must be specified. The * <code>text</code> property is ignored. The other properties default to <code>false</code>. * @example <caption>Disable left and right strafing.</caption> * var STRAFE_LEFT = { "key": 16777234, isShifted: true }; * var STRAFE_RIGHT = { "key": 16777236, isShifted: true }; * * Controller.captureKeyEvents(STRAFE_LEFT); * Controller.captureKeyEvents(STRAFE_RIGHT); * * Script.scriptEnding.connect(function () { * Controller.releaseKeyEvents(STRAFE_LEFT); * Controller.releaseKeyEvents(STRAFE_RIGHT); * }); */ virtual void captureKeyEvents(const KeyEvent& event); /**jsdoc * Re-enable default Interface actions for a particular key event that has been disabled using * {@link Controller.captureKeyEvents|captureKeyEvents}. * @function Controller.releaseKeyEvents * @param {KeyEvent} event - Details of the key event to release from capture. The <code>key</code> property must be * specified. The <code>text</code> property is ignored. The other properties default to <code>false</code>. */ virtual void releaseKeyEvents(const KeyEvent& event); /**jsdoc * Disable default Interface actions for a joystick. * @function Controller.captureJoystick * @param {number} joystickID - The integer ID of the joystick. * @deprecated This function no longer has any effect. */ virtual void captureJoystick(int joystickIndex); /**jsdoc * Re-enable default Interface actions for a joystick that has been disabled using * {@link Controller.captureJoystick|captureJoystick}. * @function Controller.releaseJoystick * @param {number} joystickID - The integer ID of the joystick. * @deprecated This function no longer has any effect. */ virtual void releaseJoystick(int joystickIndex); /**jsdoc * Disable {@link Entities.mousePressOnEntity} and {@link Entities.mouseDoublePressOnEntity} events on entities. * @function Controller.captureEntityClickEvents * @example <caption>Disable entity click events for a short period.</caption> * Entities.mousePressOnEntity.connect(function (entityID, event) { * print("Clicked on entity: " + entityID); * }); * * Script.setTimeout(function () { * Controller.captureEntityClickEvents(); * }, 5000); * * Script.setTimeout(function () { * Controller.releaseEntityClickEvents(); * }, 10000); */ virtual void captureEntityClickEvents(); /**jsdoc * Re-enable {@link Entities.mousePressOnEntity} and {@link Entities.mouseDoublePressOnEntity} events on entities that were * disabled using {@link Controller.captureEntityClickEvents|captureEntityClickEvents}. * @function Controller.releaseEntityClickEvents */ virtual void releaseEntityClickEvents(); /**jsdoc * Get the dimensions of the Interface window's interior if in desktop mode or the HUD surface if in HMD mode. * @function Controller.getViewportDimensions * @returns {Vec2} The dimensions of the Interface window interior if in desktop mode or HUD surface if in HMD mode. */ virtual glm::vec2 getViewportDimensions() const; /**jsdoc * Get the recommended area to position UI on the HUD surface if in HMD mode or Interface's window interior if in desktop * mode. * @function Controller.getRecommendedHUDRect * @returns {Rect} The recommended area in which to position UI. */ virtual QVariant getRecommendedHUDRect() const; /**jsdoc * Enables or disables the virtual game pad that is displayed on certain devices (e.g., Android). * @function Controller.setVPadEnabled * @param {boolean} enable - If <code>true</code> then the virtual game pad doesn't work, otherwise it does work provided * that it is not hidden by {@link Controller.setVPadHidden|setVPadHidden}. * */ virtual void setVPadEnabled(bool enable); /**jsdoc * Shows or hides the virtual game pad that is displayed on certain devices (e.g., Android). * @function Controller.setVPadHidden * @param {boolean} hidden - If <code>true</code> then the virtual game pad is hidden, otherwise it is shown. */ virtual void setVPadHidden(bool hidden); // Call it when a window should hide it /**jsdoc * Sets the amount of extra margin between the virtual game pad that is displayed on certain devices (e.g., Android) and * the bottom of the display. * @function Controller.setVPadExtraBottomMargin * @param {number} margin - Integer number of pixels in the extra margin. */ virtual void setVPadExtraBottomMargin(int margin);signals: /**jsdoc * Triggered when a keyboard key is pressed. * @function Controller.keyPressEvent * @param {KeyEvent} event - Details of the key press. * @returns {Signal} * @example <caption>Report the KeyEvent details for each key press.</caption> * Controller.keyPressEvent.connect(function (event) { * print(JSON.stringify(event)); * }); */ void keyPressEvent(const KeyEvent& event); /**jsdoc * Triggered when a keyboard key is released from being pressed. * @function Controller.keyReleaseEvent * @param {KeyEvent} event - Details of the key release. * @returns {Signal} */ void keyReleaseEvent(const KeyEvent& event); /**jsdoc * Triggered when the mouse moves. * @function Controller.mouseMoveEvent * @param {MouseEvent} event - Details of the mouse movement. * @returns {Signal} * @example <caption>Report the MouseEvent details for each mouse move.</caption> * Controller.mouseMoveEvent.connect(function (event) { * print(JSON.stringify(event)); * }); */ void mouseMoveEvent(const MouseEvent& event); /**jsdoc * Triggered when a mouse button is pressed. * @function Controller.mousePressEvent * @param {MouseEvent} event - Details of the button press. * @returns {Signal} */ void mousePressEvent(const MouseEvent& event); /**jsdoc * Triggered when a mouse button is double-pressed. * @function Controller.mouseDoublePressEvent * @param {MouseEvent} event - Details of the button double-press. * @returns {Signal} */ void mouseDoublePressEvent(const MouseEvent& event); /**jsdoc * Triggered when a mouse button is released from being pressed. * @function Controller.mouseReleaseEvent * @param {MouseEvent} event - Details of the button release. * @returns {Signal} */ void mouseReleaseEvent(const MouseEvent& event); /**jsdoc * Triggered when a touch event starts in the Interface window on a touch-enabled display or device. * @function Controller.touchBeginEvent * @param {TouchEvent} event - Details of the touch begin. * @returns {Signal} * @example <caption>Report the TouchEvent details when a touch event starts.</caption> * Controller.touchBeginEvent.connect(function (event) { * print(JSON.stringify(event)); * }); */ void touchBeginEvent(const TouchEvent& event); /**jsdoc * Triggered when a touch event ends in the Interface window on a touch-enabled display or device. * @function Controller.touchEndEvent * @param {TouchEvent} event - Details of the touch end. * @returns {Signal} */ void touchEndEvent(const TouchEvent& event); /**jsdoc * Triggered when a touch event update occurs in the Interface window on a touch-enabled display or device. * @function Controller.touchUpdateEvent * @param {TouchEvent} event - Details of the touch update. * @returns {Signal} */ void touchUpdateEvent(const TouchEvent& event); /**jsdoc * Triggered when the mouse wheel is rotated. * @function Controller.wheelEvent * @param {WheelEvent} event - Details of the wheel movement. * @returns {Signal} * @example <caption>Report the WheelEvent details for each wheel rotation.</caption> * Controller.wheelEvent.connect(function (event) { * print(JSON.stringify(event)); * }); */ void wheelEvent(const WheelEvent& event);private: QMultiMap<int,KeyEvent> _capturedKeys; QSet<int> _capturedJoysticks; bool _captureEntityClicks; using InputKey = controller::InputController::Key;};const int NUMBER_OF_SPATIALCONTROLS_PER_PALM = 2; // the hand and the tipconst int NUMBER_OF_JOYSTICKS_PER_PALM = 1;const int NUMBER_OF_TRIGGERS_PER_PALM = 1;const int NUMBER_OF_BUTTONS_PER_PALM = 6;const int PALM_SPATIALCONTROL = 0;const int TIP_SPATIALCONTROL = 1;#endif // hifi_ControllerScriptingInterface_h
//
// ControllerScriptingInterface.h
// interface/src/scripting
//
// Created by Brad Hefta-Gaub on 12/17/13.
// Copyright 2013 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_ControllerScriptingInterface_h
#define hifi_ControllerScriptingInterface_h
#include <QtCore/QObject>
#include <controllers/UserInputMapper.h>
#include <controllers/ScriptingInterface.h>
#include <KeyEvent.h>
#include <MouseEvent.h>
#include <SpatialEvent.h>
#include <TouchEvent.h>
#include <WheelEvent.h>
class ScriptEngine;
/**jsdoc
* The Controller API provides facilities to interact with computer and controller hardware.
*
* <h5>Functions</h5>
*
* <p>Properties</p>
* <ul>
* <li>{@link Controller.getActions|getActions}</li>
* <li>{@link Controller.getHardware|getHardware}</li>
* <li>{@link Controller.getStandard|getStandard}</li>
* </ul>
*
* <p>Mappings</p>
* <ul>
* <li>{@link Controller.disableMapping|disableMapping}</li>
* <li>{@link Controller.enableMapping|enableMapping}</li>
* <li>{@link Controller.loadMapping|loadMapping}</li>
* <li>{@link Controller.newMapping|newMapping}</li>
* <li>{@link Controller.parseMapping|parseMapping}</li>
* </ul>
*
* <p>Input, Hardware, and Action Reflection</p>
* <ul>
* <li>{@link Controller.findAction|findAction}</li>
* <li>{@link Controller.findDevice|findDevice}</li>
* <li>{@link Controller.getActionNames|getActionNames}</li>
* <li>{@link Controller.getAllActions|getAllActions}</li>
* <li>{@link Controller.getAvailableInputs|getAvailableInputs}</li>
* <li>{@link Controller.getDeviceName|getDeviceName}</li>
* <li>{@link Controller.getDeviceNames|getDeviceNames}</li>
* </ul>
*
* <p>Input, Hardware, and Action Events</p>
* <ul>
* <li>{@link Controller.actionEvent|actionEvent}</li>
* <li>{@link Controller.hardwareChanged|hardwareChanged}</li>
* <li>{@link Controller.inputEvent|inputEvent}</li>
* </ul>
*
* <p>Mouse, Keyboard, and Touch Events</p>
* <ul>
* <li>{@link Controller.keyPressEvent|keyPressEvent}</li>
* <li>{@link Controller.keyReleaseEvent|keyReleaseEvent}</li>
* <li>{@link Controller.mouseDoublePressEvent|mouseDoublePressEvent}</li>
* <li>{@link Controller.mouseMoveEvent|mouseMoveEvent}</li>
* <li>{@link Controller.mousePressEvent|mousePressEvent}</li>
* <li>{@link Controller.mouseReleaseEvent|mouseReleaseEvent}</li>
* <li>{@link Controller.touchBeginEvent|touchBeginEvent}</li>
* <li>{@link Controller.touchEndEvent|touchEndEvent}</li>
* <li>{@link Controller.touchUpdateEvent|touchUpdateEvent}</li>
* <li>{@link Controller.wheelEvent|wheelEvent}</li>
* </ul>
*
* <p>Control Capturing</p>
* <ul>
* <li>{@link Controller.captureMouseEvents|captureMouseEvents}</li>
* <li>{@link Controller.captureTouchEvents|captureTouchEvents}</li>
* <li>{@link Controller.captureWheelEvents|captureWheelEvents}</li>
* <li>{@link Controller.releaseMouseEvents|releaseMouseEvents}</li>
* <li>{@link Controller.releaseTouchEvents|releaseTouchEvents}</li>
* <li>{@link Controller.releaseWheelEvents|releaseWheelEvents}</li>
* </ul>
*
* <p>Action Capturing</p>
* <ul>
* <li>{@link Controller.captureActionEvents|captureActionEvents}</li>
* <li>{@link Controller.captureEntityClickEvents|captureEntityClickEvents}</li>
* <li>{@link Controller.captureJoystick|captureJoystick}</li>
* <li>{@link Controller.captureKeyEvents|captureKeyEvents}</li>
* <li>{@link Controller.releaseActionEvents|releaseActionEvents}</li>
* <li>{@link Controller.releaseEntityClickEvents|releaseEntityClickEvents}</li>
* <li>{@link Controller.releaseJoystick|releaseJoystick}</li>
* <li>{@link Controller.releaseKeyEvents|releaseKeyEvents}</li>
* </ul>
*
* <p>Controller and Action Values</p>
* <ul>
* <li>{@link Controller.getValue|getValue}</li>
* <li>{@link Controller.getAxisValue|getAxisValue}</li>
* <li>{@link Controller.getPoseValue|getgetPoseValue}</li>
* <li>{@link Controller.getActionValue|getActionValue}</li>
* </ul>
*
* <p>Haptics</p>
* <ul>
* <li>{@link Controller.triggerHapticPulse|triggerHapticPulse}</li>
* <li>{@link Controller.triggerHapticPulseOnDevice|triggerHapticPulseOnDevice}</li>
* <li>{@link Controller.triggerShortHapticPulse|triggerShortHapticPulse}</li>
* <li>{@link Controller.triggerShortHapticPulseOnDevice|triggerShortHapticPulseOnDevice}</li>
* </ul>
*
* <p>Display Information</p>
* <ul>
* <li>{@link Controller.getViewportDimensions|getViewportDimensions}</li>
* <li>{@link Controller.getRecommendedHUDRect|getRecommendedHUDRect}</li>
* </ul>
*
* <p>Virtual Game Pad</p>
* <ul>
* <li>{@link Controller.setVPadEnabled|setVPadEnabled}</li>
* <li>{@link Controller.setVPadHidden|setVPadHidden}</li>
* <li>{@link Controller.setVPadExtraBottomMargin|setVPadExtraBottomMargin}</li>
* </ul>
*
* <p>Input Recordings</p>
* <ul>
* <li>{@link Controller.startInputRecording|startInputRecording}</li>
* <li>{@link Controller.stopInputRecording|stopInputRecording}</li>
* <li>{@link Controller.saveInputRecording|saveInputRecording}</li>
* <li>{@link Controller.getInputRecorderSaveDirectory|getInputRecorderSaveDirectory}</li>
* <li>{@link Controller.loadInputRecording|loadInputRecording}</li>
* <li>{@link Controller.startInputPlayback|startInputPlayback}</li>
* <li>{@link Controller.stopInputPlayback|stopInputPlayback}</li>
* </ul>
*
* <h5>Entity Methods:</h5>
*
* <p>The default scripts implement hand controller actions that use {@link Entities.callEntityMethod} to call entity script
* methods, if present in the entity being interacted with.</p>
*
* <table>
* <thead>
* <tr><th>Method Name</th><th>Description</th><th>Example</th></tr>
* </thead>
* <tbody>
* <tr>
* <td><code>startFarTrigger</code><br /><code>continueFarTrigger</code><br /><code>stopFarTrigger</code></td>
* <td>These methods are called when a user is more than 0.3m away from the entity, the entity is triggerable, and the
* user starts, continues, or stops squeezing the trigger.</td>
* </td>
* <td>A light switch that can be toggled on and off from a distance.</td>
* </tr>
* <tr>
* <td><code>startNearTrigger</code><br /><code>continueNearTrigger</code><br /><code>stopNearTrigger</code></td>
* <td>These methods are called when a user is less than 0.3m away from the entity, the entity is triggerable, and the
* user starts, continues, or stops squeezing the trigger.</td>
* <td>A doorbell that can be rung when a user is near.</td>
* </tr>
* <tr>
* <td><code>startDistanceGrab</code><br /><code>continueDistanceGrab</code><br /></td>
* <td>These methods are called when a user is more than 0.3m away from the entity, the entity is either cloneable, or
* grabbable and not locked, and the user starts or continues to squeeze the trigger.</td>
* <td>A comet that emits icy particle trails when a user is dragging it through the sky.</td>
* </tr>
* <tr>
* <td><code>startNearGrab</code><br /><code>continueNearGrab</code><br /></td>
* <td>These methods are called when a user is less than 0.3m away from the entity, the entity is either cloneable, or
* grabbable and not locked, and the user starts or continues to squeeze the trigger.</td>
* <td>A ball that glows when it's being held close.</td>
* </tr>
* <tr>
* <td><code>releaseGrab</code></td>
* <td>This method is called when a user releases the trigger when having been either distance or near grabbing an
* entity.</td>
* <td>Turn off the ball glow or comet trail with the user finishes grabbing it.</td>
* </tr>
* <tr>
* <td><code>startEquip</code><br /><code>continueEquip</code><br /><code>releaseEquip</code></td>
* <td>These methods are called when a user starts, continues, or stops equipping an entity.</td>
* <td>A glass that stays in the user's hand after the trigger is clicked.</td>
* </tr>
* </tbody>
* </table>
* <p>All the entity methods are called with the following two arguments:</p>
* <ul>
* <li>The entity ID.</li>
* <li>A string, <code>"hand,userID"</code> — where "hand" is <code>"left"</code> or <code>"right"</code>, and "userID"
* is the user's {@link MyAvatar|MyAvatar.sessionUUID}.</li>
* </ul>
*
* @namespace Controller
*
* @hifi-interface
* @hifi-client-entity
*
* @property {Controller.Actions} Actions - Predefined actions on Interface and the user's avatar. These can be used as end
* points in a {@link RouteObject} mapping. A synonym for <code>Controller.Hardware.Actions</code>.
* <em>Read-only.</em><br />
* Default mappings are provided from the <code>Controller.Hardware.Keyboard</code> and <code>Controller.Standard</code> to
* actions in
* <a href="https://github.com/highfidelity/hifi/blob/master/interface/resources/controllers/keyboardMouse.json">
* keyboardMouse.json</a> and
* <a href="https://github.com/highfidelity/hifi/blob/master/interface/resources/controllers/standard.json">
* standard.json</a>, respectively.
*
* @property {Controller.Hardware} Hardware - Standard and hardware-specific controller and computer outputs, plus predefined
* actions on Interface and the user's avatar. The outputs can be mapped to <code>Actions</code> or functions in a
* {@link RouteObject} mapping. Additionally, hardware-specific controller outputs can be mapped to <code>Standard</code>
* controller outputs. <em>Read-only.</em>
*
* @property {Controller.Standard} Standard - Standard controller outputs that can be mapped to <code>Actions</code> or
* functions in a {@link RouteObject} mapping. <em>Read-only.</em><br />
* Each hardware device has a mapping from its outputs to <code>Controller.Standard</code> items, specified in a JSON file.
* For example, <a href="https://github.com/highfidelity/hifi/blob/master/interface/resources/controllers/leapmotion.json">
* leapmotion.json</a> and
* <a href="https://github.com/highfidelity/hifi/blob/master/interface/resources/controllers/vive.json">vive.json</a>.
*/
/// handles scripting of input controller commands from JS
class ControllerScriptingInterface : public controller::ScriptingInterface {
Q_OBJECT
public:
virtual ~ControllerScriptingInterface() {}
void emitKeyPressEvent(QKeyEvent* event);
void emitKeyReleaseEvent(QKeyEvent* event);
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);
void emitTouchUpdateEvent(const TouchEvent& event);
void emitWheelEvent(QWheelEvent* event);
bool isKeyCaptured(QKeyEvent* event) const;
bool isKeyCaptured(const KeyEvent& event) const;
bool isJoystickCaptured(int joystickIndex) const;
bool areEntityClicksCaptured() const;
public slots:
/**jsdoc
* Disable default Interface actions for a particular key event.
* @function Controller.captureKeyEvents
* @param {KeyEvent} event - Details of the key event to be captured. The <code>key</code> property must be specified. The
* <code>text</code> property is ignored. The other properties default to <code>false</code>.
* @example <caption>Disable left and right strafing.</caption>
* var STRAFE_LEFT = { "key": 16777234, isShifted: true };
* var STRAFE_RIGHT = { "key": 16777236, isShifted: true };
*
* Controller.captureKeyEvents(STRAFE_LEFT);
* Controller.captureKeyEvents(STRAFE_RIGHT);
*
* Script.scriptEnding.connect(function () {
* Controller.releaseKeyEvents(STRAFE_LEFT);
* Controller.releaseKeyEvents(STRAFE_RIGHT);
* });
*/
virtual void captureKeyEvents(const KeyEvent& event);
/**jsdoc
* Re-enable default Interface actions for a particular key event that has been disabled using
* {@link Controller.captureKeyEvents|captureKeyEvents}.
* @function Controller.releaseKeyEvents
* @param {KeyEvent} event - Details of the key event to release from capture. The <code>key</code> property must be
* specified. The <code>text</code> property is ignored. The other properties default to <code>false</code>.
*/
virtual void releaseKeyEvents(const KeyEvent& event);
/**jsdoc
* Disable default Interface actions for a joystick.
* @function Controller.captureJoystick
* @param {number} joystickID - The integer ID of the joystick.
* @deprecated This function no longer has any effect.
*/
virtual void captureJoystick(int joystickIndex);
/**jsdoc
* Re-enable default Interface actions for a joystick that has been disabled using
* {@link Controller.captureJoystick|captureJoystick}.
* @function Controller.releaseJoystick
* @param {number} joystickID - The integer ID of the joystick.
* @deprecated This function no longer has any effect.
*/
virtual void releaseJoystick(int joystickIndex);
/**jsdoc
* Disable {@link Entities.mousePressOnEntity} and {@link Entities.mouseDoublePressOnEntity} events on entities.
* @function Controller.captureEntityClickEvents
* @example <caption>Disable entity click events for a short period.</caption>
* Entities.mousePressOnEntity.connect(function (entityID, event) {
* print("Clicked on entity: " + entityID);
* });
*
* Script.setTimeout(function () {
* Controller.captureEntityClickEvents();
* }, 5000);
*
* Script.setTimeout(function () {
* Controller.releaseEntityClickEvents();
* }, 10000);
*/
virtual void captureEntityClickEvents();
/**jsdoc
* Re-enable {@link Entities.mousePressOnEntity} and {@link Entities.mouseDoublePressOnEntity} events on entities that were
* disabled using {@link Controller.captureEntityClickEvents|captureEntityClickEvents}.
* @function Controller.releaseEntityClickEvents
*/
virtual void releaseEntityClickEvents();
/**jsdoc
* Get the dimensions of the Interface window's interior if in desktop mode or the HUD surface if in HMD mode.
* @function Controller.getViewportDimensions
* @returns {Vec2} The dimensions of the Interface window interior if in desktop mode or HUD surface if in HMD mode.
*/
virtual glm::vec2 getViewportDimensions() const;
/**jsdoc
* Get the recommended area to position UI on the HUD surface if in HMD mode or Interface's window interior if in desktop
* mode.
* @function Controller.getRecommendedHUDRect
* @returns {Rect} The recommended area in which to position UI.
*/
virtual QVariant getRecommendedHUDRect() const;
/**jsdoc
* Enables or disables the virtual game pad that is displayed on certain devices (e.g., Android).
* @function Controller.setVPadEnabled
* @param {boolean} enable - If <code>true</code> then the virtual game pad doesn't work, otherwise it does work provided
* that it is not hidden by {@link Controller.setVPadHidden|setVPadHidden}.
*
*/
virtual void setVPadEnabled(bool enable);
/**jsdoc
* Shows or hides the virtual game pad that is displayed on certain devices (e.g., Android).
* @function Controller.setVPadHidden
* @param {boolean} hidden - If <code>true</code> then the virtual game pad is hidden, otherwise it is shown.
*/
virtual void setVPadHidden(bool hidden); // Call it when a window should hide it
/**jsdoc
* Sets the amount of extra margin between the virtual game pad that is displayed on certain devices (e.g., Android) and
* the bottom of the display.
* @function Controller.setVPadExtraBottomMargin
* @param {number} margin - Integer number of pixels in the extra margin.
*/
virtual void setVPadExtraBottomMargin(int margin);
signals:
/**jsdoc
* Triggered when a keyboard key is pressed.
* @function Controller.keyPressEvent
* @param {KeyEvent} event - Details of the key press.
* @returns {Signal}
* @example <caption>Report the KeyEvent details for each key press.</caption>
* Controller.keyPressEvent.connect(function (event) {
* print(JSON.stringify(event));
* });
*/
void keyPressEvent(const KeyEvent& event);
/**jsdoc
* Triggered when a keyboard key is released from being pressed.
* @function Controller.keyReleaseEvent
* @param {KeyEvent} event - Details of the key release.
* @returns {Signal}
*/
void keyReleaseEvent(const KeyEvent& event);
/**jsdoc
* Triggered when the mouse moves.
* @function Controller.mouseMoveEvent
* @param {MouseEvent} event - Details of the mouse movement.
* @returns {Signal}
* @example <caption>Report the MouseEvent details for each mouse move.</caption>
* Controller.mouseMoveEvent.connect(function (event) {
* print(JSON.stringify(event));
* });
*/
void mouseMoveEvent(const MouseEvent& event);
/**jsdoc
* Triggered when a mouse button is pressed.
* @function Controller.mousePressEvent
* @param {MouseEvent} event - Details of the button press.
* @returns {Signal}
*/
void mousePressEvent(const MouseEvent& event);
/**jsdoc
* Triggered when a mouse button is double-pressed.
* @function Controller.mouseDoublePressEvent
* @param {MouseEvent} event - Details of the button double-press.
* @returns {Signal}
*/
void mouseDoublePressEvent(const MouseEvent& event);
/**jsdoc
* Triggered when a mouse button is released from being pressed.
* @function Controller.mouseReleaseEvent
* @param {MouseEvent} event - Details of the button release.
* @returns {Signal}
*/
void mouseReleaseEvent(const MouseEvent& event);
/**jsdoc
* Triggered when a touch event starts in the Interface window on a touch-enabled display or device.
* @function Controller.touchBeginEvent
* @param {TouchEvent} event - Details of the touch begin.
* @returns {Signal}
* @example <caption>Report the TouchEvent details when a touch event starts.</caption>
* Controller.touchBeginEvent.connect(function (event) {
* print(JSON.stringify(event));
* });
*/
void touchBeginEvent(const TouchEvent& event);
/**jsdoc
* Triggered when a touch event ends in the Interface window on a touch-enabled display or device.
* @function Controller.touchEndEvent
* @param {TouchEvent} event - Details of the touch end.
* @returns {Signal}
*/
void touchEndEvent(const TouchEvent& event);
/**jsdoc
* Triggered when a touch event update occurs in the Interface window on a touch-enabled display or device.
* @function Controller.touchUpdateEvent
* @param {TouchEvent} event - Details of the touch update.
* @returns {Signal}
*/
void touchUpdateEvent(const TouchEvent& event);
/**jsdoc
* Triggered when the mouse wheel is rotated.
* @function Controller.wheelEvent
* @param {WheelEvent} event - Details of the wheel movement.
* @returns {Signal}
* @example <caption>Report the WheelEvent details for each wheel rotation.</caption>
* Controller.wheelEvent.connect(function (event) {
* print(JSON.stringify(event));
* });
*/
void wheelEvent(const WheelEvent& event);
private:
QMultiMap<int,KeyEvent> _capturedKeys;
QSet<int> _capturedJoysticks;
bool _captureEntityClicks;
using InputKey = controller::InputController::Key;
};
const int NUMBER_OF_SPATIALCONTROLS_PER_PALM = 2; // the hand and the tip
const int NUMBER_OF_JOYSTICKS_PER_PALM = 1;
const int NUMBER_OF_TRIGGERS_PER_PALM = 1;
const int NUMBER_OF_BUTTONS_PER_PALM = 6;
const int PALM_SPATIALCONTROL = 0;
const int TIP_SPATIALCONTROL = 1;
#endif // hifi_ControllerScriptingInterface_h