Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquick3dxractionmapper.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5
8
10
12{
13}
14
15static inline quint32 actionIntKey(const QQuick3DXrInputAction::Action id, const QQuick3DXrInputAction::Controller hand)
16{
17 return quint16(id) | (quint32(hand) << 16);
18}
19
20static inline QString actionStringKey(const QString &name, const QQuick3DXrInputAction::Controller hand)
21{
22 return QString::number(hand) + name;
23}
24
26{
27 static QQuick3DXrActionMapper instance;
28 return &instance;
29}
30
31void QQuick3DXrActionMapper::handleInput(QQuick3DXrInputAction::Action id, QQuick3DXrInputAction::Controller hand, const char *shortName, float value)
32{
33 auto *that = instance();
34 auto set = [](auto action, auto value) {
35 action->setValue(value);
36 // TODO: distinguish between bool and float values
37 action->setPressed(value > 0.9);
38 };
39
40 const QLatin1StringView name(shortName);
41 // emit that->inputValueChange(id, name, value); // TODO: emit a signal from public class
42
43 QList<QQuick3DXrInputAction *> actions;
44 if (id == QQuick3DXrInputAction::CustomAction) {
45 actions = that->m_customActions.values(actionStringKey(name, hand));
46 } else {
47 actions = that->m_actions.values(actionIntKey(id, hand));
48 }
49
50 for (const auto &action : std::as_const(actions))
51 if (action->enabled())
52 set(action, value);
53}
54
55QList<QPointer<QQuick3DXrHapticFeedback>> QQuick3DXrActionMapper::getHapticEffects(QQuick3DXrInputAction::Controller hand)
56{
57 auto *that = instance();
58 return that->m_hapticData[hand].m_hapticEffects;
59}
60
61// Note: it is the responsibility of the caller to call removeAction() before the action is destroyed or actionId/actionName is changed
63{
64 auto *that = instance();
65
66 const auto &idList = action->actionId();
67 const auto hand = action->hand();
68
69 if (idList.isEmpty()) {
70 that->m_customActions.insert(actionStringKey(action->actionName(), hand), action);
71 } else {
72 for (const auto &id : idList) {
73 if (id != QQuick3DXrInputAction::CustomAction)
74 that->m_actions.insert(actionIntKey(id, hand), action);
75 }
76 }
77}
78
79void QQuick3DXrActionMapper::registerHapticEffect(QPointer<QQuick3DXrHapticFeedback> action)
80{
81 auto *that = instance();
82
83 that->m_hapticData[size_t(action->controller())].m_hapticEffects.append(action);
84}
85
87{
88 auto *that = instance();
89
90 const auto idList = action->actionId();
91 const auto hand = action->hand();
92 if (idList.isEmpty()) {
93 that->m_customActions.remove(action->actionName(), action);
94 } else {
95 for (const auto &id : idList) {
96 if (id != QQuick3DXrInputAction::CustomAction)
97 that->m_actions.remove(actionIntKey(id, hand));
98 }
99 }
100}
101
103{
104 auto *that = instance();
105 QList<QPointer<QQuick3DXrHapticFeedback>> list = that->m_hapticData[size_t(action->controller())].m_hapticEffects;
106 list.removeAt(list.indexOf(action));
107}
108
109/*!
110 \qmltype XrInputAction
111 \inherits QtObject
112 \inqmlmodule QtQuick3D.Xr
113 \brief Represents an action from an input controller.
114
115 Actions can be boolean, such as a button press, or analog, such as a joystick axis.
116
117 Use the \l pressed property or the \l triggered signal to react to a boolean action. An analog action will set the \l value property.
118
119 \note For convenience, an analog property will also set the \c pressed property and emit the \c triggered signal,
120 while a boolean property will set \c value to 1.0 when pressed.
121
122 The following shows how to react to either the right hand grip being pressed or to a right hand pinch gesture from hand tracking:
123
124 \qml
125 XrInputAction {
126 hand: XrInputAction.RightHand
127 actionId: [XrInputAction.SqueezePressed, XrInputAction.SqueezeValue, XrInputAction.IndexFingerPinch]
128 onTriggered: console.log("Do action here.")
129 }
130 \endqml
131
132 The reason for specifying both \c SqueezePressed and \c SqueezeValue is that some controllers have an analog grip button,
133 and some controllers just have an on/off grip switch.
134 */
135
136/*!
137 \qmlsignal XrInputAction::triggered()
138
139 This signal is emitted when a boolean action is activated. This happens at the same time as the \l pressed property is set to \c true.
140 */
141
142void QQuick3DXrInputAction::setValue(float newValue)
143{
144 if (qFuzzyCompare(m_value, newValue))
145 return;
146 m_value = newValue;
147 emit valueChanged();
148}
149
150/*!
151 \qmlproperty bool XrInputAction::pressed
152 \brief Indicates whether the input action is currently pressed.
153
154 Use this property to check if the input action (for example, a button)
155 is currently pressed.
156 */
157
159{
160 return m_pressed;
161}
162
163void QQuick3DXrInputAction::setPressed(bool newPressed)
164{
165 if (m_pressed == newPressed)
166 return;
167 m_pressed = newPressed;
168 emit pressedChanged();
169 if (newPressed)
170 emit triggered();
171}
172
173/*!
174 \qmlproperty string XrInputAction::actionName
175 \brief The name of the input action.
176
177 Use this property to specify the name of the custom input action you want to react to. This property does not have an effect if \l actionId is set.
178 */
179
181{
182 return m_actionName;
183}
184
185void QQuick3DXrInputAction::setActionName(const QString &newActionName)
186{
187 if (m_actionName == newActionName)
188 return;
189 const bool needsRemap = m_actionIds.isEmpty() && m_componentComplete;
190 if (needsRemap)
192 m_actionName = newActionName;
193 if (needsRemap)
195 emit actionNameChanged();
196}
197
198QQuick3DXrInputAction::QQuick3DXrInputAction(QObject *parent)
199 : QObject(parent)
200{
201}
202
207
208/*!
209 \qmlproperty real XrInputAction::value
210 \brief The analog value of the input action.
211
212 For analog inputs, such as a thumbstick position, this property holds
213 the value of the input (usually in the range [0, 1]).
214 */
215
217{
218 return m_value;
219}
220
224
226{
228 m_componentComplete = true;
229}
230
231/*!
232 \qmlproperty List<enumeration> XrInputAction::actionId
233 \brief Specifies the action(s) to react to
234
235 Holds a List of IDs that can be of the following values:
236
237 \value XrInputAction.Button1Pressed Button 1 is pressed. \e Boolean.
238 \value XrInputAction.Button1Touched Button 1 is touched. \e Boolean.
239 \value XrInputAction.Button2Pressed Button 2 is pressed. \e Boolean.
240 \value XrInputAction.Button2Touched Button 2 is touched. \e Boolean.
241 \value XrInputAction.ButtonMenuPressed The menu button is pressed. \e Boolean.
242 \value XrInputAction.ButtonMenuTouched The menu button is touched. \e Boolean.
243 \value XrInputAction.ButtonSystemPressed The system button is pressed. \e Boolean.
244 \value XrInputAction.ButtonSystemTouched The system button is touched. \e Boolean.
245 \value XrInputAction.SqueezeValue How far the grip button is pressed. \e Analog.
246 \value XrInputAction.SqueezeForce The force applied to the grip button. \e Analog.
247 \value XrInputAction.SqueezePressed The grip button is pressed. \e Boolean.
248 \value XrInputAction.TriggerValue How far the trigger button is pressed. \e Analog.
249 \value XrInputAction.TriggerPressed The trigger is pressed. \e Boolean.
250 \value XrInputAction.TriggerTouched The trigger is touched. \e Boolean.
251 \value XrInputAction.ThumbstickX The X-axis value of the thumbstick. \e Analog.
252 \value XrInputAction.ThumbstickY The Y-axis value of the thumbstick. \e Analog.
253 \value XrInputAction.ThumbstickPressed The thumbstick is pressed. \e Boolean.
254 \value XrInputAction.ThumbstickTouched The thumbstick is touched. \e Boolean.
255 \value XrInputAction.ThumbrestTouched The thumbrest is touched. \e Boolean.
256 \value XrInputAction.TrackpadX The X-axis position on the trackpad. \e Analog.
257 \value XrInputAction.TrackpadY The Y-axis position on the trackpad. \e Analog.
258 \value XrInputAction.TrackpadForce The force applied on the trackpad. \e Analog.
259 \value XrInputAction.TrackpadTouched The trackpad is touched. \e Boolean.
260 \value XrInputAction.TrackpadPressed The trackpad is pressed. \e Boolean.
261 \value XrInputAction.IndexFingerPinch Thumb to index finger pinch gesture. \e Boolean.
262 \value XrInputAction.MiddleFingerPinch Thumb to middle finger pinch gesture. \e Boolean.
263 \value XrInputAction.RingFingerPinch Thumb to ring finger pinch gesture. \e Boolean.
264 \value XrInputAction.LittleFingerPinch Thumb to little finger pinch gesture. \e Boolean.
265 \value XrInputAction.HandTrackingMenuPress Hand tracking menu gesture. \e Boolean.
266 */
267
269{
270 return m_actionIds;
271}
272
273void QQuick3DXrInputAction::setActionId(const QList<Action> &newActionId)
274{
275 if (m_actionIds == newActionId)
276 return;
277
278 if (m_componentComplete)
280
281 m_actionIds = newActionId;
282
283 if (m_componentComplete)
285
286 emit actionIdChanged();
287}
288
289/*!
290 \qmlproperty enumeration QtQuick3D.Xr::XrInputAction::hand
291 \deprecated [6.10] This property is deprecated, use \l{XrInputAction::}{controller} instead.
292 \brief The Controller that this input action will apply to.
293
294 Specifies the hand ro react to.
295
296 It can be one of:
297
298 \value XrInputAction.LeftHand
299 \value XrInputAction.RightHand
300 \value XrInputAction.Unknown
301 */
302
304{
305 return m_controller;
306}
307
308void QQuick3DXrInputAction::setHand(Controller newHand)
309{
310 setController(newHand);
311}
312
313/*!
314 \qmlproperty enumeration QtQuick3D.Xr::XrInputAction::controller
315 \brief The Controller that this input action will apply to.
316 \since 6.10
317
318 Specifies the controller to react to.
319
320 It can be one of:
321
322 \value XrInputAction.LeftController
323 \value XrInputAction.RightController
324 \value XrInputAction.Unknown
325 \value XrInputAction.LeftHand (alias for \c LeftController)
326 \value XrInputAction.RightHand (alias for \c RightController)
327
328 \note In Qt 6.9, this property was called "hand"
329 */
330
332{
333 return m_controller;
334}
335
336void QQuick3DXrInputAction::setController(Controller newController)
337{
338 if (m_controller == newController)
339 return;
340 m_controller = newController;
341 emit controllerChanged();
342 emit handChanged();
343}
344
345/*!
346 \qmlproperty bool XrInputAction::enabled
347 \since 6.9
348
349 This property determines whether the input action will react to events.
350 \default true
351*/
352
354{
355 return m_enabled;
356}
357
358void QQuick3DXrInputAction::setEnabled(bool newEnabled)
359{
360 if (m_enabled == newEnabled)
361 return;
362 m_enabled = newEnabled;
363 emit enabledChanged();
364
365}
366
367/*!
368 \qmltype XrHapticFeedback
369 \inherits QtObject
370 \inqmlmodule QtQuick3D.Xr
371 \brief Controls haptic feedback for an XR controller.
372 \since 6.9
373
374 Haptic feedback typically involves applying a short vibration to a controller to provide a tactile
375 experience when an event happens. This can give the illusion of touching a button, for example.
376
377 There are two ways of using XrHapticFeedback:
378
379 \list
380 \li Imperatively, by calling the \l start function
381 \li Declaratively, by specifying \l trigger and \l condition
382 \endlist
383
384 The following code makes the right-hand controller vibrate when the value of the \c someObject.hit property
385 changes from \c false to \c true:
386
387 \qml
388 XrHapticFeedback {
389 controller: XrHapticFeedback.RightController
390 condition: XrHapticFeedback.RisingEdge
391 trigger: someObject.hit
392 hapticEffect: XrSimpleHapticEffect {
393 amplitude: 0.5
394 duration: 300
395 frequency: 3000
396 }
397 }
398 \endqml
399 */
400
401QQuick3DXrHapticFeedback::QQuick3DXrHapticFeedback(QObject *parent)
402 : QObject(parent)
403{
404}
405
410
414
416{
417 QQuick3DXrActionMapper::registerHapticEffect(this);
418 m_componentComplete = true;
419}
420
421/*!
422 \qmlproperty enumeration QtQuick3D.Xr::XrHapticFeedback::controller
423 \brief The Controller that this haptic feedback will apply to.
424
425 It can be one of:
426
427 \value XrHapticFeedback.LeftController
428 \value XrHapticFeedback.RightController
429 \value XrHapticFeedback.UnknownController
430 */
431
433{
434 return m_controller;
435}
436
437void QQuick3DXrHapticFeedback::setController(Controller newController)
438{
439 if (m_controller == newController)
440 return;
441 m_controller = newController;
442 emit controllerChanged();
443}
444
445/*!
446 \qmlproperty bool XrHapticFeedback::trigger
447 \brief Trigger for the haptic feedback
448
449 This property defines what the haptic effect will react to.
450 The \l condition property determines how the trigger is interpreted.
451
452 \sa start condition
453 */
455{
456 return m_trigger;
457}
458
460{
461 if (m_trigger == newTrigger)
462 return;
463
464 switch (m_condition)
465 {
466 case Condition::RisingEdge:
467 if (newTrigger)
468 start();
469 break;
470 case Condition::TrailingEdge:
471 if (!newTrigger)
472 start();
473 break;
474 }
475 m_trigger = newTrigger;
476 emit triggerChanged();
477}
478
479/*!
480 \qmlproperty XrHapticEffect XrHapticFeedback::hapticEffect
481
482 This property describes the effect that is applied to the controller when the haptic feedback is triggered.
483 */
484
486{
487 return m_hapticEffect;
488}
489
491{
492 if (m_hapticEffect == newHapticEffect)
493 return;
494 m_hapticEffect = newHapticEffect;
495 emit hapticEffectChanged();
496}
497
498/*!
499 \qmlproperty enumeration QtQuick3D.Xr::XrHapticFeedback::condition
500 \brief The condition for triggering this haptic feedback.
501 \default XrHapticFeedback.RisingEdge
502
503 This property specifies how the \l trigger property is interpreted
504
505 It can be one of:
506
507 \value XrHapticFeedback.RisingEdge The haptic effect starts when \l trigger changes from \c false to \c true.
508 \value XrHapticFeedback.TrailingEdge The haptic effect starts when \l trigger changes from \c true to \c false.
509 */
511{
512 return m_condition;
513}
514
515void QQuick3DXrHapticFeedback::setCondition(enum Condition newCondition)
516{
517 if (m_condition == newCondition)
518 return;
519 m_condition = newCondition;
520 emit conditionChanged();
521}
522
523/*!
524 \qmlmethod void XrHapticFeedback::start
525 \brief Starts the haptic feedback effect
526 */
528{
529 m_pending = true;
530}
531
532/*!
533 \qmlmethod void XrHapticFeedback::stop
534 \brief Stops the haptic feedback effect
535 */
537{
538 m_pending = false;
539}
540
542{
543 bool t = m_pending;
544 m_pending = false;
545 return t;
546}
547
548QT_END_NAMESPACE
QObject * parent
Definition qobject.h:73
\inmodule QtCore
Definition qobject.h:105
static void registerAction(QQuick3DXrInputAction *action)
static void removeHapticEffect(QQuick3DXrHapticFeedback *action)
static void removeAction(QQuick3DXrInputAction *action)
void classBegin() override
Invoked after class creation, but before any properties have been set.
void setCondition(enum Condition newCondition)
void setController(Controller newController)
enum Condition condition() const
\qmlproperty enumeration QtQuick3D.Xr::XrHapticFeedback::condition
void stop()
\qmlmethod void XrHapticFeedback::stop
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
void setHapticEffect(QQuick3DXrAbstractHapticEffect *newHapticEffect)
QQuick3DXrAbstractHapticEffect * hapticEffect() const
\qmlproperty XrHapticEffect XrHapticFeedback::hapticEffect
Controller controller() const
\qmlproperty enumeration QtQuick3D.Xr::XrHapticFeedback::controller
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
bool pressed() const
\qmlproperty bool XrInputAction::pressed
void classBegin() override
Invoked after class creation, but before any properties have been set.
Controller controller() const
\qmlproperty enumeration QtQuick3D.Xr::XrInputAction::controller
void setPressed(bool newPressed)
QList< Action > actionId() const
\qmlproperty List<enumeration> XrInputAction::actionId
void setActionId(const QList< Action > &newActionId)
bool enabled() const
\qmlproperty bool XrInputAction::enabled
void setActionName(const QString &newActionName)
QString actionName() const
\qmlproperty string XrInputAction::actionName
float value() const
\qmlproperty real XrInputAction::value
void setEnabled(bool newEnabled)
void setController(Controller newController)
Controller hand() const
\qmlproperty enumeration QtQuick3D.Xr::XrInputAction::hand
void setValue(float newValue)
\qmltype XrInputAction \inherits QtObject \inqmlmodule QtQuick3D.Xr
void setHand(Controller newHand)
Combined button and popup list for selecting options.
static quint32 actionIntKey(const QQuick3DXrInputAction::Action id, const QQuick3DXrInputAction::Controller hand)
static QString actionStringKey(const QString &name, const QQuick3DXrInputAction::Controller hand)