Controller API JSDoc

This commit is contained in:
David Rowe 2018-04-17 11:46:40 +12:00
parent 7c65c9c444
commit 9f83c606e9
19 changed files with 2229 additions and 19 deletions

View file

@ -688,6 +688,34 @@ private:
}
};
/**jsdoc
* <p>The <code>Controller.Hardware.Application</code> object has properties representing Interface's state. The property
* values are integer IDs, uniquely identifying each output. <em>Read-only.</em> These can be can be mapped to actions or
* functions or <code>Controller.Standard</code> items in a {@link RouteObject} mapping. Each data value is either
* <code>1.0</code> for "true" or <code>0.0</code> for "false".</p>
* <table>
* <thead>
* <tr><th>Property</th><th>Type</th><th>Data</th><th>Description</th></tr>
* </thead>
* <tbody>
* <tr><td><code>CameraFirstPerson</code></td><td>number</td><td>number</td><td>The camera is in first-person mode.
* </td></tr>
* <tr><td><code>CameraThirdPerson</code></td><td>number</td><td>number</td><td>The camera is in third-person mode.
* </td></tr>
* <tr><td><code>CameraFSM</code></td><td>number</td><td>number</td><td>The camera is in full screen mirror mode.</td></tr>
* <tr><td><code>CameraIndependent</code></td><td>number</td><td>number</td><td>The camera is in independent mode.</td></tr>
* <tr><td><code>CameraEntity</code></td><td>number</td><td>number</td><td>The camera is in entity mode.</td></tr>
* <tr><td><code>NavigationFocused</code></td><td>number</td><td>number</td><td><strong>TODO</strong></td></tr>
* <tr><td><code>InHMD</code></td><td>number</td><td>number</td><td>The user is in HMD mode.</td></tr>
* <tr><td><code>AdvancedMovement</code></td><td>number</td><td>number</td><td>Advanced movement controls are enabled.
* </td></tr>
* <tr><td><code>SnapTurn</code></td><td>number</td><td>number</td><td>Snap turn is enabled.</td></tr>
* <tr><td><code>Grounded</code></td><td>number</td><td>number</td><td>The user's avatar is on the ground.</td></tr>
* </tbody>
* </table>
* @typedef Controller.Hardware-Application
*/
static const QString STATE_IN_HMD = "InHMD";
static const QString STATE_CAMERA_FULL_SCREEN_MIRROR = "CameraFSM";
static const QString STATE_CAMERA_FIRST_PERSON = "CameraFirstPerson";

View file

@ -24,11 +24,154 @@
#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.getButtonValue|getButtonValue} for a particular device</li>
* <li>{@link Controller.getAxisValue(0)|getAxisValue} for a particular device</li>
* <li>{@link Controller.getPoseValue(0)|getPoseValue} for a particular device</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>
*
* @namespace Controller
*
* @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() {}
@ -53,40 +196,214 @@ public:
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 margins 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 of 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:
QString sanatizeName(const QString& name); /// makes a name clean for inclusing in JavaScript
QMultiMap<int,KeyEvent> _capturedKeys;
QSet<int> _capturedJoysticks;
bool _captureEntityClicks;

View file

