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