Overte C++ Documentation
MappingBuilderProxy.h
1 //
2 // Created by Bradley Austin Davis 2015/10/09
3 // Copyright 2015 High Fidelity, Inc.
4 // Copyright 2023 Overte e.V.
5 //
6 // Distributed under the Apache License, Version 2.0.
7 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
8 // SPDX-License-Identifier: Apache-2.0
9 //
10 #pragma once
11 #ifndef hifi_Controllers_Impl_MappingBuilderProxy_h
12 #define hifi_Controllers_Impl_MappingBuilderProxy_h
13 
14 #include <QtCore/QObject>
15 #include <QtCore/QString>
16 
17 #include "Mapping.h"
18 #include "Endpoint.h"
19 
20 class QJSValue;
21 class QJsonValue;
22 class ScriptValue;
23 
24 namespace controller {
25 
26 class ScriptingInterface;
27 class UserInputMapper;
28 
29 /*@jsdoc
30  * <p>A {@link Controller} mapping object that can contain a set of routes that map:</p>
31  * <ul>
32  * <li>{@link Controller.Standard} outputs to {@link Controller.Actions} actions or script functions.</li>
33  * <li>{@link Controller.Hardware} outputs to {@link Controller.Standard} outputs, {@link Controller.Actions} actions, or
34  * script functions.</li>
35  * </ul>
36  *
37  * <p>Create by one of the following methods:</p>
38  * <ul>
39  * <li>Use {@link Controller.newMapping} to create the mapping object, add routes using {@link MappingObject#from|from} or
40  * {@link MappingObject#makeAxis|makeAxis}, and map the routes to actions or functions using {@link RouteObject}
41  * methods.</li>
42  * <li>Use {@link Controller.parseMapping} or {@link Controller.loadMapping} to load a {@link Controller.MappingJSON}.</li>
43  * </ul>
44  *
45  * <p>Enable the mapping using {@link MappingObject#enable|enable} or {@link Controller.enableMapping} for it to take
46  * effect.</p>
47  *
48  * <p>Mappings and their routes are applied according to the following rules:</p>
49  * <ul>
50  * <li>One read per output: after a controller output has been read, it can't be read again. Exception: You can use
51  * {@link RouteObject#peek} to read a value without marking that output as having been read.</li>
52  * <li>Existing mapping routes take precedence over new mapping routes: within a mapping, if a route is added for a control
53  * output that already has a route the new route is ignored.</li>
54  * <li>New mappings override previous mappings: each output is processed using the route in the most recently enabled
55  * mapping that contains that output.</li>
56  * </ul>
57  *
58  * @class MappingObject
59  * @hideconstructor
60  *
61  * @hifi-interface
62  * @hifi-client-entity
63  * @hifi-avatar
64  */
65 
66 /*@jsdoc
67  * A {@link MappingObject} can be specified in JSON format. A simple example is provided below. Full examples &mdash; the
68  * default mappings provided in Interface &mdash; can be found at
69  * <a href="https://github.com/highfidelity/hifi/tree/master/interface/resources/controllers">
70  * https://github.com/highfidelity/hifi/tree/master/interface/resources/controllers</a>.
71  * @typedef {object} Controller.MappingJSON
72  * @property {string} name - The name of the mapping.
73  * @property {Controller.MappingJSONRoute[]} channels - An array of routes.
74  * @example <caption>A simple mapping JSON that makes the right trigger move your avatar up after a dead zone.</caption>
75  * {
76  * "name": "org.overte.controllers.example.jsonMapping",
77  * "channels": [
78  * {
79  * "from": "Standard.RT",
80  * "filters": { "type": "deadZone", "min": 0.05 },
81  * "to": "Actions.TranslateY"
82  * }
83  * ]
84  * }
85  */
86 
87 /*@jsdoc
88  * A route in a {@link Controller.MappingJSON}.
89  * @typedef {object} Controller.MappingJSONRoute
90  * @property {string|Controller.MappingJSONAxis} from - The name of a {@link Controller.Hardware} property or an axis made from
91  * them. If a property name, the leading <code>"Controller.Hardware."</code> can be omitted.
92  * @property {boolean} [peek=false] - If <code>true</code>, then peeking is enabled per {@link RouteObject#peek}.
93  * @property {boolean} [debug=false] - If <code>true</code>, then debug is enabled per {@link RouteObject#debug}.
94  * @property {string|string[]} [when=[]] - One or more numeric {@link Controller.Hardware} property names which are evaluated
95  * as booleans and ANDed together. Prepend a property name with a <code>!</code> to do a logical NOT. The leading
96  * <code>"Controller.Hardware."</code> can be omitted from the property names.
97  * @property {Controller.MappingJSONFilter|Controller.MappingJSONFilter[]} [filters=[]] - One or more filters in the route.
98  * @property {string} to - The name of a {@link Controller.Actions} or {@link Controller.Standard} property. The leading
99  * <code>"Controller."</code> can be omitted.
100  */
101 
102 /*@jsdoc
103  * An axis pair in a {@link Controller.MappingJSONRoute}.
104  * @typedef {object} Controller.MappingJSONAxis
105  * @property {string[][]} makeAxis - A two-member array of single-member arrays of {@link Controller.Hardware} property names.
106  * The leading <code>"Controller.Hardware."</code> can be omitted from the property names.
107  * @example <caption>An axis using the keyboard's left and right keys.</caption>
108  * { "makeAxis" : [
109  * ["Keyboard.Left"],
110  * ["Keyboard.Right"]
111  * ]
112  * }
113  */
114 
115 /*@jsdoc
116  * A filter in a {@link Controller.MappingJSONRoute}.
117  * @typedef {object} Controller.MappingJSONFilter
118  * @property {string} type - The name of the filter, being the name of the one of the {@link RouteObject}'s filter methods.
119  * @property {string} [?] - If the filter method has a first parameter, the property name is the name of that parameter and the
120  * property value is the value to use.
121  * @property {string} [?] - If the filter method has a second parameter, the property name is the name of that parameter and
122  * the property value is the value to use.
123  * @example <caption>A hysteresis filter.</caption>
124  * {
125  * "type": "hysteresis",
126  * "min": 0.85,
127  * "max": 0.9
128  * }
129  */
130 
131 // TODO migrate functionality to a MappingBuilder class and make the proxy defer to that
132 // (for easier use in both C++ and JS)
133 class MappingBuilderProxy : public QObject {
134  Q_OBJECT
135 public:
136  MappingBuilderProxy(UserInputMapper& parent, Mapping::Pointer mapping)
137  : _parent(parent), _mapping(mapping) { }
138 
139  /*@jsdoc
140  * Creates a new {@link RouteObject} from a controller output, ready to be mapped to a standard control, action, or
141  * function.
142  * <p>This is a QML-specific version of {@link MappingObject#from|from}: use this version in QML files.</p>
143  * @function MappingObject#fromQml
144  * @param {Controller.Standard|Controller.Hardware|function} source - The controller output or function that is the source
145  * of the route data. If a function, it must return a number or a {@link Pose} value as the route data.
146  * @returns {RouteObject} A route ready for mapping to an action or function using {@link RouteObject} methods.
147  */
148  Q_INVOKABLE QObject* fromQml(const QJSValue& source);
149 
150  /*@jsdoc
151  * Creates a new {@link RouteObject} from two numeric {@link Controller.Hardware} outputs, one applied in the negative
152  * direction and the other in the positive direction, ready to be mapped to a standard control, action, or function.
153  * <p>This is a QML-specific version of {@link MappingObject#makeAxis|makeAxis}: use this version in QML files.</p>
154  * @function MappingObject#makeAxisQml
155  * @param {Controller.Hardware} source1 - The first, negative-direction controller output.
156  * @param {Controller.Hardware} source2 - The second, positive-direction controller output.
157  * @returns {RouteObject} A route ready for mapping to an action or function using {@link RouteObject} methods. The data
158  * value passed to the route is the combined value of <code>source2 - source1</code>.
159  */
160  Q_INVOKABLE QObject* makeAxisQml(const QJSValue& source1, const QJSValue& source2);
161 
162  /*@jsdoc
163  * Creates a new {@link RouteObject} from a controller output, ready to be mapped to a standard control, action, or
164  * function.
165  * @function MappingObject#from
166  * @param {Controller.Standard|Controller.Hardware|function} source - The controller output or function that is the source
167  * of the route data. If a function, it must return a number or a {@link Pose} value as the route data.
168  * @returns {RouteObject} A route ready for mapping to an action or function using {@link RouteObject} methods.
169  */
170  Q_INVOKABLE QObject* from(const ScriptValue& source);
171 
172  /*@jsdoc
173  * Creates a new {@link RouteObject} from two numeric {@link Controller.Hardware} outputs, one applied in the negative
174  * direction and the other in the positive direction, ready to be mapped to a standard control, action, or function.
175  * @function MappingObject#makeAxis
176  * @param {Controller.Hardware} source1 - The first, negative-direction controller output.
177  * @param {Controller.Hardware} source2 - The second, positive-direction controller output.
178  * @returns {RouteObject} A route ready for mapping to an action or function using {@link RouteObject} methods. The data
179  * value passed to the route is the combined value of <code>source2 - source1</code>.
180  * @example <caption>Make the Oculus Touch triggers move your avatar up and down.</caption>
181  * var MAPPING_NAME = "org.overte.controllers.example.newMapping";
182  * var mapping = Controller.newMapping(MAPPING_NAME);
183  * mapping
184  * .makeAxis(Controller.Hardware.OculusTouch.LT, Controller.Hardware.OculusTouch.RT)
185  * .to(Controller.Actions.Up);
186  * Controller.enableMapping(MAPPING_NAME);
187  *
188  * Script.scriptEnding.connect(function () {
189  * Controller.disableMapping(MAPPING_NAME);
190  * });
191  */
192  Q_INVOKABLE QObject* makeAxis(const ScriptValue& source1, const ScriptValue& source2);
193 
194  /*@jsdoc
195  * Enables or disables the mapping. When enabled, the routes in the mapping take effect.
196  * <p>Synonymous with {@link Controller.enableMapping}.</p>
197  * @function MappingObject#enable
198  * @param {boolean} enable=true - If <code>true</code> then the mapping is enabled, otherwise it is disabled.
199  * @returns {MappingObject} The mapping object, so that further routes can be added.
200  */
201  Q_INVOKABLE QObject* enable(bool enable = true);
202 
203  /*@jsdoc
204  * Disables the mapping. When disabled, the routes in the mapping have no effect.
205  * <p>Synonymous with {@link Controller.disableMapping}.</p>
206  * @function MappingObject#disable
207  * @returns {MappingObject} The mapping object, so that further routes can be added.
208  */
209  Q_INVOKABLE QObject* disable() { return enable(false); }
210 
211 protected:
212  QObject* from(const Endpoint::Pointer& source);
213 
214  friend class RouteBuilderProxy;
215  UserInputMapper& _parent;
216  Mapping::Pointer _mapping;
217 
218 
219  void parseRoute(const QJsonValue& json);
220 
221 };
222 
223 }
224 
225 #endif
[ScriptInterface] Provides an engine-independent interface for QScriptValue
Definition: ScriptValue.h:40