1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qquickpointerdevicehandler_p_p.h"
5#include <private/qquickitem_p.h>
6#include <QMouseEvent>
7#include <QDebug>
8
9QT_BEGIN_NAMESPACE
10
11/*!
12 \qmltype PointerDeviceHandler
13 \qmlabstract
14 \since 5.10
15 \preliminary
16 \instantiates QQuickPointerDeviceHandler
17 \inherits PointerHandler
18 \inqmlmodule QtQuick
19 \brief Abstract handler for pointer events with device-specific constraints.
20
21 An intermediate class (not registered as a QML type) for handlers which
22 allow filtering based on device type, pointer type, or keyboard modifiers.
23*/
24QQuickPointerDeviceHandler::QQuickPointerDeviceHandler(QQuickItem *parent)
25 : QQuickPointerHandler(*(new QQuickPointerDeviceHandlerPrivate), parent)
26{
27}
28
29QQuickPointerDeviceHandler::QQuickPointerDeviceHandler(QQuickPointerDeviceHandlerPrivate &dd, QQuickItem *parent)
30 : QQuickPointerHandler(dd, parent)
31{
32}
33
34QInputDevice::DeviceTypes QQuickPointerDeviceHandler::acceptedDevices() const
35{
36 Q_D(const QQuickPointerDeviceHandler);
37 return d->acceptedDevices;
38}
39
40QPointingDevice::PointerTypes QQuickPointerDeviceHandler::acceptedPointerTypes() const
41{
42 Q_D(const QQuickPointerDeviceHandler);
43 return d->acceptedPointerTypes;
44}
45
46/*!
47 \qmlproperty flags QtQuick::PointerDeviceHandler::acceptedButtons
48
49 The mouse buttons which can activate this Pointer Handler.
50
51 By default, this property is set to \l {QtQuick::MouseEvent::button} {Qt.LeftButton}.
52 It can be set to an OR combination of mouse buttons, and will ignore events
53 from other buttons.
54
55 For example, a control could be made to respond to left and right clicks
56 in different ways, with two handlers:
57
58 \qml
59 Item {
60 TapHandler {
61 onTapped: console.log("left clicked")
62 }
63 TapHandler {
64 acceptedButtons: Qt.RightButton
65 onTapped: console.log("right clicked")
66 }
67 }
68 \endqml
69
70 \note Tapping on a touchscreen or tapping the stylus on a graphics tablet
71 emulates clicking the left mouse button. This behavior can be altered via
72 \l {PointerDeviceHandler::acceptedDevices}{acceptedDevices} or
73 \l {PointerDeviceHandler::acceptedPointerTypes}{acceptedPointerTypes}.
74*/
75Qt::MouseButtons QQuickPointerDeviceHandler::acceptedButtons() const
76{
77 Q_D(const QQuickPointerDeviceHandler);
78 return d->acceptedButtons;
79}
80
81void QQuickPointerDeviceHandler::setAcceptedButtons(Qt::MouseButtons buttons)
82{
83 Q_D(QQuickPointerDeviceHandler);
84 if (d->acceptedButtons == buttons)
85 return;
86
87 d->acceptedButtons = buttons;
88 emit acceptedButtonsChanged();
89}
90
91Qt::KeyboardModifiers QQuickPointerDeviceHandler::acceptedModifiers() const
92{
93 Q_D(const QQuickPointerDeviceHandler);
94 return d->acceptedModifiers;
95}
96
97/*!
98 \qmlproperty flags PointerDeviceHandler::acceptedDevices
99
100 The types of pointing devices that can activate this Pointer Handler.
101
102 By default, this property is set to
103 \l{QInputDevice::DeviceType}{PointerDevice.AllDevices}.
104 If you set it to an OR combination of device types, it will ignore events
105 from non-matching devices.
106
107 For example, a control could be made to respond to mouse and stylus clicks
108 in one way, and touchscreen taps in another way, with two handlers:
109
110 \qml
111 Item {
112 TapHandler {
113 acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus
114 onTapped: console.log("clicked")
115 }
116 TapHandler {
117 acceptedDevices: PointerDevice.TouchScreen
118 onTapped: console.log("tapped")
119 }
120 }
121 \endqml
122*/
123void QQuickPointerDeviceHandler::setAcceptedDevices(QPointingDevice::DeviceTypes acceptedDevices)
124{
125 Q_D(QQuickPointerDeviceHandler);
126 if (d->acceptedDevices == acceptedDevices)
127 return;
128
129 d->acceptedDevices = acceptedDevices;
130 emit acceptedDevicesChanged();
131}
132
133/*!
134 \qmlproperty flags PointerDeviceHandler::acceptedPointerTypes
135
136 The types of pointing instruments (finger, stylus, eraser, etc.)
137 that can activate this Pointer Handler.
138
139 By default, this property is set to
140 \l {QPointingDevice::PointerType} {PointerDevice.AllPointerTypes}.
141 If you set it to an OR combination of device types, it will ignore events
142 from non-matching \l {PointerDevice}{devices}.
143
144 For example, a control could be made to respond to mouse, touch, and stylus clicks
145 in some way, but delete itself if tapped with an eraser tool on a graphics tablet,
146 with two handlers:
147
148 \qml
149 Rectangle {
150 id: rect
151 TapHandler {
152 acceptedPointerTypes: PointerDevice.Generic | PointerDevice.Finger | PointerDevice.Pen
153 onTapped: console.log("clicked")
154 }
155 TapHandler {
156 acceptedPointerTypes: PointerDevice.Eraser
157 onTapped: rect.destroy()
158 }
159 }
160 \endqml
161*/
162void QQuickPointerDeviceHandler::setAcceptedPointerTypes(QPointingDevice::PointerTypes acceptedPointerTypes)
163{
164 Q_D(QQuickPointerDeviceHandler);
165 if (d->acceptedPointerTypes == acceptedPointerTypes)
166 return;
167
168 d->acceptedPointerTypes = acceptedPointerTypes;
169 emit acceptedPointerTypesChanged();
170}
171
172/*!
173 \qmlproperty flags PointerDeviceHandler::acceptedModifiers
174
175 If this property is set, it will require the given keyboard modifiers to
176 be pressed in order to react to pointer events, and otherwise ignore them.
177
178 If this property is set to \c Qt.KeyboardModifierMask (the default value),
179 then the PointerHandler ignores the modifier keys.
180
181 For example, an \l [QML] Item could have two handlers of the same type,
182 one of which is enabled only if the required keyboard modifiers are
183 pressed:
184
185 \qml
186 Item {
187 TapHandler {
188 acceptedModifiers: Qt.ControlModifier
189 onTapped: console.log("control-tapped")
190 }
191 TapHandler {
192 acceptedModifiers: Qt.NoModifier
193 onTapped: console.log("tapped")
194 }
195 }
196 \endqml
197
198 If you set \c acceptedModifiers to an OR combination of modifier keys,
199 it means \e all of those modifiers must be pressed to activate the handler:
200
201 \qml
202 Item {
203 TapHandler {
204 acceptedModifiers: Qt.ControlModifier | Qt.AltModifier | Qt.ShiftModifier
205 onTapped: console.log("control-alt-shift-tapped")
206 }
207 }
208 \endqml
209
210 The available modifiers are as follows:
211
212 \value NoModifier No modifier key is allowed.
213 \value ShiftModifier A Shift key on the keyboard must be pressed.
214 \value ControlModifier A Ctrl key on the keyboard must be pressed.
215 \value AltModifier An Alt key on the keyboard must be pressed.
216 \value MetaModifier A Meta key on the keyboard must be pressed.
217 \value KeypadModifier A keypad button must be pressed.
218 \value GroupSwitchModifier X11 only (unless activated on Windows by a command line argument).
219 A Mode_switch key on the keyboard must be pressed.
220 \value KeyboardModifierMask The handler does not care which modifiers are pressed.
221
222 If you need even more complex behavior than can be achieved with
223 combinations of multiple handlers with multiple modifier flags, you can
224 check the modifiers in JavaScript code:
225
226 \qml
227 Item {
228 TapHandler {
229 onTapped:
230 switch (point.modifiers) {
231 case Qt.ControlModifier | Qt.AltModifier:
232 console.log("CTRL+ALT");
233 break;
234 case Qt.ControlModifier | Qt.AltModifier | Qt.MetaModifier:
235 console.log("CTRL+META+ALT");
236 break;
237 default:
238 console.log("other modifiers", point.modifiers);
239 break;
240 }
241 }
242 }
243 \endqml
244
245 \sa Qt::KeyboardModifier
246*/
247void QQuickPointerDeviceHandler::setAcceptedModifiers(Qt::KeyboardModifiers acceptedModifiers)
248{
249 Q_D(QQuickPointerDeviceHandler);
250 if (d->acceptedModifiers == acceptedModifiers)
251 return;
252
253 d->acceptedModifiers = acceptedModifiers;
254 emit acceptedModifiersChanged();
255}
256
257bool QQuickPointerDeviceHandler::wantsPointerEvent(QPointerEvent *event)
258{
259 Q_D(QQuickPointerDeviceHandler);
260 if (!QQuickPointerHandler::wantsPointerEvent(event))
261 return false;
262 qCDebug(lcPointerHandlerDispatch) << objectName()
263 << "checking device type" << d->acceptedDevices
264 << "pointer type" << d->acceptedPointerTypes
265 << "modifiers" << d->acceptedModifiers;
266 if (!d->acceptedDevices.testFlag(flag: event->device()->type()))
267 return false;
268 if (!d->acceptedPointerTypes.testFlag(flag: event->pointingDevice()->pointerType()))
269 return false;
270 if (d->acceptedModifiers != Qt::KeyboardModifierMask && event->modifiers() != d->acceptedModifiers)
271 return false;
272 // Some handlers (HoverHandler, PinchHandler) set acceptedButtons to Qt::NoButton to indicate that button state is irrelevant.
273 if (event->pointingDevice()->type() != QPointingDevice::DeviceType::TouchScreen &&
274 acceptedButtons() != Qt::NoButton && event->type() != QEvent::Wheel &&
275 (static_cast<QSinglePointEvent *>(event)->buttons() & acceptedButtons()) == 0 &&
276 (static_cast<QSinglePointEvent *>(event)->button() & acceptedButtons()) == 0)
277 return false;
278 return true;
279}
280
281QT_END_NAMESPACE
282
283#include "moc_qquickpointerdevicehandler_p.cpp"
284

source code of qtdeclarative/src/quick/handlers/qquickpointerdevicehandler.cpp