overte-lubosz/interface/src/scripting/ControllerScriptingInterface.h
2018-04-21 12:45:00 +12:00

422 lines
17 KiB
C++

//
// ControllerScriptingInterface.h
// interface/src/scripting
//
// Created by Brad Hefta-Gaub on 12/17/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_ControllerScriptingInterface_h
#define hifi_ControllerScriptingInterface_h
#include <QtCore/QObject>
#include <controllers/UserInputMapper.h>
#include <controllers/ScriptingInterface.h>
#include <KeyEvent.h>
#include <MouseEvent.h>
#include <SpatialEvent.h>
#include <TouchEvent.h>
#include <WheelEvent.h>
class ScriptEngine;
/**jsdoc
* The Controller API provides facilities to interact with computer and controller hardware.
*
* <h5>Functions:</h5>
*
* <p>Properties</p>
* <ul>
* <li>{@link Controller.getActions|getActions}</li>
* <li>{@link Controller.getHardware|getHardware}</li>
* <li>{@link Controller.getStandard|getStandard}</li>
* </ul>
*
* <p>Mappings</p>
* <ul>
* <li>{@link Controller.disableMapping|disableMapping}</li>
* <li>{@link Controller.enableMapping|enableMapping}</li>
* <li>{@link Controller.loadMapping|loadMapping}</li>
* <li>{@link Controller.newMapping|newMapping}</li>
* <li>{@link Controller.parseMapping|parseMapping}</li>
* </ul>
*
* <p>Input, Hardware, and Action Reflection</p>
* <ul>
* <li>{@link Controller.findAction|findAction}</li>
* <li>{@link Controller.findDevice|findDevice}</li>
* <li>{@link Controller.getActionNames|getActionNames}</li>
* <li>{@link Controller.getAllActions|getAllActions}</li>
* <li>{@link Controller.getAvailableInputs|getAvailableInputs}</li>
* <li>{@link Controller.getDeviceName|getDeviceName}</li>
* <li>{@link Controller.getDeviceNames|getDeviceNames}</li>
* </ul>
*
* <p>Input, Hardware, and Action Events</p>
* <ul>
* <li>{@link Controller.actionEvent|actionEvent}</li>
* <li>{@link Controller.hardwareChanged|hardwareChanged}</li>
* <li>{@link Controller.inputEvent|inputEvent}</li>
* </ul>
*
* <p>Mouse, Keyboard, and Touch Events</p>
* <ul>
* <li>{@link Controller.keyPressEvent|keyPressEvent}</li>
* <li>{@link Controller.keyReleaseEvent|keyReleaseEvent}</li>
* <li>{@link Controller.mouseDoublePressEvent|mouseDoublePressEvent}</li>
* <li>{@link Controller.mouseMoveEvent|mouseMoveEvent}</li>
* <li>{@link Controller.mousePressEvent|mousePressEvent}</li>
* <li>{@link Controller.mouseReleaseEvent|mouseReleaseEvent}</li>
* <li>{@link Controller.touchBeginEvent|touchBeginEvent}</li>
* <li>{@link Controller.touchEndEvent|touchEndEvent}</li>
* <li>{@link Controller.touchUpdateEvent|touchUpdateEvent}</li>
* <li>{@link Controller.wheelEvent|wheelEvent}</li>
* </ul>
*
* <p>Control Capturing</p>
* <ul>
* <li>{@link Controller.captureMouseEvents|captureMouseEvents}</li>
* <li>{@link Controller.captureTouchEvents|captureTouchEvents}</li>
* <li>{@link Controller.captureWheelEvents|captureWheelEvents}</li>
* <li>{@link Controller.releaseMouseEvents|releaseMouseEvents}</li>
* <li>{@link Controller.releaseTouchEvents|releaseTouchEvents}</li>
* <li>{@link Controller.releaseWheelEvents|releaseWheelEvents}</li>
* </ul>
*
* <p>Action Capturing</p>
* <ul>
* <li>{@link Controller.captureActionEvents|captureActionEvents}</li>
* <li>{@link Controller.captureEntityClickEvents|captureEntityClickEvents}</li>
* <li>{@link Controller.captureJoystick|captureJoystick}</li>
* <li>{@link Controller.captureKeyEvents|captureKeyEvents}</li>
* <li>{@link Controller.releaseActionEvents|releaseActionEvents}</li>
* <li>{@link Controller.releaseEntityClickEvents|releaseEntityClickEvents}</li>
* <li>{@link Controller.releaseJoystick|releaseJoystick}</li>
* <li>{@link Controller.releaseKeyEvents|releaseKeyEvents}</li>
* </ul>
*
* <p>Controller and Action Values</p>
* <ul>
* <li>{@link Controller.getValue|getValue}</li>
* <li>{@link Controller.getAxisValue|getAxisValue}</li>
* <li>{@link Controller.getPoseValue|getgetPoseValue}</li>
* <li>{@link Controller.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() {}
void emitKeyPressEvent(QKeyEvent* event);
void emitKeyReleaseEvent(QKeyEvent* event);
void emitMouseMoveEvent(QMouseEvent* event);
void emitMousePressEvent(QMouseEvent* event);
void emitMouseDoublePressEvent(QMouseEvent* event);
void emitMouseReleaseEvent(QMouseEvent* event);
void emitTouchBeginEvent(const TouchEvent& event);
void emitTouchEndEvent(const TouchEvent& event);
void emitTouchUpdateEvent(const TouchEvent& event);
void emitWheelEvent(QWheelEvent* event);
bool isKeyCaptured(QKeyEvent* event) const;
bool isKeyCaptured(const KeyEvent& event) const;
bool isJoystickCaptured(int joystickIndex) const;
bool areEntityClicksCaptured() const;
public slots:
/**jsdoc
* Disable default Interface actions for a particular key event.
* @function Controller.captureKeyEvents
* @param {KeyEvent} event - Details of the key event to be captured. The <code>key</code> property must be specified. The
* <code>text</code> property is ignored. The other properties default to <code>false</code>.
* @example <caption>Disable left and right strafing.</caption>
* var STRAFE_LEFT = { "key": 16777234, isShifted: true };
* var STRAFE_RIGHT = { "key": 16777236, isShifted: true };
*
* Controller.captureKeyEvents(STRAFE_LEFT);
* Controller.captureKeyEvents(STRAFE_RIGHT);
*
* Script.scriptEnding.connect(function () {
* Controller.releaseKeyEvents(STRAFE_LEFT);
* Controller.releaseKeyEvents(STRAFE_RIGHT);
* });
*/
virtual void captureKeyEvents(const KeyEvent& event);
/**jsdoc
* Re-enable default Interface actions for a particular key event that has been disabled using
* {@link Controller.captureKeyEvents|captureKeyEvents}.
* @function Controller.releaseKeyEvents
* @param {KeyEvent} event - Details of the key event to release from capture. The <code>key</code> property must be
* specified. The <code>text</code> property is ignored. The other properties default to <code>false</code>.
*/
virtual void releaseKeyEvents(const KeyEvent& event);
/**jsdoc
* Disable default Interface actions for a joystick.
* @function Controller.captureJoystick
* @param {number} joystickID - The integer ID of the joystick.
* @deprecated This function no longer has any effect.
*/
virtual void captureJoystick(int joystickIndex);
/**jsdoc
* Re-enable default Interface actions for a joystick that has been disabled using
* {@link Controller.captureJoystick|captureJoystick}.
* @function Controller.releaseJoystick
* @param {number} joystickID - The integer ID of the joystick.
* @deprecated This function no longer has any effect.
*/
virtual void releaseJoystick(int joystickIndex);
/**jsdoc
* Disable {@link Entities.mousePressOnEntity} and {@link Entities.mouseDoublePressOnEntity} events on entities.
* @function Controller.captureEntityClickEvents
* @example <caption>Disable entity click events for a short period.</caption>
* Entities.mousePressOnEntity.connect(function (entityID, event) {
* print("Clicked on entity: " + entityID);
* });
*
* Script.setTimeout(function () {
* Controller.captureEntityClickEvents();
* }, 5000);
*
* Script.setTimeout(function () {
* Controller.releaseEntityClickEvents();
* }, 10000);
*/
virtual void captureEntityClickEvents();
/**jsdoc
* Re-enable {@link Entities.mousePressOnEntity} and {@link Entities.mouseDoublePressOnEntity} events on entities that were
* disabled using {@link Controller.captureEntityClickEvents|captureEntityClickEvents}.
* @function Controller.releaseEntityClickEvents
*/
virtual void releaseEntityClickEvents();
/**jsdoc
* Get the dimensions of the Interface window's interior if in desktop mode or the HUD surface if in HMD mode.
* @function Controller.getViewportDimensions
* @returns {Vec2} The dimensions of the Interface window interior if in desktop mode or HUD surface if in HMD mode.
*/
virtual glm::vec2 getViewportDimensions() const;
/**jsdoc
* Get the recommended area to position UI on the HUD surface if in HMD mode or Interface's window interior if in desktop
* mode.
* @function Controller.getRecommendedHUDRect
* @returns {Rect} The recommended area in which to position UI.
*/
virtual QVariant getRecommendedHUDRect() const;
/**jsdoc
* Enables or disables the virtual game pad that is displayed on certain devices (e.g., Android).
* @function Controller.setVPadEnabled
* @param {boolean} enable - If <code>true</code> then the virtual game pad doesn't work, otherwise it does work provided
* that it is not hidden by {@link Controller.setVPadHidden|setVPadHidden}.
*
*/
virtual void setVPadEnabled(bool enable);
/**jsdoc
* Shows or hides the virtual game pad that is displayed on certain devices (e.g., Android).
* @function Controller.setVPadHidden
* @param {boolean} hidden - If <code>true</code> then the virtual game pad is hidden, otherwise it is shown.
*/
virtual void setVPadHidden(bool hidden); // Call it when a window should hide it
/**jsdoc
* Sets the amount of extra margin between the virtual game pad that is displayed on certain devices (e.g., Android) and
* the bottom of the display.
* @function Controller.setVPadExtraBottomMargin
* @param {number} margin - Integer number of pixels in the extra margin.
*/
virtual void setVPadExtraBottomMargin(int margin);
signals:
/**jsdoc
* Triggered when a keyboard key is pressed.
* @function Controller.keyPressEvent
* @param {KeyEvent} event - Details of the key press.
* @returns {Signal}
* @example <caption>Report the KeyEvent details for each key press.</caption>
* Controller.keyPressEvent.connect(function (event) {
* print(JSON.stringify(event));
* });
*/
void keyPressEvent(const KeyEvent& event);
/**jsdoc
* Triggered when a keyboard key is released from being pressed.
* @function Controller.keyReleaseEvent
* @param {KeyEvent} event - Details of the key release.
* @returns {Signal}
*/
void keyReleaseEvent(const KeyEvent& event);
/**jsdoc
* Triggered when the mouse moves.
* @function Controller.mouseMoveEvent
* @param {MouseEvent} event - Details of the mouse movement.
* @returns {Signal}
* @example <caption>Report the MouseEvent details for each mouse move.</caption>
* Controller.mouseMoveEvent.connect(function (event) {
* print(JSON.stringify(event));
* });
*/
void mouseMoveEvent(const MouseEvent& event);
/**jsdoc
* Triggered when a mouse button is pressed.
* @function Controller.mousePressEvent
* @param {MouseEvent} event - Details of the button press.
* @returns {Signal}
*/
void mousePressEvent(const MouseEvent& event);
/**jsdoc
* Triggered when a mouse button is double-pressed.
* @function Controller.mouseDoublePressEvent
* @param {MouseEvent} event - Details of the button double-press.
* @returns {Signal}
*/
void mouseDoublePressEvent(const MouseEvent& event);
/**jsdoc
* Triggered when a mouse button is released from being pressed.
* @function Controller.mouseReleaseEvent
* @param {MouseEvent} event - Details of the button release.
* @returns {Signal}
*/
void mouseReleaseEvent(const MouseEvent& event);
/**jsdoc
* Triggered when a touch event starts in the Interface window on a touch-enabled display or device.
* @function Controller.touchBeginEvent
* @param {TouchEvent} event - Details of the touch begin.
* @returns {Signal}
* @example <caption>Report the TouchEvent details when a touch event starts.</caption>
* Controller.touchBeginEvent.connect(function (event) {
* print(JSON.stringify(event));
* });
*/
void touchBeginEvent(const TouchEvent& event);
/**jsdoc
* Triggered when a touch event ends in the Interface window on a touch-enabled display or device.
* @function Controller.touchEndEvent
* @param {TouchEvent} event - Details of the touch end.
* @returns {Signal}
*/
void touchEndEvent(const TouchEvent& event);
/**jsdoc
* Triggered when a touch event update occurs in the Interface window on a touch-enabled display or device.
* @function Controller.touchUpdateEvent
* @param {TouchEvent} event - Details of the touch update.
* @returns {Signal}
*/
void touchUpdateEvent(const TouchEvent& event);
/**jsdoc
* Triggered when the mouse wheel is rotated.
* @function Controller.wheelEvent
* @param {WheelEvent} event - Details of the wheel movement.
* @returns {Signal}
* @example <caption>Report the WheelEvent details for each wheel rotation.</caption>
* Controller.wheelEvent.connect(function (event) {
* print(JSON.stringify(event));
* });
*/
void wheelEvent(const WheelEvent& event);
private:
QMultiMap<int,KeyEvent> _capturedKeys;
QSet<int> _capturedJoysticks;
bool _captureEntityClicks;
using InputKey = controller::InputController::Key;
};
const int NUMBER_OF_SPATIALCONTROLS_PER_PALM = 2; // the hand and the tip
const int NUMBER_OF_JOYSTICKS_PER_PALM = 1;
const int NUMBER_OF_TRIGGERS_PER_PALM = 1;
const int NUMBER_OF_BUTTONS_PER_PALM = 6;
const int PALM_SPATIALCONTROL = 0;
const int TIP_SPATIALCONTROL = 1;
#endif // hifi_ControllerScriptingInterface_h