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

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