@ -33,6 +33,282 @@ namespace controller {
return std::make_shared<ActionEndpoint>(input);
}
/**jsdoc
* <p>The <code>Controller.Actions</code> object has properties representing predefined actions on the user's avatar and
* Interface. The property values are integer IDs, uniquely identifying each action. <em>Read-only.</em> These can be used
* as end points in the routes of a {@link MappingObject}. The data routed to each action is either a number or a
* {@link Pose}.</p>
*
* <table>
* <thead>
* <tr><th>Property</th><th>Type</th><th>Data</th><th>Description</th></tr>
* </thead>
* <tbody>
* <tr><td colSpan=4><strong>Avatar Movement</strong></td>
* <tr><td><code>TranslateX</code></td><td>number</td><td>number</td><td>Move the user's avatar in the direction of its
* x-axis, if the camera isn't in independent or mirror modes.</td></tr>
* <tr><td><code>TranslateY</code></td><td>number</td><td>number</td><td>Move the user's avatar in the direction of its
* y-axis, if the camera isn't in independent or mirror modes.</td></tr>
* <tr><td><code>TranslateZ</code></td><td>number</td><td>number</td><td>Move the user's avatar in the direction of its
* z-axis, if the camera isn't in independent or mirror modes.</td></tr>
* <tr><td><code>Pitch</code></td><td>number</td><td>number</td><td>Rotate the user's avatar head and attached camera
* about its negative x-axis (i.e., positive values pitch down), if the camera isn't in HMD, independent, or mirror
* modes.</td></tr>
* <tr><td><code>Yaw</code></td><td>number</td><td>number</td><td>Rotate the user's avatar about its y-axis, if the
* camera isn't in independent or mirror modes.</td></tr>
* <tr><td><code>Roll</code></td><td>number</td><td>number</td><td>No action.</td></tr>
* <tr><td><code>StepTranslateX</code></td><td>number</td><td>number</td><td>No action.</td></tr>
* <tr><td><code>StepTranslateY</code></td><td>number</td><td>number</td><td>No action.</td></tr>
* <tr><td><code>StepTranslateZ</code></td><td>number</td><td>number</td><td>No action.</td></tr>
* <tr><td><code>StepPitch</code></td><td>number</td><td>number</td><td>No action.</td></tr>
* <tr><td><code>StepYaw</code></td><td>number</td><td>number</td><td>Rotate the user's avatar about its y-axis in a
* step increment, if the camera isn't in independent or mirror modes.</td></tr>
* <tr><td><code>StepRoll</code></td><td>number</td><td>number</td><td>No action.</td></tr>
*
* <tr><td colSpan=4><strong>Avatar Skeleton</strong></td>
* <tr><td><code>Hips</code></td><td>number</td><td>{@link Pose}</td><td>Set the hips pose of the user's avatar.
* </td></tr>
* <tr><td><code>Spine2</code></td><td>number</td><td>{@link Pose}</td><td>Set the spine2 pose of the user's avatar.
* </td></tr>
* <tr><td><code>Head</code></td><td>number</td><td>{@link Pose}</td><td>Set the head pose of the user's avatar.
* </td></tr>
* <tr><td><code>LeftArm</code></td><td>number</td><td>{@link Pose}</td><td>Set the left arm pose of the user's avatar.
* </td></tr>
* <tr><td><code>RightArm</code></td><td>number</td><td>{@link Pose}</td><td>Set the right arm pose of the user's
* avatar.</td></tr>
* <tr><td><code>LeftHand</code></td><td>number</td><td>{@link Pose}</td><td>Set the left hand pose of the user's
* avatar.</td></tr>
* <tr><td><code>LeftHandThumb1</code></td><td>number</td><td>{@link Pose}</td><td>Set the left thumb 1 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>LeftHandThumb2</code></td><td>number</td><td>{@link Pose}</td><td>Set the left thumb 2 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>LeftHandThumb3</code></td><td>number</td><td>{@link Pose}</td><td>Set the left thumb 3 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>LeftHandThumb4</code></td><td>number</td><td>{@link Pose}</td><td>Set the left thumb 4 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>LeftHandIndex1</code></td><td>number</td><td>{@link Pose}</td><td>Set the left index 1 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>LeftHandIndex2</code></td><td>number</td><td>{@link Pose}</td><td>Set the left index 2 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>LeftHandIndex3</code></td><td>number</td><td>{@link Pose}</td><td>Set the left index 3 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>LeftHandIndex4</code></td><td>number</td><td>{@link Pose}</td><td>Set the left index 4 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>LeftHandMiddle1</code></td><td>number</td><td>{@link Pose}</td><td>Set the left middle 1 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>LeftHandMiddle2</code></td><td>number</td><td>{@link Pose}</td><td>Set the left middle 2 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>LeftHandMiddle3</code></td><td>number</td><td>{@link Pose}</td><td>Set the left middle 3 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>LeftHandMiddle4</code></td><td>number</td><td>{@link Pose}</td><td>Set the left middle 4 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>LeftHandRing1</code></td><td>number</td><td>{@link Pose}</td><td>Set the left ring 1 finger joint pose
* of the user's avatar.</td></tr>
* <tr><td><code>LeftHandRing2</code></td><td>number</td><td>{@link Pose}</td><td>Set the left ring 2 finger joint pose
* of the user's avatar.</td></tr>
* <tr><td><code>LeftHandRing3</code></td><td>number</td><td>{@link Pose}</td><td>Set the left ring 3 finger joint pose
* of the user's avatar.</td></tr>
* <tr><td><code>LeftHandRing4</code></td><td>number</td><td>{@link Pose}</td><td>Set the left ring 4 finger joint pose
* of the user's avatar.</td></tr>
* <tr><td><code>LeftHandPinky1</code></td><td>number</td><td>{@link Pose}</td><td>Set the left pinky 1 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>LeftHandPinky2</code></td><td>number</td><td>{@link Pose}</td><td>Set the left pinky 2 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>LeftHandPinky3</code></td><td>number</td><td>{@link Pose}</td><td>Set the left pinky 3 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>LeftHandPinky4</code></td><td>number</td><td>{@link Pose}</td><td>Set the left pinky 4 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>RightHand</code></td><td>number</td><td>{@link Pose}</td><td>Set the right hand of the user's avatar.
* </td></tr>
* <tr><td><code>RightHandThumb1</code></td><td>number</td><td>{@link Pose}</td><td>Set the right thumb 1 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>RightHandThumb2</code></td><td>number</td><td>{@link Pose}</td><td>Set the right thumb 2 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>RightHandThumb3</code></td><td>number</td><td>{@link Pose}</td><td>Set the right thumb 3 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>RightHandThumb4</code></td><td>number</td><td>{@link Pose}</td><td>Set the right thumb 4 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>RightHandIndex1</code></td><td>number</td><td>{@link Pose}</td><td>Set the right index 1 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>RightHandIndex2</code></td><td>number</td><td>{@link Pose}</td><td>Set the right index 2 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>RightHandIndex3</code></td><td>number</td><td>{@link Pose}</td><td>Set the right index 3 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>RightHandIndex4</code></td><td>number</td><td>{@link Pose}</td><td>Set the right index 4 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>RightHandMiddle1</code></td><td>number</td><td>{@link Pose}</td><td>Set the right middle 1 finger
* joint pose of the user's avatar.</td></tr>
* <tr><td><code>RightHandMiddle2</code></td><td>number</td><td>{@link Pose}</td><td>Set the right middle 2 finger
* joint pose of the user's avatar.</td></tr>
* <tr><td><code>RightHandMiddle3</code></td><td>number</td><td>{@link Pose}</td><td>Set the right middle 3 finger
* joint pose of the user's avatar.</td></tr>
* <tr><td><code>RightHandMiddle4</code></td><td>number</td><td>{@link Pose}</td><td>Set the right middle 4 finger
* joint pose of the user's avatar.</td></tr>
* <tr><td><code>RightHandRing1</code></td><td>number</td><td>{@link Pose}</td><td>Set the right ring 1 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>RightHandRing2</code></td><td>number</td><td>{@link Pose}</td><td>Set the right ring 2 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>RightHandRing3</code></td><td>number</td><td>{@link Pose}</td><td>Set the right ring 3 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>RightHandRing4</code></td><td>number</td><td>{@link Pose}</td><td>Set the right ring 4 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>RightHandPinky1</code></td><td>number</td><td>{@link Pose}</td><td>Set the right pinky 1 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>RightHandPinky2</code></td><td>number</td><td>{@link Pose}</td><td>Set the right pinky 2 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>RightHandPinky3</code></td><td>number</td><td>{@link Pose}</td><td>Set the right pinky 3 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>RightHandPinky4</code></td><td>number</td><td>{@link Pose}</td><td>Set the right pinky 4 finger joint
* pose of the user's avatar.</td></tr>
* <tr><td><code>LeftFoot</code></td><td>number</td><td>{@link Pose}</td><td>Set the left foot pose of the user's
* avatar.</td></tr>
* <tr><td><code>RightFoot</code></td><td>number</td><td>{@link Pose}</td><td>Set the right foot pose of the user's
* avatar.</td></tr>
*
* <tr><td colSpan=4><strong><strong>Application</strong></td>
* <tr><td><code>BoomIn</code></td><td>number</td><td>number</td><td>Zoom camera in from third person toward first
* person view.</td></tr>
* <tr><td><code>BoomOut</code></td><td>number</td><td>number</td><td>Zoom camera out from first person to third
* person view.</td></tr>
* <tr><td><code>CycleCamera</code></td><td>number</td><td>number</td><td>Cycle the camera view from first person, to
* third person, to full screen mirror, then back to first person and repeat.</td></tr>
* <tr><td><code>ContextMenu</code></td><td>number</td><td>number</td><td>Show / hide the tablet.</td></tr>
* <tr><td><code>ToggleMute</code></td><td>number</td><td>number</td><td>Toggle the microphone mute.</td></tr>
* <tr><td><code>ToggleOverlay</code></td><td>number</td><td>number</td><td>Toggle the display of overlays.</td></tr>
* <tr><td><code>Sprint</code></td><td>number</td><td>number</td><td>Set avatar sprint mode.</td></tr>
* <tr><td><code>ReticleClick</code></td><td>number</td><td>number</td><td>Set mouse-pressed.</td></tr>
* <tr><td><code>ReticleX</code></td><td>number</td><td>number</td><td>Move the cursor left/right in the x direction.
* </td></tr>
* <tr><td><code>ReticleY</code></td><td>number</td><td>number</td><td>move the cursor up/down in the y direction.
* </td></tr>
* <tr><td><code>ReticleLeft</code></td><td>number</td><td>number</td><td>Move the cursor left.</td></tr>
* <tr><td><code>ReticleRight</code></td><td>number</td><td>number</td><td>Move the cursor right.</td></tr>
* <tr><td><code>ReticleUp</code></td><td>number</td><td>number</td><td>Move the cursor up.</td></tr>
* <tr><td><code>ReticleDown</code></td><td>number</td><td>number</td><td>Move the cursor down.</td></tr>
* <tr><td><code>UiNavLateral</code></td><td>number</td><td>number</td><td>Generate a keyboard left or right arrow key
* event.</td></tr>
* <tr><td><code>UiNavVertical</code></td><td>number</td><td>number</td><td>Generate a keyboard up or down arrow key
* event.</td></tr>
* <tr><td><code>UiNavGroup</code></td><td>number</td><td>number</td><td>Generate a keyboard tab or back-tab key event.
* </td></tr>
* <tr><td><code>UiNavSelect</code></td><td>number</td><td>number</td><td>Generate keyboard an Enter key event.
* </td></tr>
* <tr><td><code>UiNavBack</code></td><td>number</td><td>number</td><td>Generate keyboard an Esc key event.</td></tr>
* <tr><td><code>LeftHandClick</code></td><td>number</td><td>number</td><td><strong>Deprecated: </strong>: No action.
* </td></tr>
* <tr><td><code>RightHandClick</code></td><td>number</td><td>number</td><td><strong>Deprecated:</strong>: No action.
* </td></tr>
* <tr><td><code>Shift</code></td><td>number</td><td>number</td><td><strong>Deprecated:</strong>: No action.</td></tr>
* <tr><td><code>PrimaryAction</code></td><td>number</td><td>number</td><td><strong>Deprecated: </strong>: No action.
* </td></tr>
* <tr><td><code>SecondaryAction</code></td><td>number</td><td>number</td><td><strong>Deprecated:</strong>: No action.
* </td></tr>
*
* <tr><td colSpan=4><strong>Aliases</strong></td>
* <tr><td><code>Backward</code></td><td>number</td><td>number</td><td>Alias for <code>TranslateZ</code> in the
* positive direction.</td></tr>
* <tr><td><code>Forward</code></td><td>number</td><td>number</td><td>Alias for <code>TranslateZ<code> in the negative
* direction.</td></tr>
* <tr><td><code>StrafeRight</code></td><td>number</td><td>number</td><td>Alias for <code>TranslateX</code> in the
* positive direction.</td></tr>
* <tr><td><code>StrafeLeft</code></td><td>number</td><td>number</td><td>Alias for <code>TranslateX</code> in the
* negative direction.</td></tr>
* <tr><td><code>Up</code></td><td>number</td><td>number</td><td>Alias for <code>TranslateY</code> in the positive
* direction.</td></tr>
* <tr><td><code>Down</code></td><td>number</td><td>number</td><td>Alias for <code>TranslateY</code> in the negative
* direction.</td></tr>
* <tr><td><code>PitchDown</code></td><td>number</td><td>number</td><td>Alias for <code>Pitch</code> in the positive
* direction.</td></tr>
* <tr><td><code>PitchUp</code></td><td>number</td><td>number</td><td>Alias for <code>Pitch</code> in the negative
* direction.</td></tr>
* <tr><td><code>YawLeft</code></td><td>number</td><td>number</td><td>Alias of <code>Yaw</code> in the positive
* direction.</td></tr>
* <tr><td><code>YawRight</code></td><td>number</td><td>number</td><td>Alias for <code>Yaw</code> in the negative
* direction.</td></tr>
*
* <tr><td colSpan=4><strong>Deprecated Aliases</strong></td>
* <tr><td><code>LEFT_HAND</code></td><td>number</td><td>{@link Pose}</td><td><strong>Deprecated:</strong> Use
* <code>LeftHand</code> instead.</td></tr>
* <tr><td><code>RIGHT_HAND</code></td><td>number</td><td>{@link Pose}</td><td><strong>Deprecated:</strong> Use
* <code>RightHand</code> instead.</td></tr>
* <tr><td><code>BOOM_IN</code></td><td>number</td><td>number</td><td><strong>Deprecated:</strong> Use
* <code>BoomIn</code> instead.</td></tr>
* <tr><td><code>BOOM_OUT</code></td><td>number</td><td>number</td><td><strong>Deprecated:</strong> Use
* <code>BoomOut</code> instead.</td></tr>
* <tr><td><code>CONTEXT_MENU</code></td><td>number</td><td>number</td><td><strong>Deprecated:</strong> Use
* <code>ContextMenu</code> instead.</td></tr>
* <tr><td><code>TOGGLE_MUTE</code></td><td>number</td><td>number</td><td><strong>Deprecated:</strong> Use
* <code>ToggleMute</code> instead.</td></tr>
* <tr><td><code>SPRINT</code></td><td>number</td><td>number</td><td><strong>Deprecated:</strong> Use
* <code>Sprint</code> instead.</td></tr>
* <tr><td><code>LONGITUDINAL_BACKWARD</code></td><td>number</td><td>number</td><td><strong>Deprecated:</strong> Use
* <code>Backward</code> instead.</td></tr>
* <tr><td><code>LONGITUDINAL_FORWARD</code></td><td>number</td><td>number</td><td><strong>Deprecated:</strong> Use
* <code>Forward</code> instead.</td></tr>
* <tr><td><code>LATERAL_LEFT</code></td><td>number</td><td>number</td><td><strong>Deprecated:</strong> Use
* <code>StrafeLeft</code> instead.</td></tr>
* <tr><td><code>LATERAL_RIGHT</code></td><td>number</td><td>number</td><td><strong>Deprecated:</strong> Use
* <code>StrafeRight</code> instead.</td></tr>
* <tr><td><code>VERTICAL_UP</code></td><td>number</td><td>number</td><td><strong>Deprecated:</strong> Use
* <code>Up</code> instead.</td></tr>
* <tr><td><code>VERTICAL_DOWN</code></td><td>number</td><td>number</td><td><strong>Deprecated:</strong> Use
* <code>Down</code> instead.</td></tr>
* <tr><td><code>PITCH_DOWN</code></td><td>number</td><td>number</td><td><strong>Deprecated:</strong> Use
* <code>PitchDown</code> instead.</td></tr>
* <tr><td><code>PITCH_UP</code></td><td>number</td><td>number</td><td><strong>Deprecated:</strong> Use
* <code>PitchUp</code> instead.</td></tr>
* <tr><td><code>YAW_LEFT</code></td><td>number</td><td>number</td><td><strong>Deprecated:</strong> Use
* <code>YawLeft</code> instead.</td></tr>
* <tr><td><code>YAW_RIGHT</code></td><td>number</td><td>number</td><td><strong>Deprecated:</strong> Use
* <code>YawRight</code> instead.</td></tr>
* <tr><td><code>LEFT_HAND_CLICK</code></td><td>number</td><td>number</td><td><strong>Deprecated:</strong> Use
* <code>LeftHandClick</code> instead.</td></tr>
* <tr><td><code>RIGHT_HAND_CLICK</code></td><td>number</td><td>number</td><td><strong>Deprecated:</strong> Use
* <code>RightHandClick</code> instead.</td></tr>
* <tr><td><code>SHIFT</code></td><td>number</td><td>number</td><td><strong>Deprecated:</strong> Use
* <code>Shift</code> instead.</td></tr>
* <tr><td><code>ACTION1</code></td><td>number</td><td>number</td><td><strong>Deprecated:</strong> Use
* <code>PrimaryAction</code> instead.</td></tr>
* <tr><td><code>ACTION2</code></td><td>number</td><td>number</td><td><strong>Deprecated:</strong> Use
* <code>SecondaryAction</code> instead.</td></tr>
*
* <tr><td colSpan=4><strong>Deprecated Trackers</strong></td>
* <tr><td><code>TrackedObject00</code></td><td>number</td><td>{@link Pose}</td><td><strong>Deprecated: </strong> No
* action.</td></tr>
* <tr><td><code>TrackedObject01</code></td><td>number</td><td>{@link Pose}</td><td><strong>Deprecated: </strong> No
* action.</td></tr>
* <tr><td><code>TrackedObject02</code></td><td>number</td><td>{@link Pose}</td><td><strong>Deprecated: </strong> No
* action.</td></tr>
* <tr><td><code>TrackedObject03</code></td><td>number</td><td>{@link Pose}</td><td><strong>Deprecated: </strong> No
* action.</td></tr>
* <tr><td><code>TrackedObject04</code></td><td>number</td><td>{@link Pose}</td><td><strong>Deprecated: </strong> No
* action.</td></tr>
* <tr><td><code>TrackedObject05</code></td><td>number</td><td>{@link Pose}</td><td><strong>Deprecated: </strong> No
* action.</td></tr>
* <tr><td><code>TrackedObject06</code></td><td>number</td><td>{@link Pose}</td><td><strong>Deprecated: </strong> No
* action.</td></tr>
* <tr><td><code>TrackedObject07</code></td><td>number</td><td>{@link Pose}</td><td><strong>Deprecated: </strong> No
* action.</td></tr>
* <tr><td><code>TrackedObject08</code></td><td>number</td><td>{@link Pose}</td><td><strong>Deprecated: </strong> No
* action.</td></tr>
* <tr><td><code>TrackedObject09</code></td><td>number</td><td>{@link Pose}</td><td><strong>Deprecated: </strong> No
* action.</td></tr>
* <tr><td><code>TrackedObject10</code></td><td>number</td><td>{@link Pose}</td><td><strong>Deprecated: </strong> No
* action.</td></tr>
* <tr><td><code>TrackedObject11</code></td><td>number</td><td>{@link Pose}</td><td><strong>Deprecated: </strong> No
* action.</td></tr>
* <tr><td><code>TrackedObject12</code></td><td>number</td><td>{@link Pose}</td><td><strong>Deprecated: </strong> No
* action.</td></tr>
* <tr><td><code>TrackedObject13</code></td><td>number</td><td>{@link Pose}</td><td><strong>Deprecated: </strong> No
* action.</td></tr>
* <tr><td><code>TrackedObject14</code></td><td>number</td><td>{@link Pose}</td><td><strong>Deprecated: </strong> No
* action.</td></tr>
* <tr><td><code>TrackedObject15</code></td><td>number</td><td>{@link Pose}</td><td><strong>Deprecated: </strong> No
* action.</td></tr>
* </tbody>
* </table>
* @typedef Controller.Actions
*/
// Device functions
Input::NamedVector ActionsDevice::getAvailableInputs() const {
static Input::NamedVector availableInputs {

View file

@ -31,12 +31,67 @@ namespace controller {
class Endpoint;
using EndpointPointer = std::shared_ptr<Endpoint>;
/**jsdoc
* <p>Some controller actions may be associated with one or both hands:</p>
* <table>
* <thead>
* <tr><th>Value</th><th>Description</th></tr>
* </thead>
* <tbody>
* <tr><td><code>0</code></td><td>Left hand.</td></tr>
* <tr><td><code>1</code></td><td>Right hand.</td></tr>
* <tr><td><code>2</code></td><td>Both hands.</td></tr>
* </tbody>
* </table>
* @typedef {number} Controller.Hand
*/
enum Hand {
LEFT = 0,
RIGHT,
BOTH
};
/**jsdoc
* <p>The <code>Controller.Hardware</code> object has properties representing standard and hardware-specific controller and
* computer outputs, plus predefined actions on Interface and the user's avatar. <em>Read-only.</em> The outputs can be mapped
* to actions or functions in a {@link RouteObject} mapping. Additionally, hardware-specific controller outputs can be mapped
* to standard controller outputs.
*
* <p>Controllers typically implement a subset of the {@link Controller.Standard} controls, plus they may implement some extras.
* Some common controllers are included in the table. You can see the outputs provided by these and others by
* viewing their {@link Controller.MappingJSON|MappingJSON} files at
* <a href="https://github.com/highfidelity/hifi/tree/master/interface/resources/controllers">
* https://github.com/highfidelity/hifi/tree/master/interface/resources/controllers</a>.</p>
*
* <table>
* <thead>
* <tr><th>Property</th><th>Type</th><th>Description</th></tr>
* </thead>
* <tbody>
* <tr><td><code>Controller.Hardware.Actions</code></td><td>object</td><td>Synonym for {@link Controller.Actions}.</td></tr>
* <tr><td><code>Controller.Hardware.Application</code></td><td>object</td><td>Interface state outputs. See
* {@link Controller.Hardware-Application}.</td></tr>
* <tr><td><code>Controller.Hardware.Keyboard</code></td><td>object</td><td>Keyboard, mouse, and touch pad outputs. See
* {@link Controller.Hardware-Keyboard}.</td></tr>
* <tr><td><code>Controller.Hardware.OculusTouch</code></td><td>object</td><td>Oculus Rift HMD outputs. See
* {@link Controller.Hardware-OculusTouch}.</td></tr>
* <tr><td><code>Controller.Hardware.Vive</code></td><td>object</td><td>Vive HMD outputs. See
* {@link Controller.Hardware-Vive}.</td></tr>
* </tbody>
* </table>
* @typedef Controller.Hardware
* @example <caption>List all the currently available <code>Controller.Hardware</code> properties.</caption>
* function printProperties(string, item) {
* print(string);
* for (var key in item) {
* if (item.hasOwnProperty(key)) {
* printProperties(string + "." + key, item[key]);
* }
* }
* }
*
* printProperties("Controller.Hardware", Controller.Hardware);
*/
// NOTE: If something inherits from both InputDevice and InputPlugin, InputPlugin must go first.
// e.g. class Example : public InputPlugin, public InputDevice
// instead of class Example : public InputDevice, public InputPlugin

View file

@ -30,6 +30,15 @@ namespace controller {
velocity == right.getVelocity() && angularVelocity == right.getAngularVelocity();
}
/**jsdoc
* The pose of a joint or other item relative to the world or a parent.
* @typedef {object} Pose
* @property {Vec3} translation - Translation.
* @property {Quat} rotation - Rotation.
* @property {Vec3} velocity - Velocity in m/s.
* @property {Vec3} angularVelocity - Angular velocity in rad/s.
* @property {boolean} valid - <code>true</code> if the pose is valid, otherwise <code>false</code>.
*/
QScriptValue Pose::toScriptValue(QScriptEngine* engine, const Pose& pose) {
QScriptValue obj = engine->newObject();
obj.setProperty("translation", vec3toScriptValue(engine, pose.translation));
@ -37,7 +46,6 @@ namespace controller {
obj.setProperty("velocity", vec3toScriptValue(engine, pose.velocity));
obj.setProperty("angularVelocity", vec3toScriptValue(engine, pose.angularVelocity));
obj.setProperty("valid", pose.valid);
return obj;
}

View file

@ -1,6 +1,6 @@
//
// AbstractControllerScriptingInterface.h
// libraries/script-engine/src
// ScriptingInterface.h
// libraries/controllers/src/controllers
//
// Created by Brad Hefta-Gaub on 12/17/13.
// Copyright 2013 High Fidelity, Inc.
@ -61,6 +61,8 @@ namespace controller {
/// handles scripting of input controller commands from JS
class ScriptingInterface : public QObject, public Dependency {
Q_OBJECT
// These properties have JSDoc in ControllerScriptingInterface.h.
Q_PROPERTY(QVariantMap Hardware READ getHardware CONSTANT FINAL)
Q_PROPERTY(QVariantMap Actions READ getActions CONSTANT FINAL)
Q_PROPERTY(QVariantMap Standard READ getStandard CONSTANT FINAL)
@ -69,42 +71,373 @@ namespace controller {
ScriptingInterface();
virtual ~ScriptingInterface() {};
/**jsdoc
* Get a list of all available actions.
* @function Controller.getAllActions
* @returns {Action[]} All available actions.
* @deprecated This function no longer works.
*/
// FIXME: This function causes a JavaScript crash: https://highfidelity.manuscript.com/f/cases/edit/13921
Q_INVOKABLE QVector<Action> getAllActions();
/**jsdoc
* Get a list of all available inputs for a hardware device.
* @function Controller.getAvailableInputs
* @param {number} deviceID - Integer ID of the hardware device.
* @returns {NamedPair[]} All available inputs for the device.
* @deprecated This function no longer works.
*/
// FIXME: This function causes a JavaScript crash: https://highfidelity.manuscript.com/f/cases/edit/13922
Q_INVOKABLE QVector<Input::NamedPair> getAvailableInputs(unsigned int device);
/**jsdoc
* Find the name of a particular controller from its device ID.
* @function Controller.getDeviceName
* @param {number} deviceID - The integer ID of the device.
* @returns {string} The name of the device if found, otherwise <code>"unknown"</code>.
* @example <caption>Get the name of the Oculus Touch controller from its ID.</caption>
* var deviceID = Controller.findDevice("OculusTouch");
* print("Device ID = " + deviceID);
*
* var deviceName = Controller.getDeviceName(deviceID);
* print("Device name = " + deviceName);
*/
Q_INVOKABLE QString getDeviceName(unsigned int device);
/**jsdoc
* Get the current value of an action.
* @function Controller.getActionValue
* @param {number} actionID - The integer ID of the action.
* @returns {number} The current value of the action.
* @example <caption>Periodically report the value of the "TranslateX" action.</caption>
* var actionID = Controller.findAction("TranslateX");
*
* function reportValue() {
* print(Controller.getActionValue(actionID));
* }
* reportTimer = Script.setInterval(reportValue, 1000);
*/
Q_INVOKABLE float getActionValue(int action);
/**jsdoc
* Find the ID of a specific controller from its device name.
* @function Controller.findDevice
* @param {string} deviceName - The name of the device to find.
* @returns {number} The integer ID of the device if available, otherwise <code>65535</code>.
* @example <caption>Get the ID of the Oculus Touch.</caption>
* var deviceID = Controller.findDevice("OculusTouch");
* print("Device ID = " + deviceID);
*/
Q_INVOKABLE int findDevice(QString name);
/**jsdoc
* Get the names of all currently available controller devices plus "Actions", "Application", and "Standard".
* @function Controller.getDeviceNames
* @returns {string[]} An array of device names.
* @example <caption>Get the names of all currently available controller devices.</caption>
* var deviceNames = Controller.getDeviceNames();
* print(JSON.stringify(deviceNames));
* // ["Standard","Keyboard","LeapMotion","OculusTouch","Application","Actions"] or similar.
*/
Q_INVOKABLE QVector<QString> getDeviceNames();
/**jsdoc
* Find the ID of an action from its name.
* @function Controller.findAction
* @param {string} actionName - The name of the action: one of the {@link Controller.Actions} property names.
* @returns {number} The integer ID of the action if found, otherwise <code>4095</code>. Note that this value is not
* the same as the value of the relevant {@link Controller.Actions} property.
* @example <caption>Get the ID of the "TranslateY" action. Compare with the property value.</caption>
* var actionID = Controller.findAction("TranslateY");
* print("Action ID = " + actionID); // 1
* print("Property value = " + Controller.Actions.TranslateY); // 537001728 or similar value.
*/
Q_INVOKABLE int findAction(QString actionName);
/**jsdoc
* Get the names of all actions available as properties of {@link Controller.Actions}.
* @function Controller.getActionNames
* @returns {string[]} An array of action names.
* @example <caption>Get the names of all actions.</caption>
* var actionNames = Controller.getActionNames();
* print("Action names: " + JSON.stringify(actionNames));
* // ["TranslateX","TranslateY","TranslateZ","Roll", ...
*/
Q_INVOKABLE QVector<QString> getActionNames() const;
/**jsdoc
* Get the value of a controller button or axis output. Note: Also gets the value of a controller axis output.
* @function Controller.getValue
* @param {number} source - The {@link Controller.Standard} or {@link Controller.Hardware} item.
* @returns {number} The current value of the controller item output if <code>source</code> is valid, otherwise
* <code>0</code>.
* @example <caption>Report the Standard and Vive right trigger values.</caption>
* var triggerValue = Controller.getValue(Controller.Standard.RT);
* print("Trigger value: " + triggerValue);
*
* if (Controller.Hardware.Vive) {
* triggerValue = Controller.getValue(Controller.Hardware.Vive.RT);
* print("Vive trigger value: " + triggerValue);
* } else {
* print("No Vive present");
* }
*/
Q_INVOKABLE float getValue(const int& source) const;
Q_INVOKABLE float getButtonValue(StandardButtonChannel source, uint16_t device = 0) const;
Q_INVOKABLE float getAxisValue(StandardAxisChannel source, uint16_t device = 0) const;
/**jsdoc
* Get the value of a controller axis output. Note: Also gets the value of a controller button output.
* @function Controller.getAxisValue
* @param {number} source - The {@link Controller.Standard} or {@link Controller.Hardware} item.
* @returns {number} The current value of the controller item output if <code>source</code> is valid, otherwise
* <code>0</code>.
*/
// TODO: getAxisValue() should use const int& parameter? Or others shouldn't?
Q_INVOKABLE float getAxisValue(int source) const;
/**jsdoc
* Get the value of a controller pose output.
* @function Controller.getPoseValue
* @param {number} source - The {@link Controller.Standard} or {@link Controller.Hardware} pose output.
* @returns {Pose} The current value of the controller pose output if <code>source</code> is a pose output, otherwise
* an invalid pose with <code>Pose.valid == false</code>.
* @exammple <caption>Report the right hand's pose.</caption>
* var pose = Controller.getPoseValue(Controller.Standard.RightHand);
* print("Pose: " + JSON.stringify(pose));
*/
Q_INVOKABLE Pose getPoseValue(const int& source) const;
/**jsdoc
* Get the value of a button on a particular device.
* @function Controller.getButtonValue
* @param {StandardButtonChannel} source - The button to get the value of.
* @param {number} [device=0] - The ID of the hardware device to get the value from. The default value of
* <code>0</code> corresponds to <code>Standard</code>.
* @returns {number} The current value of the button if the parameters are valid, otherwise <code>0</code>.
* @deprecated This function no longer works.
*/
// FIXME: This function causes a JavaScript crash: https://highfidelity.manuscript.com/f/cases/edit/14139
Q_INVOKABLE float getButtonValue(StandardButtonChannel source, uint16_t device = 0) const;
/**jsdoc
* Get the value of an axis control on a particular device.
* @function Controller.getAxisValue
* @variation 0
* @param {StandardAxisChannel} source - The axis to get the value of.
* @param {number} [device=0] - The ID of the hardware device to get the value from. The default value of
* <code>0</code> corresponds to <code>Standard</code>.
* @returns {number} The current value of the axis if the parameters are valid, otherwise <code>0</code>.
* @deprecated This function no longer works.
*/
Q_INVOKABLE float getAxisValue(StandardAxisChannel source, uint16_t device = 0) const;
/**jsdoc
* Get the value of an pose control on a particular device.
* @function Controller.getPoseValue
* @variation 0
* @param {StandardPoseChannel} source - The pose to get the value of.
* @param {number} [device=0] - The ID of the hardware device to get the value from. The default value of
* <code>0</code> corresponds to <code>Standard</code>.
* @returns {Pose} The current value of the controller pose output if the parameters are valid, otherwise an invalid
* pose with <code>Pose.valid == false</code>.
* @deprecated This function no longer works.
*/
Q_INVOKABLE Pose getPoseValue(StandardPoseChannel source, uint16_t device = 0) const;
/**jsdoc
* Triggers a haptic pulse on connected and enabled devices that have the capability.
* @function Controller.triggerHapticPulse
* @param {number} strength - The strength of the haptic pulse, <code>0.0</code> &ndash; <code>1.0</code>.
* @param {number} duration - The duration of the haptic pulse, in milliseconds.
* @param {Controller.Hand} hand=2 - The hand or hands to trigger the haptic pulse on.
* @example <caption>Trigger a haptic pulse on the right hand.</caption>
* var HAPTIC_STRENGTH = 0.5;
* var HAPTIC_DURATION = 10;
* var RIGHT_HAND = 1;
* Controller.triggerHapticPulse(HAPTIC_STRENGTH, HAPTIC_DURATION, RIGHT_HAND);
*/
Q_INVOKABLE bool triggerHapticPulse(float strength, float duration, controller::Hand hand = BOTH) const;
Q_INVOKABLE bool triggerShortHapticPulse(float strength, controller::Hand hand = BOTH) const;
Q_INVOKABLE bool triggerHapticPulseOnDevice(unsigned int device, float strength, float duration, controller::Hand hand = BOTH) const;
Q_INVOKABLE bool triggerShortHapticPulseOnDevice(unsigned int device, float strength, controller::Hand hand = BOTH) const;
/**jsdoc
* Triggers a 250ms haptic pulse on connected and enabled devices that have the capability.
* @function Controller.triggerShortHapticPulse
* @param {number} strength - The strength of the haptic pulse, <code>0.0</code> &ndash; <code>1.0</code>.
* @param {Controller.Hand} hand=2 - The hand or hands to trigger the haptic pulse on.
*/
Q_INVOKABLE bool triggerShortHapticPulse(float strength, controller::Hand hand = BOTH) const;
/**jsdoc
* Triggers a haptic pulse on a particular device if connected and enabled and it has the capability.
* @function Controller.triggerHapticPulseOnDevice
* @param {number} deviceID - The ID of the device to trigger the haptic pulse on.
* @param {number} strength - The strength of the haptic pulse, <code>0.0</code> &ndash; <code>1.0</code>.
* @param {number} duration - The duration of the haptic pulse, in milliseconds.
* @param {Controller.Hand} hand=2 - The hand or hands to trigger the haptic pulse on.
* @example <caption>Trigger a haptic pulse on an Oculus Touch controller.</caption>
* var HAPTIC_STRENGTH = 0.5;
* var deviceID = Controller.findDevice("OculusTouch");
* var HAPTIC_DURATION = 10;
* var RIGHT_HAND = 1;
* Controller.triggerHapticPulseOnDevice(deviceID, HAPTIC_STRENGTH, HAPTIC_DURATION, RIGHT_HAND);
*/
Q_INVOKABLE bool triggerHapticPulseOnDevice(unsigned int device, float strength, float duration,
controller::Hand hand = BOTH) const;
/**jsdoc
* Triggers a 250ms haptic pulse on a particular device if connected and enabled and it has the capability.
* @function Controller.triggerShortHapticPulseOnDevice
* @param {number} deviceID - The ID of the device to trigger the haptic pulse on.
* @param {number} strength - The strength of the haptic pulse, <code>0.0</code> &ndash; <code>1.0</code>.
* @param {Controller.Hand} hand=2 - The hand or hands to trigger the haptic pulse on.
*/
Q_INVOKABLE bool triggerShortHapticPulseOnDevice(unsigned int device, float strength, controller::Hand hand = BOTH)
const;
/**jsdoc
* Create a new controller mapping. Routes can then be added to the mapping using {@link MappingObject} methods and
* routed to <code>Standard</code> controls, <code>Actions</code>, or script functions using {@link RouteObject}
* methods. The mapping can then be enabled using {@link Controller.enableMapping|enableMapping} for it to take effect.
* @function Controller.newMapping
* @param {string} mappingName=Uuid.generate() - A unique name for the mapping. If not specified a new UUID generated
* by {@link Uuid.generate} is used.
* @returns {MappingObject} A controller mapping object.
* @example <caption>Create a simple mapping that makes the right trigger move your avatar up.</caption>
* var MAPPING_NAME = "com.highfidelity.controllers.example.newMapping";
* var mapping = Controller.newMapping(MAPPING_NAME);
*
* mapping.from(Controller.Standard.RT).to(Controller.Actions.TranslateY);
* Controller.enableMapping(MAPPING_NAME);
*
* Script.scriptEnding.connect(function () {
* Controller.disableMapping(MAPPING_NAME);
* });
*/
Q_INVOKABLE QObject* newMapping(const QString& mappingName = QUuid::createUuid().toString());
/**jsdoc
* Enable or disable a controller mapping. When enabled, the routes in the mapping have effect.
* @function Controller.enableMapping
* @param {string} mappingName - The name of the mapping.
* @param {boolean} enable=true - If <code>true</code> then the mapping is enabled, otherwise it is disabled.
*/
Q_INVOKABLE void enableMapping(const QString& mappingName, bool enable = true);
/**jsdoc
* Disable a controller mapping. When disabled, the routes in the mapping have no effect.
* @function Controller.disableMapping
* @param {string} mappingName - The name of the mapping.
*/
Q_INVOKABLE void disableMapping(const QString& mappingName) { enableMapping(mappingName, false); }
/**jsdoc
* Create a new controller mapping from a {@link Controller.MappingJSON|MappingJSON} string. Use
* {@link Controller.enableMapping|enableMapping} to enable the mapping for it to take effect.
* @function Controller.parseMapping
* @param {string} jsonString - A JSON string of the {@link Controller.MappingJSON|MappingJSON}.
* @returns {MappingObject} A controller mapping object.
* @example <caption>Create a simple mapping that makes the right trigger move your avatar up.</caption>
* var mappingJSON = {
* "name": "com.highfidelity.controllers.example.jsonMapping",
* "channels": [
* { "from": "Standard.RT", "to": "Actions.TranslateY" }
* ]
* };
*
* var mapping = Controller.parseMapping(JSON.stringify(mappingJSON));
* mapping.enable();
*
* Script.scriptEnding.connect(function () {
* mapping.disable();
* });
*/
Q_INVOKABLE QObject* parseMapping(const QString& json);
/**jsdoc
* Create a new controller mapping from a {@link Controller.MappingJSON|MappingJSON} JSON file at a URL. Use
* {@link Controller.enableMapping|enableMapping} to enable the mapping for it to take effect.
* @function Controller.loadMapping
* @param {string} jsonURL - The URL the {@link Controller.MappingJSON|MappingJSON} JSON file.
* @returns {MappingObject} A controller mapping object.
* @todo <em>Implement this function. It currently does not load the mapping from the file; it just returns
* <code>null</code>.</em>
*/
Q_INVOKABLE QObject* loadMapping(const QString& jsonUrl);
/**jsdoc
* Get the {@link Controller.Hardware} property tree. Calling this function is the same as using the {@link Controller}
* property, <code>Controller.Hardware</code>.
* @function Controller.getHardware
* @returns {Controller.Hardware} The {@link Controller.Hardware} property tree.
*/
Q_INVOKABLE const QVariantMap getHardware() { return _hardware; }
Q_INVOKABLE const QVariantMap getActions() { return _actions; }
/**jsdoc
* Get the {@link Controller.Actions} property tree. Calling this function is the same as using the {@link Controller}
* property, <code>Controller.Actions</code>.
* @function Controller.getActions
* @returns {Controller.Actions} The {@link Controller.Actions} property tree.
*/
Q_INVOKABLE const QVariantMap getActions() { return _actions; } //undefined
/**jsdoc
* Get the {@link Controller.Standard} property tree. Calling this function is the same as using the {@link Controller}
* property, <code>Controller.Standard</code>.
* @function Controller.getStandard
* @returns {Controller.Standard} The {@link Controller.Standard} property tree.
*/
Q_INVOKABLE const QVariantMap getStandard() { return _standard; }
/**jsdoc
* Start making a recording of currently active controllers.
* @function Controller.startInputRecording
*/
Q_INVOKABLE void startInputRecording();
/**jsdoc
* Stop making a recording started by {@link Controller.startInputRecording|startInputRecording}.
* @function Controller.stopInputRecording
*/
Q_INVOKABLE void stopInputRecording();
/**jsdoc
* Play back the current recording from the beginning. The current recording may have been recorded by
* {@link Controller.startInputRecording|startInputRecording} and
* {@link Controller.stopInputRecording|stopInputRecording}, or loaded by
* {@link Controller.loadInputRecording|loadInputRecording}.
* @function Controller.startInputPlayback
*/
Q_INVOKABLE void startInputPlayback();
/**jsdoc
* Stop play back of a recording started by {@link Controller.startInputPlayback|startInputPlayback}.
* @function Controller.stopInputPlayback
*/
Q_INVOKABLE void stopInputPlayback();
/**jsdoc
* Save the current recording to a file. The current recording may have been recorded by
* {@link Controller.startInputRecording|startInputRecording} and
* {@link Controller.stopInputRecording|stopInputRecording}, or loaded by
* {@link Controller.loadInputRecording|loadInputRecording}. It is saved in the directory returned by
* {@link Controller.getInputRecorderSaveDirectory|getInputRecorderSaveDirectory}.
* @function Controller.saveInputRecording
*/
Q_INVOKABLE void saveInputRecording();
/**jsdoc
* Load an input recording, ready for play back.
* @function Controller.loadInputRecording
* @parameter {string} file - The path to the recording file.
*/
Q_INVOKABLE void loadInputRecording(const QString& file);
/**jsdoc
* Get the directory in which input recordings are saved.
* @function Controller.getInputRecorderSaveDirectory
* @returns {string} The directory in which input recordings are saved.
*/
Q_INVOKABLE QString getInputRecorderSaveDirectory();
bool isMouseCaptured() const { return _mouseCaptured; }
@ -114,21 +447,156 @@ namespace controller {
public slots:
/**jsdoc
* Disable processing of mouse "move", "press", "double-press", and "release" events into
* {@link Controller.Hardware|Controller.Hardware.Keyboard} outputs.
* @function Controller.captureMouseEvents
* @example <caption>Disable Controller.Hardware.Keyboard mouse events for a short period.</caption>
* var MAPPING_NAME = "com.highfidelity.controllers.example.newMapping";
* var mapping = Controller.newMapping(MAPPING_NAME);
* mapping.from(Controller.Hardware.Keyboard.MouseX).to(function (x) {
* print("Mouse x = " + x);
* });
* mapping.from(Controller.Hardware.Keyboard.MouseY).to(function (y) {
* print("Mouse y = " + y);
* });
* Controller.enableMapping(MAPPING_NAME);
* Script.scriptEnding.connect(function () {
* Controller.disableMapping(MAPPING_NAME);
* });
*
* Script.setTimeout(function () {
* Controller.captureMouseEvents();
* }, 5000);
*
* Script.setTimeout(function () {
* Controller.releaseMouseEvents();
* }, 10000);
*/
virtual void captureMouseEvents() { _mouseCaptured = true; }
/**jsdoc
* Enable processing of mouse "move", "press", "double-press", and "release" events into
* {@link Controller.Hardware-Keyboard|Controller.Hardware.Keyboard} outputs that was disabled using
* {@link Controller.captureMouseEvents|captureMouseEvents}.
* @function Controller.releaseMouseEvents
*/
virtual void releaseMouseEvents() { _mouseCaptured = false; }
/**jsdoc
* Disable processing of touch "begin", "update", and "end" events into
* {@link Controller.Hardware|Controller.Hardware.Keyboard},
* {@link Controller.Hardware|Controller.Hardware.Touchscreen}, and
* {@link Controller.Hardware|Controller.Hardware.TouchscreenVirtualPad} outputs.
* @function Controller.captureTouchEvents
*/
virtual void captureTouchEvents() { _touchCaptured = true; }
/**jsdoc
* Enable processing of touch "begin", "update", and "end" events into
* {@link Controller.Hardware|Controller.Hardware.Keyboard},
* {@link Controller.Hardware|Controller.Hardware.Touchscreen}, and
* {@link Controller.Hardware|Controller.Hardware.TouchscreenVirtualPad} outputs that was disabled using
* {@link Controller.captureTouchEvents|captureTouchEvents}.
* @function Controller.releaseTouchEvents
*/
virtual void releaseTouchEvents() { _touchCaptured = false; }
/**jsdoc
* Disable processing of mouse wheel rotation events into {@link Controller.Hardware|Controller.Hardware.Keyboard}
* outputs.
* @function Controller.captureWheelEvents
*/
virtual void captureWheelEvents() { _wheelCaptured = true; }
/**jsdoc
* Enable processing of mouse wheel rotation events into {@link Controller.Hardware|Controller.Hardware.Keyboard}
* outputs that was disabled using {@link Controller.captureWheelEvents|captureWheelEvents}.
* @function Controller.releaseWheelEvents
*/
virtual void releaseWheelEvents() { _wheelCaptured = false; }
/**jsdoc
* Disable translating and rotating the user's avatar in response to keyboard and controller controls.
* @function Controller.captureActionEvents
* @example <caption>Disable avatar translation and rotation for a short period.</caption>
* Script.setTimeout(function () {
* Controller.captureActionEvents();
* }, 5000);
*
* Script.setTimeout(function () {
* Controller.releaseActionEvents();
* }, 10000);
*/
virtual void captureActionEvents() { _actionsCaptured = true; }
/**jsdoc
* Enable translating and rotating the user's avatar in response to keyboard and controller controls that was disabled
* using {@link Controller.captureActionEvents|captureActionEvents}.
* @function Controller.releaseActionEvents
*/
virtual void releaseActionEvents() { _actionsCaptured = false; }
signals:
/**jsdoc
* Triggered when an action occurs.
* @function Controller.actionEvent
* @param {number} actionID - The ID of the action, per {@link Controller.findAction|findAction}.
* @param {number} value - The value associated with the action.
* @returns {Signal}
* @example <caption>Report action events as they occur.</caption>
* var actionNamesForID = {};
* var actionNames = Controller.getActionNames();
* for (var i = 0, length = actionNames.length; i < length; i++) {
* actionNamesForID[Controller.findAction(actionNames[i])] = actionNames[i];
* }
*
* function onActionEvent(action, value) {
* print("onActionEvent() : " + action + " ( " + actionNamesForID[action] + " ) ; " + value);
* }
*
* Controller.actionEvent.connect(onActionEvent);
*
* Script.scriptEnding.connect(function () {
* Controller.actionEvent.disconnect(onActionEvent);
* });
*/
void actionEvent(int action, float state);
/**jsdoc
* Triggered when there is a new controller input event.
* @function Controller.inputEvent
* @param {number} action - The input action, per {@link Controller.Standard}.
* @param {number} value - The value associated with the input action.
* @returns {Signal}
* @example <caption>Report input events as they occur.</caption>
* var inputNamesForID = {};
* for (var property in Controller.Standard) {
* inputNamesForID[Controller.Standard[property]] = "Controller.Standard." + property;
* }
*
* function onInputEvent(input, value) {
* print("onInputEvent() : " + input + " ( " + inputNamesForID[input] + " ) ; " + value);
* }
*
* Controller.inputEvent.connect(onInputEvent);
*
* Script.scriptEnding.connect(function () {
* Controller.inputEvent.disconnect(onInputEvent);
* });
*/
void inputEvent(int action, float state);
/**jsdoc
* Triggered when a device is registered or unregistered by a plugin. Not all plugins generate
* <code>hardwareChanged</code> events: for example connecting or disconnecting a mouse will not generate an event but
* connecting or disconnecting an Xbox controller will.
* @function Controller.hardwareChanged
* @returns {Signal}
*/
void hardwareChanged();
private:
@ -145,8 +613,6 @@ namespace controller {
std::atomic<bool> _actionsCaptured { false };
};
}
#endif // hifi_AbstractControllerScriptingInterface_h

View file

@ -27,6 +27,212 @@ void StandardController::focusOutEvent() {
_buttonPressedMap.clear();
};
/**jsdoc
* <p>The <code>Controller.Standard</code> object has properties representing standard controller outputs. Those for physical
* controllers are based on the XBox controller, with aliases for PlayStation. The property values are integer IDs, uniquely
* identifying each output. <em>Read-only.</em> These can be can be mapped to actions or functions in a {@link RouteObject}
* mapping.</p>
*
* <p>The data value provided by each control is either a number or a {@link Pose}. Numbers are typically normalized to
* <code>0.0</code> or <code>1.0</code> for button states, the range <code>0.0 &ndash; 1.0</code> for unidirectional scales,
* and the range <code>-1.0 &ndash; 1.0</code> for bidirectional scales.</p>
*
* <p>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>.</p>
*
* <table>
* <thead>
* <tr><th>Property</th><th>Type</th><th>Data</th><th>Description</th></tr>
* </thead>
* <tbody>
*
* <tr><td colspan="4"><strong>Buttons</strong></td></tr>
* <tr><td><code>A</code></td><td>number</td><td>number</td><td>"A" button pressed.</td></tr>
* <tr><td><code>B</code></td><td>number</td><td>number</td><td>"B" button pressed.</td></tr>
* <tr><td><code>X</code></td><td>number</td><td>number</td><td>"X" button pressed.</td></tr>
* <tr><td><code>Y</code></td><td>number</td><td>number</td><td>"Y" button pressed.</td></tr>
* <tr><td><code>DL</code></td><td>number</td><td>number</td><td>D-pad left pressed.</td></tr>
* <tr><td><code>DR</code></td><td>number</td><td>number</td><td>D-pad right pressed.</td></tr>
* <tr><td><code>DU</code></td><td>number</td><td>number</td><td>D-pad up pressed.</td></tr>
* <tr><td><code>DD</code></td><td>number</td><td>number</td><td>D-pad down pressed.</td></tr>
* <tr><td><code>Start</code></td><td>number</td><td>number</td><td>"Start" center button pressed.</td></tr>
* <tr><td><code>Back</code></td><td>number</td><td>number</td><td>"Back" center button pressed.</td></tr>
* <tr><td><code>LB</code></td><td>number</td><td>number</td><td>Left bumper button pressed.</td></tr>
* <tr><td><code>RB</code></td><td>number</td><td>number</td><td>Right bumper button pressed.</td></tr>
*
* <tr><td colspan="4"><strong>Sticks</strong></td></tr>
* <tr><td><code>LX</code></td><td>number</td><td>number</td><td>Left stick x-axis scale.</td></tr>
* <tr><td><code>LY</code></td><td>number</td><td>number</td><td>left stick y-axis scale.</td></tr>
* <tr><td><code>RX</code></td><td>number</td><td>number</td><td>Right stick x-axis scale.</td></tr>
* <tr><td><code>RY</code></td><td>number</td><td>number</td><td>Right stick y-axis scale.</td></tr>
* <tr><td><code>LS</code></td><td>number</td><td>number</td><td>Left stick button pressed.</td></tr>
* <tr><td><code>RS</code></td><td>number</td><td>number</td><td>Right stick button pressed.</td></tr>
* <tr><td><code>LSTouch</code></td><td>number</td><td>number</td><td>Left stick is touched.</td></tr>
* <tr><td><code>RSTouch</code></td><td>number</td><td>number</td><td>Right stick is touched.</td></tr>
*
* <tr><td colspan="4"><strong>Triggers</strong></td></tr>
* <tr><td><code>LT</code></td><td>number</td><td>number</td><td>Left trigger scale.</td></tr>
* <tr><td><code>RT</code></td><td>number</td><td>number</td><td>Right trigger scale.</td></tr>
* <tr><td><code>LTClick</code></td><td>number</td><td>number</td><td>Left trigger click.</td></tr>
* <tr><td><code>RTClick</code></td><td>number</td><td>number</td><td>Right trigger click.</td></tr>
* <tr><td><code>LeftGrip</code></td><td>number</td><td>number</td><td>Left grip scale.</td></tr>
* <tr><td><code>RightGrip</code></td><td>number</td><td>number</td><td>Right grip scale.</td></tr>
* <tr><td><code>LeftGripTouch</code></td><td>number</td><td>number</td><td>Left grip is touched.</td></tr>
* <tr><td><code>RightGripTouch</code></td><td>number</td><td>number</td><td>Right grip is touched.</td></tr>
*
* <tr><td colspan="4"><strong>Aliases, PlayStation Style Names</strong></td></tr>
* <tr><td><code>Cross</code></td><td>number</td><td>number</td><td>Alias for <code>A</code>.</td></tr>
* <tr><td><code>Circle</code></td><td>number</td><td>number</td><td>Alias for <code>B</code>.</td></tr>
* <tr><td><code>Square</code></td><td>number</td><td>number</td><td>Alias for <code>X</code>.</td></tr>
* <tr><td><code>Triangle</code></td><td>number</td><td>number</td><td>Alias for <code>Y</code>.</td></tr>
* <tr><td><code>Left</code></td><td>number</td><td>number</td><td>Alias for <code>DL</code>.</td></tr>
* <tr><td><code>Right</code></td><td>number</td><td>number</td><td>Alias for <code>DR</code>.</td></tr>
* <tr><td><code>Up</code></td><td>number</td><td>number</td><td>Alias for <code>DU</code>.</td></tr>
* <tr><td><code>Down</code></td><td>number</td><td>number</td><td>Alias for <code>DD</code>.</td></tr>
* <tr><td><code>Select</code></td><td>number</td><td>number</td><td>Alias for <code>Back</code>.</td></tr>
* <tr><td><code>L1</code></td><td>number</td><td>number</td><td>Alias for <code>LB</code>.</td></tr>
* <tr><td><code>R1</code></td><td>number</td><td>number</td><td>Alias for <code>RB</code>.</td></tr>
* <tr><td><code>L3</code></td><td>number</td><td>number</td><td>Alias for <code>LS</code>.</td></tr>
* <tr><td><code>R3</code></td><td>number</td><td>number</td><td>Alias for <code>RS</code>.</td></tr>
* <tr><td><code>L2</code></td><td>number</td><td>number</td><td>Alias for <code>LT</code>.</td></tr>
* <tr><td><code>R2</code></td><td>number</td><td>number</td><td>Alias for <code>RT</code>.</td></tr>
*
* <tr><td colspan="4"><strong>Finger Abstractions</strong></td></tr>
* <tr><td><code>LeftPrimaryThumb</code></td><td>number</td><td>number</td><td>Left primary thumb button pressed.</td></tr>
* <tr><td><code>LeftSecondaryThumb</code></td><td>number</td><td>number</td><td>Left secondary thumb button pressed.
* </td></tr>
* <tr><td><code>RightPrimaryThumb</code></td><td>number</td><td>number</td><td>Right primary thumb button pressed.
* </td></tr>
* <tr><td><code>RightSecondaryThumb</code></td><td>number</td><td>number</td><td>Right secondary thumb button pressed.
* </td></tr>
* <tr><td><code>LeftPrimaryThumbTouch</code></td><td>number</td><td>number</td><td>Left thumb touching primary thumb
* button.</td></tr>
* <tr><td><code>LeftSecondaryThumbTouch</code></td><td>number</td><td>number</td><td>Left thumb touching secondary thumb
* button.</td></tr>
* <tr><td><code>LeftThumbUp</code></td><td>number</td><td>number</td><td>Left thumb not touching primary or secondary
* thumb buttons.</td></tr>
* <tr><td><code>RightPrimaryThumbTouch</code></td><td>number</td><td>number</td><td>Right thumb touching primary thumb
* button.</td></tr>
* <tr><td><code>RightSecondaryThumbTouch</code></td><td>number</td><td>number</td><td>Right thumb touching secondary thumb
* button.</td></tr>
* <tr><td><code>RightThumbUp</code></td><td>number</td><td>number</td><td>Right thumb not touching primary or secondary
* thumb buttons.</td></tr>
* <tr><td><code>LeftPrimaryIndex</code></td><td>number</td><td>number</td><td>Left primary index control pressed.
* <strong>To Do:</strong> <em>Implement this for current controllers.</em></td></tr>
* <tr><td><code>LeftSecondaryIndex</code></td><td>number</td><td>number</td><td>Left secondary index control pressed.
* </td></tr>
* <tr><td><code>RightPrimaryIndex</code></td><td>number</td><td>number</td><td>Right primary index control pressed.
* <strong>To Do:</strong> <em>Implement this for current controllers.</em></td></tr>
* <tr><td><code>RightSecondaryIndex</code></td><td>number</td><td>number</td><td>Right secondary index control pressed.
* </td></tr>
* <tr><td><code>LeftPrimaryIndexTouch</code></td><td>number</td><td>number</td><td>Left index finger is touching primary
* index finger control.</td></tr>
* <tr><td><code>LeftSecondaryIndexTouch</code></td><td>number</td><td>number</td><td>Left index finger is touching
* secondary index finger control.</td></tr>
* <tr><td><code>LeftIndexPoint</code></td><td>number</td><td>number</td><td>Left index finger is pointing, not touching
* primary or secondary index finger controls.</td></tr>
* <tr><td><code>RightPrimaryIndexTouch</code></td><td>number</td><td>number</td><td>Right index finger is touching primary
* index finger control.</td></tr>
* <tr><td><code>RightSecondaryIndexTouch</code></td><td>number</td><td>number</td><td>Right index finger is touching
* secondary index finger control.</td></tr>
* <tr><td><code>RightIndexPoint</code></td><td>number</td><td>number</td><td>Right index finger is pointing, not touching
* primary or secondary index finger controls.</td></tr>
*
* <tr><td colspan="4"><strong>Avatar Skeleton</strong></td></tr>
* <tr><td><code>Hips</code></td><td>number</td><td>{@link Pose}</td><td>Hips pose.</td></tr>
* <tr><td><code>Spine2</code></td><td>number</td><td>{@link Pose}</td><td>Spine2 pose.</td></tr>
* <tr><td><code>Head</code></td><td>number</td><td>{@link Pose}</td><td>Head pose.</td></tr>
* <tr><td><code>LeftArm</code></td><td>number</td><td>{@link Pose}</td><td>Left arm pose.</td></tr>
* <tr><td><code>RightArm</code></td><td>number</td><td>{@link Pose}</td><td>Right arm pose</td></tr>
* <tr><td><code>LeftHand</code></td><td>number</td><td>{@link Pose}</td><td>Left hand pose.</td></tr>
* <tr><td><code>LeftHandThumb1</code></td><td>number</td><td>{@link Pose}</td><td>Left thumb 1 finger joint pose.</td></tr>
* <tr><td><code>LeftHandThumb2</code></td><td>number</td><td>{@link Pose}</td><td>Left thumb 2 finger joint pose.</td></tr>
* <tr><td><code>LeftHandThumb3</code></td><td>number</td><td>{@link Pose}</td><td>Left thumb 3 finger joint pose.</td></tr>
* <tr><td><code>LeftHandThumb4</code></td><td>number</td><td>{@link Pose}</td><td>Left thumb 4 finger joint pose.</td></tr>
* <tr><td><code>LeftHandIndex1</code></td><td>number</td><td>{@link Pose}</td><td>Left index 1 finger joint pose.</td></tr>
* <tr><td><code>LeftHandIndex2</code></td><td>number</td><td>{@link Pose}</td><td>Left index 2 finger joint pose.</td></tr>
* <tr><td><code>LeftHandIndex3</code></td><td>number</td><td>{@link Pose}</td><td>Left index 3 finger joint pose.</td></tr>
* <tr><td><code>LeftHandIndex4</code></td><td>number</td><td>{@link Pose}</td><td>Left index 4 finger joint pose.</td></tr>
* <tr><td><code>LeftHandMiddle1</code></td><td>number</td><td>{@link Pose}</td><td>Left middle 1 finger joint pose.
* </td></tr>
* <tr><td><code>LeftHandMiddle2</code></td><td>number</td><td>{@link Pose}</td><td>Left middle 2 finger joint pose.
* </td></tr>
* <tr><td><code>LeftHandMiddle3</code></td><td>number</td><td>{@link Pose}</td><td>Left middle 3 finger joint pose.
* </td></tr>
* <tr><td><code>LeftHandMiddle4</code></td><td>number</td><td>{@link Pose}</td><td>Left middle 4 finger joint pose.
* </td></tr>
* <tr><td><code>LeftHandRing1</code></td><td>number</td><td>{@link Pose}</td><td>Left ring 1 finger joint pose.</td></tr>
* <tr><td><code>LeftHandRing2</code></td><td>number</td><td>{@link Pose}</td><td>Left ring 2 finger joint pose.</td></tr>
* <tr><td><code>LeftHandRing3</code></td><td>number</td><td>{@link Pose}</td><td>Left ring 3 finger joint pose.</td></tr>
* <tr><td><code>LeftHandRing4</code></td><td>number</td><td>{@link Pose}</td><td>Left ring 4 finger joint pose.</td></tr>
* <tr><td><code>LeftHandPinky1</code></td><td>number</td><td>{@link Pose}</td><td>Left pinky 1 finger joint pose.</td></tr>
* <tr><td><code>LeftHandPinky2</code></td><td>number</td><td>{@link Pose}</td><td>Left pinky 2 finger joint pose.</td></tr>
* <tr><td><code>LeftHandPinky3</code></td><td>number</td><td>{@link Pose}</td><td>Left pinky 3 finger joint pose.</td></tr>
* <tr><td><code>LeftHandPinky4</code></td><td>number</td><td>{@link Pose}</td><td>Left pinky 4 finger joint pose.</td></tr>
* <tr><td><code>RightHand</code></td><td>number</td><td>{@link Pose}</td><td>Right hand pose.</td></tr>
* <tr><td><code>RightHandThumb1</code></td><td>number</td><td>{@link Pose}</td><td>Right thumb 1 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandThumb2</code></td><td>number</td><td>{@link Pose}</td><td>Right thumb 2 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandThumb3</code></td><td>number</td><td>{@link Pose}</td><td>Right thumb 3 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandThumb4</code></td><td>number</td><td>{@link Pose}</td><td>Right thumb 4 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandIndex1</code></td><td>number</td><td>{@link Pose}</td><td>Right index 1 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandIndex2</code></td><td>number</td><td>{@link Pose}</td><td>Right index 2 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandIndex3</code></td><td>number</td><td>{@link Pose}</td><td>Right index 3 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandIndex4</code></td><td>number</td><td>{@link Pose}</td><td>Right index 4 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandMiddle1</code></td><td>number</td><td>{@link Pose}</td><td>Right middle 1 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandMiddle2</code></td><td>number</td><td>{@link Pose}</td><td>Right middle 2 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandMiddle3</code></td><td>number</td><td>{@link Pose}</td><td>Right middle 3 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandMiddle4</code></td><td>number</td><td>{@link Pose}</td><td>Right middle 4 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandRing1</code></td><td>number</td><td>{@link Pose}</td><td>Right ring 1 finger joint pose.</td></tr>
* <tr><td><code>RightHandRing2</code></td><td>number</td><td>{@link Pose}</td><td>Right ring 2 finger joint pose.</td></tr>
* <tr><td><code>RightHandRing3</code></td><td>number</td><td>{@link Pose}</td><td>Right ring 3 finger joint pose.</td></tr>
* <tr><td><code>RightHandRing4</code></td><td>number</td><td>{@link Pose}</td><td>Right ring 4 finger joint pose.</td></tr>
* <tr><td><code>RightHandPinky1</code></td><td>number</td><td>{@link Pose}</td><td>Right pinky 1 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandPinky2</code></td><td>number</td><td>{@link Pose}</td><td>Right pinky 2 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandPinky3</code></td><td>number</td><td>{@link Pose}</td><td>Right pinky 3 finger joint pose.
* </td></tr>
* <tr><td><code>RightHandPinky4</code></td><td>number</td><td>{@link Pose}</td><td>Right pinky 4 finger joint pose.
* </td></tr>
* <tr><td><code>LeftFoot</code></td><td>number</td><td>{@link Pose}</td><td>Left foot pose.</td></tr>
* <tr><td><code>RightFoot</code></td><td>number</td><td>{@link Pose}</td><td>Right foot pose.</td></tr>
*
* <tr><td colspan="4"><strong>Trackers</strong></td></tr>
* <tr><td><code>TrackedObject00</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 0 pose.</td></tr>
* <tr><td><code>TrackedObject01</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 1 pose.</td></tr>
* <tr><td><code>TrackedObject02</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 2 pose.</td></tr>
* <tr><td><code>TrackedObject03</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 3 pose.</td></tr>
* <tr><td><code>TrackedObject04</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 4 pose.</td></tr>
* <tr><td><code>TrackedObject05</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 5 pose.</td></tr>
* <tr><td><code>TrackedObject06</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 6 pose.</td></tr>
* <tr><td><code>TrackedObject07</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 7 pose.</td></tr>
* <tr><td><code>TrackedObject08</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 8 pose.</td></tr>
* <tr><td><code>TrackedObject09</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 9 pose.</td></tr>
* <tr><td><code>TrackedObject10</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 10 pose.</td></tr>
* <tr><td><code>TrackedObject11</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 11 pose.</td></tr>
* <tr><td><code>TrackedObject12</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 12 pose.</td></tr>
* <tr><td><code>TrackedObject13</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 13 pose.</td></tr>
* <tr><td><code>TrackedObject14</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 14 pose.</td></tr>
* <tr><td><code>TrackedObject15</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 15 pose.</td></tr>
*
* </tbody>
* </table>
* @typedef Controller.Standard
*/
Input::NamedVector StandardController::getAvailableInputs() const {
static Input::NamedVector availableInputs {
// Buttons

View file

@ -24,6 +24,101 @@ namespace controller {
class ScriptingInterface;
class UserInputMapper;
/**jsdoc
* <p>A {@link Controller} mapping object that can contain a set of routes that map:</p>
* <ul>
* <li>{@link Controller.Standard} outputs to {@link Controller.Actions} actions or script functions.</li>
* <li>{@link Controller.Hardware} outputs to {@link Controller.Standard} outputs, {@link Controller.Actions} actions, or
* script functions.</li>
* </ul>
*
* <p>Create by one of the following methods:</p>
* <ul>
* <li>Use {@link Controller.newMapping} to create the mapping object, add routes using {@link MappingObject#from|from} or
* {@link MappingObject#makeAxis|makeAxis}, and map the routes to actions or functions using {@link RouteObject}
* methods.</li>
* <li>Use {@link Controller.parseMapping} or {@link Controller.loadMapping} to load a {@link Controller.MappingJSON}.</li>
* </ul>
* <p>Enable the mapping using {@link MappingObject#enable|enable} or {@link Controller.enableMapping} for it to take effect.
*
* <p>Mappings and their routes are applied according to the following rules:</p>
* <ul>
* <li>One read per output: after a controller output has been read, it can't be read again. Exception: You can use
* {@link RouteObject#peek} to read a value without marking that output as having been read.</li>
* <li>Existing mapping routes take precedence over new mapping routes: within a mapping, if a route is added for a control
* output that already has a route the new route is ignored.</li>
* <li>New mappings override previous mappings: each output is processed using the route in the most recently enabled
* mapping that contains that output.</li>
* </p>
*
* @class MappingObject
*/
/**jsdoc
* A {@link MappingObject} can be specified in JSON format. A simple example is provided below. Full examples &mdash; the
* default mappings provided in Interface &mdash; can be found at
* <a href="https://github.com/highfidelity/hifi/tree/master/interface/resources/controllers">
* https://github.com/highfidelity/hifi/tree/master/interface/resources/controllers</a>.
* @typedef {object} Controller.MappingJSON
* @property {string} name - The name of the mapping.
* @property {Controller.MappingJSONRoute[]} channels - An array of routes.
* @example <caption>A simple mapping JSON that makes the right trigger move your avatar up after a dead zone.</caption>
* {
* "name": "com.highfidelity.controllers.example.jsonMapping",
* "channels": [
* {
* "from": "Standard.RT",
* "filters": { "type": "deadZone", "min": 0.05 },
* "to": "Actions.TranslateY"
* }
* ]
* }
*/
/**jsdoc
* A route in a {@link Controller.MappingJSON}.
* @typedef {object} Controller.MappingJSONRoute
* @property {string|Controller.MappingJSONAxis} from - The name of a {@link Controller.Hardware} property name or an axis
* made from them. If a property name, the leading <code>"Controller.Hardware."</code> can be omitted.
* @property {boolean} [peek=false] - If <codd>true</code> then peeking is enabled per {@link RouteObject#peek}.
* @property {boolean} [debug=false] - If <code>true</code> then debug is enabled per {@link RouteObject#debug}.
* @property {string|string[]} [when=[]] - One or more numeric {@link Controller.Hardware} property names which are evaluated
* as booleans and ANDed together. Prepend with a <code>!</code> to use the logical NOT of the property value. The leading
* <code>"Controller.Hardware."</code> can be omitted from the property names.
* @property {Controller.MappingJSONFilter|Controller.MappingJSONFilter[]} [filters=[]] - One or more filters in the route.
* @property {string} to - The name of a {@link Controller.Actions} or {@link Controller.Standard} property. The leading
* <code>"Controller."</code> can be omitted.
*/
/**jsdoc
* An axis pair in a {@link Controller.MappingJSONRoute}.
* @typedef {object} Controller.MappingJSONAxis
* @property {string[][]} makeAxis - A two-member array of single-member arrays of {@link Controller.Hardware} property names.
* The leading <code>"Controller.Hardware."</code> can be omitted from the property names.
* @example <caption>An axis using the keyboard's left and right keys.</caption>
* { "makeAxis" : [
* ["Keyboard.Left"],
* ["Keyboard.Right"]
* ]
* }
*/
/**jsdoc
* A filter in a {@link Controller.MappingJSONRoute}.
* @typedef {object} Controller.MappingJSONFilter
* @property {string} type - The name of the filter, being the name of the one of the {@link RouteObject}'s filter methods.
* @property {string} [?] - If the filter method has a first parameter, the property name is the name of that parameter and the
* property value is the value to use.
* @property {string} [?] - If the filter method has a second parameter, the property name is the name of that parameter and
* the property value is the value to use.
* @example <caption>A hysteresis filter.</caption>
* {
* "type": "hysteresis",
* "min": 0.85,
* "max": 0.9
* }
*/
// TODO migrate functionality to a MappingBuilder class and make the proxy defer to that
// (for easier use in both C++ and JS)
class MappingBuilderProxy : public QObject {
@ -32,13 +127,76 @@ public:
MappingBuilderProxy(UserInputMapper& parent, Mapping::Pointer mapping)
: _parent(parent), _mapping(mapping) { }
/**jsdoc
* Create a new {@link RouteObject} from a controller output, ready to be mapped to a standard control, action, or
* function.<br />
* This is a QML-specific version of {@link MappingObject#from|from}: use this version in QML files.
* @function MappingObject#fromQml
* @param {Controller.Standard|Controller.Hardware|function} source - The controller output or function that is the source
* of the route data. If a function, it must return a number or a {@link Pose} value as the route data.
* @returns {RouteObject} A route ready for mapping to an action or function using {@link RouteObject} methods.
*/
Q_INVOKABLE QObject* fromQml(const QJSValue& source);
/**jsdoc
* Create a new {@link RouteObject} from two numeric {@link Controller.Hardware} outputs, one applied in the negative
* direction and the other in the positive direction, ready to be mapped to a standard control, action, or function.<br />
* This is a QML-specific version of {@link MappingObject#makeAxis|makeAxis}: use this version in QML files.
* @function MappingObject#makeAxisQml
* @param {Controller.Hardware} source1 - The first, negative-direction controller output.
* @param {Controller.Hardware} source2 - The second, positive-direction controller output.
* @returns {RouteObject} A route ready for mapping to an action or function using {@link RouteObject} methods. The data
* value passed to the route is the combined value of <code>source2 - source1</code>.
*/
Q_INVOKABLE QObject* makeAxisQml(const QJSValue& source1, const QJSValue& source2);
/**jsdoc
* Create a new {@link RouteObject} from a controller output, ready to be mapped to a standard control, action, or
* function.
* @function MappingObject#from
* @param {Controller.Standard|Controller.Hardware|function} source - The controller output or function that is the source
* of the route data. If a function, it must return a number or a {@link Pose} value as the route data.
* @returns {RouteObject} A route ready for mapping to an action or function using {@link RouteObject} methods.
*/
Q_INVOKABLE QObject* from(const QScriptValue& source);
/**jsdoc
* Create a new {@link RouteObject} from two numeric {@link Controller.Hardware} outputs, one applied in the negative
* direction and the other in the positive direction, ready to be mapped to a standard control, action, or function.
* @function MappingObject#makeAxis
* @param {Controller.Hardware} source1 - The first, negative-direction controller output.
* @param {Controller.Hardware} source2 - The second, positive-direction controller output.
* @returns {RouteObject} A route ready for mapping to an action or function using {@link RouteObject} methods. The data
* value passed to the route is the combined value of <code>source2 - source1</code>.
* @example <caption>Make the Oculus Touch triggers move your avatar up and down.</caption>
* var MAPPING_NAME = "com.highfidelity.controllers.example.newMapping";
* var mapping = Controller.newMapping(MAPPING_NAME);
* mapping
* .makeAxis(Controller.Hardware.OculusTouch.LT, Controller.Hardware.OculusTouch.RT)
* .to(Controller.Actions.Up);
* Controller.enableMapping(MAPPING_NAME);
*
* Script.scriptEnding.connect(function () {
* Controller.disableMapping(MAPPING_NAME);
* });
*/
Q_INVOKABLE QObject* makeAxis(const QScriptValue& source1, const QScriptValue& source2);
/**jsdoc
* Enable or disable the mapping. When enabled, the routes in the mapping take effect.<br />
* Synonymous with {@link Controller.enableMapping}.
* @function MappingObject#enable
* @param {boolean} enable=true - If <code>true</code> then the mapping is enabled, otherwise it is disabled.
* @returns {MappingObject} The mapping object, so that further routes can be added.
*/
Q_INVOKABLE QObject* enable(bool enable = true);
/**jsdoc
* Disable the mapping. When disabled, the routes in the mapping have no effect.<br />
* Synonymous with {@link Controller.disableMapping}.
* @function MappingObject#disable
* @returns {MappingObject} The mapping object, so that further routes can be added.
*/
Q_INVOKABLE QObject* disable() { return enable(false); }
protected:

View file

@ -25,6 +25,18 @@ namespace controller {
class ScriptingInterface;
/**jsdoc
* <p>A route in a {@link MappingObject} used by the {@link Controller} API.</p>
*
* <p>Create a route using {@link MappingObject} methods and apply this object's methods to process it, terminating with
* {@link RouteObject#to} to apply it to a <code>Standard</code> control, action, or script function.</p>
*
* <p>Some methods apply to routes with number data, some apply routes with {@link Pose} data, and some apply to both route
* types.<p>
*
* @class RouteObject
*/
// TODO migrate functionality to a RouteBuilder class and make the proxy defer to that
// (for easier use in both C++ and JS)
class RouteBuilderProxy : public QObject {
@ -33,27 +45,404 @@ class RouteBuilderProxy : public QObject {
RouteBuilderProxy(UserInputMapper& parent, Mapping::Pointer mapping, Route::Pointer route)
: _parent(parent), _mapping(mapping), _route(route) { }
/**jsdoc
* Terminate the route with a standard control, an action, or a script function. The output value from the route is
* sent to the specified destination.<br />
* This is a QML-specific version of {@link MappingObject#to|to}: use this version in QML files.
* @function RouteObject#toQml
* @param {Controller.Standard|Controller.Actions|function} destination - The standard control, action, or JavaScript
* function that the route output is mapped to. For a function, the parameter can be either the name of the function or
* an in-line function definition.
*/
Q_INVOKABLE void toQml(const QJSValue& destination);
/**jsdoc
* Process the route only if a condition is satisfied. The condition is evaluated before the route input is read, and
* the input is read only if the condition is <code>true</code>. Thus, if the condition is not met then subsequent
* routes using the same input are processed.<br />
* This is a QML-specific version of {@link MappingObject#to|to}: use this version in QML files.
* @function RouteObject#whenQml
* @param {condition|condition[]} expression - <p>A <code>condition</code> may be a:</p>
* <ul>
* <li>A boolean or numeric {@link Controller.Hardware} property, which is evaluated as a boolean.</li>
* <li><code>!</code> followed by a {@link Controller.Hardware} property, indicating the logical NOT should be
* used.</li>
* <li>A script function returning a boolean value. This can be either the name of the function or an in-line
* definition.</li>
* </ul>
* <p>If an array of conditions is provided, their values are ANDed together.</p>
* @returns {RouteObject} The <code>RouteObject</code> with the condition added.
*/
Q_INVOKABLE QObject* whenQml(const QJSValue& expression);
/**jsdoc
* Terminate the route with a standard control, an action, or a script function. The output value from the route is
* sent to the specified destination.
* @function RouteObject#to
* @param {Controller.Standard|Controller.Actions|function} destination - The standard control, action, or JavaScript
* function that the route output is mapped to. For a function, the parameter can be either the name of the function or
* an in-line function definition.
*
* @example <caption>Make the right trigger move your avatar up.</caption>
* var MAPPING_NAME = "com.highfidelity.controllers.example.newMapping";
* var mapping = Controller.newMapping(MAPPING_NAME);
*
* mapping.from(Controller.Standard.RT).to(Controller.Actions.TranslateY);
* Controller.enableMapping(MAPPING_NAME);
*
* Script.scriptEnding.connect(function () {
* Controller.disableMapping(MAPPING_NAME);
* });
*
* @example <caption>Make the right trigger call a function.</caption>
* function onRightTrigger(value) {
* print("Trigger value: " + value);
* }
*
* var MAPPING_NAME = "com.highfidelity.controllers.example.newMapping";
* var mapping = Controller.newMapping(MAPPING_NAME);
*
* mapping.from(Controller.Standard.RT).to(onRightTrigger);
* Controller.enableMapping(MAPPING_NAME);
*
* Script.scriptEnding.connect(function () {
* Controller.disableMapping(MAPPING_NAME);
* });
*/
Q_INVOKABLE void to(const QScriptValue& destination);
/**jsdoc
* Enable and disabling writing debug information for a route to the program log.
* @function RouteObject#debug
* @param {boolean} [enable=true] - If <code>true</code> then writing debug information is enabled for the route,
* otherwise it is disabled.
* @returns {RouteObject} The <code>RouteObject</code> with debug output enabled or disabled.
* @example <caption>Write debug information to the program log for a right trigger mapping.</caption>
* var MAPPING_NAME = "com.highfidelity.controllers.example.newMapping";
* var mapping = Controller.newMapping(MAPPING_NAME);
*
* mapping.from(Controller.Standard.RT).debug().to(function (value) {
* print("Value: " + value);
* });
*
* // Information similar to the following is written each frame:
* [DEBUG] [hifi.controllers] Beginning mapping frame
* [DEBUG] [hifi.controllers] Processing device routes
* [DEBUG] [hifi.controllers] Processing standard routes
* [DEBUG] [hifi.controllers] Applying route ""
* [DEBUG] [hifi.controllers] Value was 5.96046e-07
* [DEBUG] [hifi.controllers] Filtered value was 5.96046e-07
*
* Controller.enableMapping(MAPPING_NAME);
*
* Script.scriptEnding.connect(function () {
* Controller.disableMapping(MAPPING_NAME);
* });
*/
Q_INVOKABLE QObject* debug(bool enable = true);
/**jsdoc
* Process the route without marking the controller output as having been read, so that other routes from the same
* controller output can also process.
* @function RouteObject#peek
* @param {boolean} [enable=true] - If <code>true</code> then the route is processed without marking the route's
* controller source as having been read.
* @returns {RouteObject} The <code>RouteObject</code> with the peek feature enabled.
*/
Q_INVOKABLE QObject* peek(bool enable = true);
/**jsdoc
* Process the route only if a condition is satisfied. The condition is evaluated before the route input is read, and
* the input is read only if the condition is <code>true</code>. Thus, if the condition is not met then subsequent
* routes using the same input are processed.
* @function RouteObject#when
* @param {condition|condition[]} expression - <p>A <code>condition</code> may be a:</p>
* <ul>
* <li>A numeric {@link Controller.Hardware} property, which is evaluated as a boolean.</li>
* <li><code>!</code> followed by a {@link Controller.Hardware} property to use the logical NOT of the property
* value.</li>
* <li>A script function returning a boolean value. This can be either the name of the function or an in-line
* definition.</li>
* </ul>
* <p>If an array of conditions is provided, their values are ANDed together.</p>
* @returns {RouteObject} The <code>RouteObject</code> with the condition added.
* @example <caption>Process the right trigger differently in HMD and desktop modes.</caption>
* var MAPPING_NAME = "com.highfidelity.controllers.example.newMapping";
* var mapping = Controller.newMapping(MAPPING_NAME);
*
* // Processed only if in HMD mode.
* mapping.from(Controller.Standard.RT)
* .when(Controller.Hardware.Application.InHMD)
* .to(function () { print("Trigger pressed in HMD mode."); });
*
* // Processed only if previous route not processed.
* mapping.from(Controller.Standard.RT)
* .to(function () { print("Trigger pressed in desktop mode."); });
*
* Controller.enableMapping(MAPPING_NAME);
*
* Script.scriptEnding.connect(function () {
* Controller.disableMapping(MAPPING_NAME);
* });
*/
Q_INVOKABLE QObject* when(const QScriptValue& expression);
/**jsdoc
* Filter numeric route values to lie between two values; values outside this range are not passed on through the
* route.
* @function RouteObject#clamp
* @param {number} min - The minimum value to pass through.
* @param {number} max - The maximum value to pass through.
* @returns {RouteObject} The route object with the clamp filter added.
* @example <caption>Clamp right trigger values to between 0.3 and 0.7.</caption>
* var MAPPING_NAME = "com.highfidelity.controllers.example.newMapping";
* var mapping = Controller.newMapping(MAPPING_NAME);
* mapping.from(Controller.Standard.RT).clamp(0.3, 0.7).to(function (value) {
* print("Value: " + value);
* });
* Controller.enableMapping(MAPPING_NAME);
*
* Script.scriptEnding.connect(function () {
* Controller.disableMapping(MAPPING_NAME);
* });
*/
Q_INVOKABLE QObject* clamp(float min, float max);
/**jsdoc
* Filter numeric route values such that they are rounded to <code>0</code> or <code>1</code> without output values
* flickering when the input value hovers around <code>0.5</code>. For example, this enables you to use an analog input
* as if it were a toggle.
* @function RouteObject#hysteresis
* @param {number} min - When the input value drops below this value the output value changes to <code>0</code>.
* @param {number} max - When the input value rises above this value the output value changes to <code>1</code>.
* @returns {RouteObject} The <code>RouteObject</code> with the filter applied.
* @example <caption>Round the right joystick forward/back values to 0 or 1 with hysteresis.</caption>
* var MAPPING_NAME = "com.highfidelity.controllers.example.newMapping";
* var mapping = Controller.newMapping(MAPPING_NAME);
* mapping.from(Controller.Standard.RY).peek().to(function (value) {
* print("Raw value: " + value); // 0.0 - 1.0.
* });
* mapping.from(Controller.Standard.RY).hysteresis(0.3, 0.7).to(function (value) {
* print("Hysteresis value: " + value); // 0 or 1.
* });
* Controller.enableMapping(MAPPING_NAME);
*
* Script.scriptEnding.connect(function () {
* Controller.disableMapping(MAPPING_NAME);
* });
*/
Q_INVOKABLE QObject* hysteresis(float min, float max);
/**jsdoc
* Filter numeric route values to send at a specified interval.
* @function RouteObject#pulse
* @param {number} interval - The interval between sending values, in seconds.
* @returns {RouteObject} The <code>RouteObject</code> with the filter applied.
* @example <caption>Send right trigger values every half second.</caption>
* var MAPPING_NAME = "com.highfidelity.controllers.example.newMapping";
* var mapping = Controller.newMapping(MAPPING_NAME);
* mapping.from(Controller.Standard.RT).pulse(0.5).to(function (value) {
* print("Value: " + value);
* });
* Controller.enableMapping(MAPPING_NAME);
*
* Script.scriptEnding.connect(function () {
* Controller.disableMapping(MAPPING_NAME);
* });
*/
Q_INVOKABLE QObject* pulse(float interval);
/**jsdoc
* Filter numeric and {@link Pose} route values to be scaled by a constant amount.
* @function RouteObject#scale
* @param {number} multiplier - The scale to multiply the value by.
* @returns {RouteObject} The <code>RouteObject</code> with the filter applied.
* @example <caption>Scale the value of the right joystick forward/back values by 10.</caption>
* var MAPPING_NAME = "com.highfidelity.controllers.example.newMapping";
* var mapping = Controller.newMapping(MAPPING_NAME);
* mapping.from(Controller.Standard.LY).to(function (value) {
* print("L value: " + value); // -1.0 to 1.0 values.
* });
* mapping.from(Controller.Standard.RY).scale(10.0).to(function (value) {
* print("R value: " + value); // -10.0 to -10.0 values.
* });
* Controller.enableMapping(MAPPING_NAME);
*
* Script.scriptEnding.connect(function () {
* Controller.disableMapping(MAPPING_NAME);
* });
*/
Q_INVOKABLE QObject* scale(float multiplier);
/**jsdoc
* Filter numeric and {@link Pose} route values to have the opposite sign, e.g., <code>0.5</code> is changed to
* <code>-0.5</code>.
* @function RouteObject#invert
* @returns {RouteObject} The <code>RouteObject</code> with the filter applied.
* @example <caption>Invert the value of the right joystick forward/back values.</caption>
* var MAPPING_NAME = "com.highfidelity.controllers.example.newMapping";
* var mapping = Controller.newMapping(MAPPING_NAME);
* mapping.from(Controller.Standard.LY).to(function (value) {
* print("L value: " + value); // -1.0 to 1.0 values, forward to back.
* });
* mapping.from(Controller.Standard.RY).invert().to(function (value) {
* print("R value: " + value); // 1.0 to -1.0 values, forward to back.
* });
* Controller.enableMapping(MAPPING_NAME);
*
* Script.scriptEnding.connect(function () {
* Controller.disableMapping(MAPPING_NAME);
* });
*/
Q_INVOKABLE QObject* invert();
/**jsdoc
* Filter numeric route values such that they're sent only when the input value is outside a dead-zone. When the input
* passes the dead-zone value, output is sent starting at <code>0.0</code> and catching up with the input value. As the
* input returns toward the dead-zone value, output values reduce to <code>0.0</code> at the dead-zone value.
* @function RouteObject#deadZone
* @param {number} min - The minimum input value at which to start sending output. For negative input values, the
* negative of this value is used.
* @returns {RouteObject} The <code>RouteObject</code> with the filter applied.
* @example <caption>Apply a dead-zone to the right joystick forward/back values.</caption>
* var MAPPING_NAME = "com.highfidelity.controllers.example.newMapping";
* var mapping = Controller.newMapping(MAPPING_NAME);
* mapping.from(Controller.Standard.RY).deadZone(0.2).to(function (value) {
* print("Value: " + value); // 0.0 - 1.0 values once outside the dead-zone.
* });
* Controller.enableMapping(MAPPING_NAME);
*
* Script.scriptEnding.connect(function () {
* Controller.disableMapping(MAPPING_NAME);
* });
*/
Q_INVOKABLE QObject* deadZone(float min);
/**jsdoc
* Filter numeric route values such that they are rounded to <code>-1</code>, <code>0</code>, or <code>1</code>.
* For example, this enables you to use an analog input as if it were a toggle or, in the case of a bidirectional axis,
* a tri-state switch.
* @function RouteObject#constrainToInteger
* @returns {RouteObject} The <code>RouteObject</code> with the filter applied.
* @example <caption>Round the right joystick forward/back values to <code>-1</code>, <code>0</code>, or
* <code>1</code>.</caption>
* var MAPPING_NAME = "com.highfidelity.controllers.example.newMapping";
* var mapping = Controller.newMapping(MAPPING_NAME);
* mapping.from(Controller.Standard.RY).constrainToInteger().to(function (value) {
* print("Value: " + value); // -1, 0, or 1
* });
* Controller.enableMapping(MAPPING_NAME);
*
* Script.scriptEnding.connect(function () {
* Controller.disableMapping(MAPPING_NAME);
* });
*/
Q_INVOKABLE QObject* constrainToInteger();
/**jsdoc
* Filter numeric route values such that they are rounded to <code>0</code> or <code>1</code>. For example, this
* enables you to use an analog input as if it were a toggle.
* @function RouteObject#constrainToPositiveInteger
* @returns {RouteObject} The <code>RouteObject</code> with the filter applied.
* @example <caption>Round the right joystick forward/back values to <code>0</code> or <code>1</code>.</caption>
* var MAPPING_NAME = "com.highfidelity.controllers.example.newMapping";
* var mapping = Controller.newMapping(MAPPING_NAME);
* mapping.from(Controller.Standard.RY).constrainToPositiveInteger().to(function (value) {
* print("Value: " + value); // 0, or 1
* });
* Controller.enableMapping(MAPPING_NAME);
*
* Script.scriptEnding.connect(function () {
* Controller.disableMapping(MAPPING_NAME);
* });
*/
Q_INVOKABLE QObject* constrainToPositiveInteger();
/**jsdoc
* Filter {@link Pose} route values to have a pre-translation applied.
* @function RouteObject#translate
* @param {Vec3} translate - The pre-translation to add to the pose.
* @returns {RouteObject} The <code>RouteObject</code> with the pre-translation applied.
*/
// No JSDoc example because filter not currently used.
Q_INVOKABLE QObject* translate(glm::vec3 translate);
/**jsdoc
* Filter {@link Pose} route values to have a pre-transform applied.
* @function RouteObject#transform
* @param {Mat4} transform - The pre-transform to apply.
* @returns {RouteObject} The <code>RouteObject</code> with the pre-transform applied.
*/
// No JSDoc example because filter not currently used.
Q_INVOKABLE QObject* transform(glm::mat4 transform);
/**jsdoc
* Filter {@link Pose} route values to have a post-transform applied.
* @function RouteObject#postTransform
* @param {Mat4} transform - The post-transform to apply.
* @returns {RouteObject} The <code>RouteObject</code> with the post-transform applied.
*/
// No JSDoc example because filter not currently used.
Q_INVOKABLE QObject* postTransform(glm::mat4 transform);
/**jsdoc
* Filter {@link Pose} route values to have a pre-rotation applied.
* @function RouteObject#rotate
* @param {Quat} rotation - The pre-rotation to add to the pose.
* @returns {RouteObject} The <code>RouteObject</code> with the pre-rotation applied.
*/
// No JSDoc example because filter not currently used.
Q_INVOKABLE QObject* rotate(glm::quat rotation);
/**jsdoc
* Filter {@link Pose} route values to be smoothed by a low velocity filter. The filter's rotation and translation
* values are calculated as: <code>(1 - f) * currentValue + f * previousValue</code> where
* <code>f = currentVelocity / filterConstant</code>. At low velocities, the filter value is largely the previous
* value; at high velocities the value is wholly the current controller value.
* @function RouteObject#lowVelocity
* @param {number} rotationConstant - The rotational velocity, in rad/s, at which the filter value is wholly the latest
* controller value.
* @param {number} translationConstant - The linear velocity, in m/s, at which the filter value is wholly the latest
* controller value.
* @returns {RouteObject} The <code>RouteObject</code> smoothed by low velocity filtering.
*/
// No JSDoc example because filter not currently used.
Q_INVOKABLE QObject* lowVelocity(float rotationConstant, float translationConstant);
/**jsdoc
* Filter {@link Pose} route values to be smoothed by an exponential decay filter. The filter's rotation and
* translation values are calculated as: <code>filterConstant * currentValue + (1 - filterConstant) *
* previousValue</code>. Values near 1 are less smooth with lower latency; values near 0 are more smooth with higher
* latency.
* @function RouteObject#exponentialSmoothing
* @param {number} rotationConstant - Rotation filter constant, <code>0.0&ndash;1.0</code>.
* @param {number} translationConstant - Translation filter constant, <code>0.0&ndash;1.0</code>.
* @returns {RouteObject} The <code>RouteObject</code> smoothed by an exponential filter.
*/
// No JSDoc example because filter used only in Vive.json.
Q_INVOKABLE QObject* exponentialSmoothing(float rotationConstant, float translationConstant);
/**jsdoc
* Filter numeric route values such that a value of <code>0.0</code> is changed to <code>1.0</code>, and other values
* are changed to <code>0.0</code>.
* @function RouteObject#logicalNot
* @returns {RouteObject} The <code>RouteObject</code> with the filter applied.
* @example <caption>Logical NOT of LSTouch value.</caption>
* var MAPPING_NAME = "com.highfidelity.controllers.example.newMapping";
* var mapping = Controller.newMapping(MAPPING_NAME);
*
* mapping.from(Controller.Standard.RSTouch).peek().to(function (value) {
* print("RSTouch: " + value);
* });
* mapping.from(Controller.Standard.RSTouch).logicalNot().to(function (value) {
* print("localNot of RSTouch: " + value);
* });
* Controller.enableMapping(MAPPING_NAME);
*
* Script.scriptEnding.connect(function () {
* Controller.disableMapping(MAPPING_NAME);
* });
*/
Q_INVOKABLE QObject* logicalNot();
private:

View file

@ -1649,7 +1649,7 @@ signals:
/**jsdoc
* Triggered when a mouse button is double-clicked while the mouse cursor is on an entity.
* @function Entities.mousePressOnEntity
* @function Entities.mouseDoublePressOnEntity
* @param {Uuid} entityID - The ID of the entity that was double-pressed.
* @param {PointerEvent} event - Details of the event.
* @returns {Signal}

View file

@ -216,6 +216,72 @@ controller::Input KeyboardMouseDevice::InputDevice::makeInput(KeyboardMouseDevic
return controller::Input(_deviceID, button, controller::ChannelType::BUTTON);
}
/**jsdoc
* <p>The <code>Controller.Hardware.Keyboard</code> object has properties representing keyboard, mouse, and display touch
* events. The property values are integer IDs, uniquely identifying each output. <em>Read-only.</em> These can be can be
* mapped to actions or functions or <code>Controller.Standard</code> items in a {@link RouteObject} mapping. For presses,
* each data value is either <code>1.0</code> for "true" or <code>0.0</code> for "false".</p>
* <table>
* <thead>
* <tr><th>Property</th><th>Type</th><td>Data</th><th>Description</th></tr>
* </thead>
* <tbody>
* <tr><td><code>0</code> &ndash; <code>9</code></td><td>number</td><td>number</td><td>A "0" &ndash; "1" key on the
* keyboard or keypad is pressed.</td></tr>
* <tr><td><code>A</code> &ndash; <code>Z</code></td><td>number</td><td>number</td><td>A "A" &ndash; "Z" key on the
* keyboard is pressed.</td></tr>
* <tr><td><code>Space</code></td><td>number</td><td>number</td><td>The space bar on the keyboard is pressed.</td></tr>
* <tr><td><code>Tab</code></td><td>number</td><td>number</td><td>The tab key on the keyboard is pressed.</td></tr>
* <tr><td><code>Shift</code></td><td>number</td><td>number</td><td>The shift key on the keyboard is pressed.</td></tr>
* <tr><td><code>Control</code></td><td>number</td><td>number</td><td>The control key on the keyboard is pressed. (The
* "Command" key on OSX.)</td></tr>
* <tr><td><code>Left</code></td><td>number</td><td>number</td><td>The left arrow key on the keyboard or keypad is pressed.
* </td></tr>
* <tr><td><code>Right</code></td><td>number</td><td>number</td><td>The right arrow key on the keyboard or keypad is
* pressed.</td></tr>
* <tr><td><code>Up</code></td><td>number</td><td>number</td><td>The up arrow key on the keyboard or keypad is pressed.
* </td></tr>
* <tr><td><code>Down</code></td><td>number</td><td>number</td><td>The down arrow key on the keyboard or keypad is pressed.
* </td></tr>
* <tr><td><code>PgUp</code></td><td>number</td><td>number</td><td>The page up key on the keyboard or keypad is pressed.
* </td></tr>
* <tr><td><code>PgDown</code></td><td>number</td><td>number</td><td>The page down key on the keyboard or keypad is pressed.
* </td></tr>
* <tr><td><code>LeftMouseButton</code></td><td>number</td><td>number</td><td>The left mouse button pressed.</td></tr>
* <tr><td><code>MiddleMouseButton</code></td><td>number</td><td>number</td><td>The middle mouse button pressed.</td></tr>
* <tr><td><code>RightMouseButton</code></td><td>number</td><td>number</td><td>The right mouse button pressed.</td></tr>
* <tr><td><code>LeftMouseClicked</code></td><td>number</td><td>number</td><td>The left mouse button clicked.</td></tr>
* <tr><td><code>MiddleMouseClicked</code></td><td>number</td><td>number</td><td>The middle mouse button clicked.</td></tr>
* <tr><td><code>RightMouseClicked</code></td><td>number</td><td>number</td><td>The right mouse button clicked.</td></tr>
* <tr><td><code>MouseMoveRight</code></td><td>number</td><td>number</td><td>The mouse moved right.</td></tr>
* <tr><td><code>MouseMoveLeft</code></td><td>number</td><td>number</td><td>The mouse moved left.</td></tr>
* <tr><td><code>MouseMoveUp</code></td><td>number</td><td>number</td><td>The mouse moved up.</td></tr>
* <tr><td><code>MouseMoveDown</code></td><td>number</td><td>number</td><td>The mouse moved down.</td></tr>
* <tr><td><code>MouseX</code></td><td>number</td><td>number</td><td>The mouse x-coordinate changed. The data value is its
* new x-coordinate value.</td></tr>
* <tr><td><code>MouseY</code></td><td>number</td><td>number</td><td>The mouse y-coordinate changed. The data value is its
* new y-coordinate value.</td></tr>
* <tr><td><code>MouseWheelRight</code></td><td>number</td><td>number</td><td>The mouse wheel rotated left. The data value
* is the number of units rotated (typically <code>1.0</code>).</td></tr>
* <tr><td><code>MouseWheelLeft</code></td><td>number</td><td>number</td><td>The mouse wheel rotated left. The data value
* is the number of units rotated (typically <code>1.0</code>).</td></tr>
* <tr><td><code>MouseWheelUp</code></td><td>number</td><td>number</td><td>The mouse wheel rotated up. The data value
* is the number of units rotated (typically <code>1.0</code>).</td></tr>
* <tr><td><code>MouseWheelDown</code></td><td>number</td><td>number</td><td>The mouse wheel rotated down. The data value
* is the number of units rotated (typically <code>1.0</code>).</td></tr>
* <tr><td><code>TouchpadRight</code></td><td>number</td><td>number</td><td>The average touch on a touch-enabled device
* moved right. The data value is how far the average position of all touch points moved.</td></tr>
* <tr><td><code>TouchpadLeft</code></td><td>number</td><td>number</td><td>The average touch on a touch-enabled device
* moved left. The data value is how far the average position of all touch points moved.</td></tr>
* <tr><td><code>TouchpadUp</code></td><td>number</td><td>number</td><td>The average touch on a touch-enabled device
* moved up. The data value is how far the average position of all touch points moved.</td></tr>
* <tr><td><code>TouchpadDown</code></td><td>number</td><td>number</td><td>The average touch on a touch-enabled device
* moved down. The data value is how far the average position of all touch points moved.</td></tr>
* </tbody>
* </table>
* @typedef Controller.Hardware-Keyboard
* @todo <em>Currently, the mouse wheel in an ordinary mouse generates left/right wheel events instead of up/down.</em>
*/
controller::Input::NamedVector KeyboardMouseDevice::InputDevice::getAvailableInputs() const {
using namespace controller;
static QVector<Input::NamedPair> availableInputs;

View file

@ -150,6 +150,29 @@ KeyEvent::operator QKeySequence() const {
return QKeySequence(resultCode);
}
/**jsdoc
* A keyboard key event.
* @typedef {object} KeyEvent
* @property {number} key - The Qt keyboard code of the key pressed. For a list of keyboard codes, see
* <a href="http://doc.qt.io/qt-5/qt.html#Key-enum">http://doc.qt.io/qt-5/qt.html#Key-enum</a>.
* @property {string} text - A string describing the key. For example, <code>"a"</code> for the "A" key if the Shift is not
* pressed, <code>"F1"</code> for the F1 key, <code>"SPACE"</code> for the space bar.
* @property {boolean} isShifted - <code>true</code> if a Shift key was pressed when the event was generated, otherwise
* <code>false</code>.
* @property {boolean} isMeta - <code>true</code> if a meta key was pressed when the event was generated, otherwise
* <code>false</code>. On Windows the "meta" key is the Windows key; on OSX it is the Control (Splat) key.
* @property {boolean} isControl - <code>true</code> if a control key was pressed when the event was generated, otherwise
* <code>false</code>. On Windows the "control" key is the Ctrl key; on OSX it is the Command key.
* @property {boolean} isAlt - <code>true</code> if an Alt key was pressed when the event was generated, otherwise
* <code>false</code>.
* @property {boolean} isKeypad - <code>true</code> if the key is on the numeric keypad, otherwise <code>false</code>.
* @property {boolean} isAutoRepeat - <code>true</code> if the event is a repeat for key that is being held down, otherwise
* <code>false</code>.
* @example <caption>Report the KeyEvent details for each key press.</caption>
* Controller.keyPressEvent.connect(function (event) {
* print(JSON.stringify(event));
* });
*/
QScriptValue KeyEvent::toScriptValue(QScriptEngine* engine, const KeyEvent& event) {
QScriptValue obj = engine->newObject();
obj.setProperty("key", event.key);
@ -275,7 +298,6 @@ void KeyEvent::fromScriptValue(const QScriptValue& object, KeyEvent& event) {
}
}
const bool wantDebug = false;
if (wantDebug) {
qCDebug(scriptengine) << "event.key=" << event.key

View file

@ -60,6 +60,32 @@ MouseEvent::MouseEvent(const QMouseEvent& event) :
}
}
/**jsdoc
* A controller mouse movement or button event.
* @typedef {object} MouseEvent
* @property {number} x - Integer x-coordinate of the event on the Interface window or HMD HUD.
* @property {number} y - Integer y-coordinate of the event on the Interface window or HMD HUD.
* @property {string} button - <code>"LEFT"</code>, <code>"MIDDLE"</code>, or <code>"RIGHT"</code> if a button press or release
* caused the event, otherwise <code>"NONE"</code>.
* @property {boolean} isLeftButton - <code>true</code> if the left button was pressed when the event was generated, otherwise
* <code>false</code>.
* @property {boolean} isMiddleButton - <code>true</code> if the middle button was pressed when the event was generated,
* otherwise <code>false</code>.
* @property {boolean} isRightButton - <code>true</code> if the right button was pressed when the event was generated,
* otherwise <code>false</code>.
* @property {boolean} isShifted - <code>true</code> if the Shift key was pressed when the event was generated, otherwise
* <code>false</code>.
* @property {boolean} isMeta - <code>true</code> if the "meta" key was pressed when the event was generated, otherwise
* <code>false</code>. On Windows the "meta" key is the Windows key; on OSX it is the Control (Splat) key.
* @property {boolean} isControl - <code>true</code> if the "control" key was pressed when the event was generated, otherwise
* <code>false</code>. On Windows the "control" key is the Ctrl key; on OSX it is the Command key.
* @property {boolean} isAlt - <code>true</code> if the Alt key was pressed when the event was generated, otherwise
* <code>false</code>.
* @example <caption>Report the MouseEvent details for each mouse move.</caption>
* Controller.mouseMoveEvent.connect(function (event) {
* print(JSON.stringify(event));
* });
*/
QScriptValue MouseEvent::toScriptValue(QScriptEngine* engine, const MouseEvent& event) {
QScriptValue obj = engine->newObject();
obj.setProperty("x", event.x);

View file

@ -165,6 +165,45 @@ void TouchEvent::calculateMetaAttributes(const TouchEvent& other) {
}
}
/**jsdoc
* A display or device touch event.
* @typedef {object} TouchEvent
* @property {number} x - Integer x-coordinate of the average position of the touch events.
* @property {number} y - Integer y-coordinate of the average position of the touch events.
* @property {boolean} isPressed - <code>true</code> if the touch point has just been pressed, otherwise <code>false</code>.
* @property {boolean} isMoved - <code>true</code> if the touch point has moved, otherwise <code>false</code>.
* @property {boolean} isStationary - <code>true</code> if the touch point has not moved, otherwise <code>false</code>.
* @property {boolean} isReleased - <code>true</code> if the touch point has just been released, otherwise <code>false</code>.
* @property {boolean} isShifted - <code>true</code> if the Shift key was pressed when the event was generated, otherwise
* <code>false</code>.
* @property {boolean} isMeta - <code>true</code> if the "meta" key was pressed when the event was generated, otherwise
* <code>false</code>. On Windows the "meta" key is the Windows key; on OSX it is the Control (Splat) key.
* @property {boolean} isControl - <code>true</code> if the "control" key was pressed when the event was generated, otherwise
* <code>false</code>. On Windows the "control" key is the Ctrl key; on OSX it is the Command key.
* @property {boolean} isAlt - <code>true</code> if the Alt key was pressed when the event was generated, otherwise
* <code>false</code>.
* @property {number} touchPoints - Integer number of touch points.
* @property {Vec2[]} points - The coordinates of the touch points.
* @property {number} radius - The radius of a circle centered on their average position that encompasses the touch points.
* @property {boolean} isPinching - <code>true</code> if the <code>radius</code> has reduced since the most recent touch event
* with a different <code>radius</code> value, otherwise <code>false</code>.
* @property {boolean} isPinchOpening - <code>true</code> if the <code>radius</code> has increased since the most recent touch
* event with a different <code>radius</code> value, otherwise <code>false</code>.
* @property {number} angle - An angle calculated from the touch points, in degrees.
* @property {number} deltaAngle - The change in the <code>angle</code> value since the previous touch event, in degrees, if
* the number of touch points is the same, otherwise <code>0.0</code>.
* @property {number[]} angles - The angles of each touch point about the center of all the touch points, in degrees.
* @property {boolean} isRotating - <code>true</code> if the <code>angle</code> of the touch event has changed since the
* previous touch event and the number of touch points is the same, otherwise <code>false</code>.
* @property {string} rotating - <code>"clockwise"</code> or <code>"counterClockwise"</code> if the <code>angle</code> of the
* touch event has changed since the previous touch event and the number of touch points is the same, otherwise
* <code>"none"</code>.
*
* @example <caption>Report the TouchEvent details when a touch event starts.</caption>
* Controller.touchBeginEvent.connect(function (event) {
* print(JSON.stringify(event));
* });
*/
QScriptValue TouchEvent::toScriptValue(QScriptEngine* engine, const TouchEvent& event) {
QScriptValue obj = engine->newObject();
obj.setProperty("x", event.x);

View file

@ -53,7 +53,34 @@ WheelEvent::WheelEvent(const QWheelEvent& event) {
isAlt = event.modifiers().testFlag(Qt::AltModifier);
}
/**jsdoc
* A mouse wheel event.
* @typedef {object} WheelEvent
* @property {number} x - Integer x-coordinate of the event on the Interface window or HMD HUD.
* @property {number} y - Integer y-coordinate of the event on the Interface window or HMD HUD.
* @property {number} delta - Integer number indicating the direction and speed to scroll: positive numbers to scroll up, and
* negative numers to scroll down.
* @property {string} orientation - The orientation of the wheel: <code>"VERTICAL"</code> for a typical mouse;
* <code>"HORIZONTAL"</code> for a "horizontal" wheel.
* @property {boolean} isLeftButton - <code>true</code> if the left button was pressed when the event was generated, otherwise
* <code>false</code>.
* @property {boolean} isMiddleButton - <code>true</code> if the middle button was pressed when the event was generated,
* otherwise <code>false</code>.
* @property {boolean} isRightButton - <code>true</code> if the right button was pressed when the event was generated,
* otherwise <code>false</code>.
* @property {boolean} isShifted - <code>true</code> if the Shift key was pressed when the event was generated, otherwise
* <code>false</code>.
* @property {boolean} isMeta - <code>true</code> if the "meta" key was pressed when the event was generated, otherwise
* <code>false</code>. On Windows the "meta" key is the Windows key; on OSX it is the Control (Splat) key.
* @property {boolean} isControl - <code>true</code> if the "control" key was pressed when the event was generated, otherwise
* <code>false</code>. On Windows the "control" key is the Ctrl key; on OSX it is the Command key.
* @property {boolean} isAlt - <code>true</code> if the Alt key was pressed when the event was generated, otherwise
* <code>false</code>.
* @example <caption>Report the WheelEvent details for each wheel rotation.</caption>
* Controller.wheelEvent.connect(function (event) {
* print(JSON.stringify(event));
* });
*/
QScriptValue WheelEvent::toScriptValue(QScriptEngine* engine, const WheelEvent& event) {
QScriptValue obj = engine->newObject();
obj.setProperty("x", event.x);

View file

@ -110,11 +110,13 @@ void PointerEvent::setButton(Button button) {
* <tr><td>Shift</td><td><code>0x02000000</code></td><td><code>33554432</code></td>
* <td>A Shift key on the keyboard is pressed.</td></tr>
* <tr><td>Control</td><td><code>0x04000000</code></td><td><code>67108864</code></td>
* <td>A Control key on the keyboard is pressed.</td></tr>
* <td>A control key on the keyboard is pressed. On Windows the "control" key is the Ctrl key; on OSX it is the Command
* key.</td></tr>
* <tr><td>Alt</td><td><code>0x08000000</code></td><td><code>134217728</code></td>
* <td>An Alt key on the keyboard is pressed.</td></tr>
* <tr><td>Meta</td><td><code>0x10000000</code></td><td><code>268435456</code></td>
* <td>A Meta or Windows key on the keyboard is pressed.</td></tr>
* <td>A meta key on the keyboard is pressed. On Windows the "meta" key is the Windows key; on OSX it is the Control
* (Splat) key.</td></tr>
* <tr><td>Keypad</td><td><code>0x20000000</code></td><td><code>536870912</code></td>
* <td>A keypad button is pressed.</td></tr>
* <tr><td>Group</td><td><code>0x40000000</code></td><td><code>1073741824</code></td>

View file

@ -383,6 +383,67 @@ void OculusControllerManager::TouchDevice::stopHapticPulse(bool leftHand) {
ovr_SetControllerVibration(_parent._session, handType, 0.0f, 0.0f);
}
/**jsdoc
* <p>The <code>Controller.Hardware.OculusTouch</code> object has properties representing Oculus Rift. The property values are
* integer IDs, uniquely identifying each output. <em>Read-only.</em> These can be can be mapped to actions or functions or
* <code>Controller.Standard</code> items in a {@link RouteObject} mapping.</p>
* <table>
* <thead>
* <tr><th>Property</th><th>Type</th><th>Data</th><th>Description</th></tr>
* </thead>
* <tbody>
* <tr><td colspan="4"><strong>Buttons</strong></td></tr>
* <tr><td><code>A</code></td><td>number</td><td>number</td><td>"A" button pressed.</td></tr>
* <tr><td><code>B</code></td><td>number</td><td>number</td><td>"B" button pressed.</td></tr>
* <tr><td><code>X</code></td><td>number</td><td>number</td><td>"X" button pressed.</td></tr>
* <tr><td><code>Y</code></td><td>number</td><td>number</td><td>"Y" button pressed.</td></tr>
* <tr><td><code>LeftApplicationMenu</code></td><td>number</td><td>number</td><td>Left application menu button pressed.
* </td></tr>
* <tr><td><code>RightApplicationMenu</code></td><td>number</td><td>number</td><td>Right application menu button pressed.
* </td></tr>
* <tr><td colspan="4"><strong>Sticks</strong></td></tr>
* <tr><td><code>LX</code></td><td>number</td><td>number</td><td>Left stick x-axis scale.</td></tr>
* <tr><td><code>LY</code></td><td>number</td><td>number</td><td>Left stick y-axis scale.</td></tr>
* <tr><td><code>RX</code></td><td>number</td><td>number</td><td>Right stick x-axis scale.</td></tr>
* <tr><td><code>RY</code></td><td>number</td><td>number</td><td>Right stick y-axis scale.</td></tr>
* <tr><td><code>LS</code></td><td>number</td><td>number</td><td>Left stick button pressed.</td></tr>
* <tr><td><code>RS</code></td><td>number</td><td>number</td><td>Right stick button pressed.</td></tr>
* <tr><td><code>LSTouch</code></td><td>number</td><td>number</td><td>Left stick is touched.</td></tr>
* <tr><td><code>RSTouch</code></td><td>number</td><td>number</td><td>Right stick is touched.</td></tr>
* <tr><td colspan="4"><strong>Triggers</strong></td></tr>
* <tr><td><code>LT</code></td><td>number</td><td>number</td><td>Left trigger scale.</td></tr>
* <tr><td><code>RT</code></td><td>number</td><td>number</td><td>Right trigger scale.</td></tr>
* <tr><td><code>LeftGrip</code></td><td>number</td><td>number</td><td>Left grip scale.</td></tr>
* <tr><td><code>RightGrip</code></td><td>number</td><td>number</td><td>Right grip scale.</td></tr>
* <tr><td colspan="4"><strong>Finger Abstractions</strong></td></tr>
* <tr><td><code>LeftPrimaryThumbTouch</code></td><td>number</td><td>number</td><td>Left thumb touching primary thumb
* button.</td></tr>
* <tr><td><code>LeftSecondaryThumbTouch</code></td><td>number</td><td>number</td><td>Left thumb touching secondary thumb
* button.</td></tr>
* <tr><td><code>LeftThumbUp</code></td><td>number</td><td>number</td><td>Left thumb not touching primary or secondary
* thumb buttons.</td></tr>
* <tr><td><code>RightPrimaryThumbTouch</code></td><td>number</td><td>number</td><td>Right thumb touching primary thumb
* button.</td></tr>
* <tr><td><code>RightSecondaryThumbTouch</code></td><td>number</td><td>number</td><td>Right thumb touching secondary thumb
* button.</td></tr>
* <tr><td><code>RightThumbUp</code></td><td>number</td><td>number</td><td>Right thumb not touching primary or secondary
* thumb buttons.</td></tr>
* <tr><td><code>LeftPrimaryIndexTouch</code></td><td>number</td><td>number</td><td>Left index finger is touching primary
* index finger control.</td></tr>
* <tr><td><code>LeftIndexPoint</code></td><td>number</td><td>number</td><td>Left index finger is pointing, not touching
* primary or secondary index finger controls.</td></tr>
* <tr><td><code>RightPrimaryIndexTouch</code></td><td>number</td><td>number</td><td>Right index finger is touching primary
* index finger control.</td></tr>
* <tr><td><code>RightIndexPoint</code></td><td>number</td><td>number</td><td>Right index finger is pointing, not touching
* primary or secondary index finger controls.</td></tr>
* <tr><td colspan="4"><strong>Avatar Skeleton</strong></td></tr>
* <tr><td><code>Head</code></td><td>number</td><td>{@link Pose}</td><td>Head pose.</td></tr>
* <tr><td><code>LeftHand</code></td><td>number</td><td>{@link Pose}</td><td>Left hand pose.</td></tr>
* <tr><td><code>RightHand</code></td><td>number</td><td>{@link Pose}</td><td>right hand pose.</td></tr>
* </tbody>
* </table>
* @typedef Controller.Hardware-OculusTouch
*/
controller::Input::NamedVector OculusControllerManager::TouchDevice::getAvailableInputs() const {
using namespace controller;
QVector<Input::NamedPair> availableInputs{

View file

@ -1232,6 +1232,66 @@ void ViveControllerManager::InputDevice::setConfigFromString(const QString& valu
}
}
/**jsdoc
* <p>The <code>Controller.Hardware.Vive</code> object has properties representing Vive. The property values are integer IDs,
* uniquely identifying each output. <em>Read-only.</em> These can be can be mapped to actions or functions or
* <code>Controller.Standard</code> items in a {@link RouteObject} mapping.</p>
* <table>
* <thead>
* <tr><th>Property</th><th>Type</th><th>Data</th><th>Description</th></tr>
* </thead>
* <tbody>
* <tr><td colspan="4"><strong>Touch Pad (Sticks)</strong></td></tr>
* <tr><td><code>LX</code></td><td>number</td><td>number</td><td>Left touch pad x-axis scale.</td></tr>
* <tr><td><code>LY</code></td><td>number</td><td>number</td><td>left touch pad y-axis scale.</td></tr>
* <tr><td><code>RX</code></td><td>number</td><td>number</td><td>Right stick x-axis scale.</td></tr>
* <tr><td><code>RY</code></td><td>number</td><td>number</td><td>Right stick y-axis scale.</td></tr>
* <tr><td><code>LS</code></td><td>number</td><td>number</td><td>Left touch pad pressed.</td></tr>
* <tr><td><code>LS_CENTER</code></td><td>number</td><td>number</td><td>Left touch pad center pressed.</td></tr>
* <tr><td><code>LS_X</code></td><td>number</td><td>number</td><td>Left touch pad pressed x-coordinate.</td></tr>
* <tr><td><code>LS_Y</code></td><td>number</td><td>number</td><td>Left touch pad pressed y-coordinate.</td></tr>
* <tr><td><code>RS</code></td><td>number</td><td>number</td><td>Right touch pad pressed.</td></tr>
* <tr><td><code>RS_CENTER</code></td><td>number</td><td>number</td><td>Right touch pad center pressed.</td></tr>
* <tr><td><code>RS_X</code></td><td>number</td><td>number</td><td>Right touch pad pressed x-coordinate.</td></tr>
* <tr><td><code>RS_Y</code></td><td>number</td><td>number</td><td>Right touch pad pressed y-coordinate.</td></tr>
* <tr><td><code>LSTouch</code></td><td>number</td><td>number</td><td>Left touch pad is touched.</td></tr>
* <tr><td><code>RSTouch</code></td><td>number</td><td>number</td><td>Right touch pad is touched.</td></tr>
* <tr><td colspan="4"><strong>Triggers</strong></td></tr>
* <tr><td><code>LT</code></td><td>number</td><td>number</td><td>Left trigger scale.</td></tr>
* <tr><td><code>RT</code></td><td>number</td><td>number</td><td>Right trigger scale.</td></tr>
* <tr><td><code>LTClick</code></td><td>number</td><td>number</td><td>Left trigger click.</td></tr>
* <tr><td><code>RTClick</code></td><td>number</td><td>number</td><td>Right trigger click.</td></tr>
* <tr><td><code>LeftGrip</code></td><td>number</td><td>number</td><td>Left grip scale.</td></tr>
* <tr><td><code>RightGrip</code></td><td>number</td><td>number</td><td>Right grip scale.</td></tr>
* <tr><td colspan="4"><strong>Avatar Skeleton</strong></td></tr>
* <tr><td><code>Hips</code></td><td>number</td><td>{@link Pose}</td><td>Hips pose.</td></tr>
* <tr><td><code>Spine2</code></td><td>number</td><td>{@link Pose}</td><td>Spine2 pose.</td></tr>
* <tr><td><code>Head</code></td><td>number</td><td>{@link Pose}</td><td>Head pose.</td></tr>
* <tr><td><code>LeftArm</code></td><td>number</td><td>{@link Pose}</td><td>Left arm pose.</td></tr>
* <tr><td><code>RightArm</code></td><td>number</td><td>{@link Pose}</td><td>Right arm pose</td></tr>
* <tr><td><code>LeftHand</code></td><td>number</td><td>{@link Pose}</td><td>Left hand pose.</td></tr>
* <tr><td><code>RightHand</code></td><td>number</td><td>{@link Pose}</td><td>Right hand pose.</td></tr>
* <tr><td colspan="4"><strong>Trackers</strong></td></tr>
* <tr><td><code>TrackedObject00</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 0 pose.</td></tr>
* <tr><td><code>TrackedObject01</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 1 pose.</td></tr>
* <tr><td><code>TrackedObject02</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 2 pose.</td></tr>
* <tr><td><code>TrackedObject03</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 3 pose.</td></tr>
* <tr><td><code>TrackedObject04</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 4 pose.</td></tr>
* <tr><td><code>TrackedObject05</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 5 pose.</td></tr>
* <tr><td><code>TrackedObject06</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 6 pose.</td></tr>
* <tr><td><code>TrackedObject07</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 7 pose.</td></tr>
* <tr><td><code>TrackedObject08</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 8 pose.</td></tr>
* <tr><td><code>TrackedObject09</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 9 pose.</td></tr>
* <tr><td><code>TrackedObject10</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 10 pose.</td></tr>
* <tr><td><code>TrackedObject11</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 11 pose.</td></tr>
* <tr><td><code>TrackedObject12</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 12 pose.</td></tr>
* <tr><td><code>TrackedObject13</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 13 pose.</td></tr>
* <tr><td><code>TrackedObject14</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 14 pose.</td></tr>
* <tr><td><code>TrackedObject15</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 15 pose.</td></tr>
* </tbody>
* </table>
* @typedef Controller.Hardware-Vive
*/
controller::Input::NamedVector ViveControllerManager::InputDevice::getAvailableInputs() const {
using namespace controller;
QVector<Input::NamedPair> availableInputs{

View file

@ -24,8 +24,10 @@ exports.handlers = {
'../../libraries/animation/src',
'../../libraries/avatars/src',
'../../libraries/controllers/src/controllers/',
'../../libraries/controllers/src/controllers/impl/',
'../../libraries/graphics-scripting/src/graphics-scripting/',
'../../libraries/entities/src',
'../../libraries/input-plugins/src/input-plugins',
'../../libraries/model-networking/src/model-networking/',
'../../libraries/octree/src',
'../../libraries/networking/src',
@ -34,6 +36,8 @@ exports.handlers = {
'../../libraries/script-engine/src',
'../../libraries/shared/src',
'../../libraries/shared/src/shared',
'../../plugins/oculus/src',
'../../plugins/openvr/src',
];
var exts = ['.h', '.cpp'];