<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
On 2020-05-26 16:07, Shawn Rutledge wrote:<br>
<blockquote type="cite"
cite="mid:4067B6F7-A562-41FC-A047-CB862BDCA80A@qt.io">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<div class="">When I started working with Qt Quick in 2011, it
wasn't too</div>
<div class="">long before I began to notice that our vaunted
support for multitouch (which</div>
<div class="">still felt like an innovative new feature at the
time, even though it had</div>
<div class="">already been 5 years since the introduction of the
iPhone) was quite flawed.</div>
<div class="">Everyone was using MouseArea and Flickable, and
those were not very good</div>
<div class="">companions for the only components that actually
supported multitouch:</div>
<div class="">MultiPointTouchArea and PinchArea. At some point
someone had made the decision</div>
<div class="">that touch is enough like mouse, that it would
simplify things if we just</div>
<div class="">convert touch events to synthetic mouse events and
reuse the same logic for</div>
<div class="">both. Maybe that was decided before multi-touch
screens were invented; it</div>
<div class="">would have been ok for the resistive ones from the
QTopia days, for example.</div>
<div class="">But I thought that Qt Quick was newer than that, so
it was an immediate</div>
<div class="">facepalm moment when I realized that mistake was
perpetuated there. Finding</div>
<div class="">ways to work around it has dominated a lot of my
time working on Qt Quick ever</div>
<div class="">since. But Qt 5 has had such a long lifespan, and
it wasn't possible to fix it</div>
<div class="">in a fundamental way, without increasing complexity
in ways that you might have</div>
<div class="">noticed.</div>
<div class=""><br class="">
</div>
<div class="">First, I did some patches to handle actual
QTouchEvents in Flickable and</div>
<div class="">MouseArea. This naturally increases the code size
quite dramatically, because</div>
<div class="">QMouseEvent and QTouchEvent have too little in
common, and the delivery</div>
<div class="">strategy needs to be different. QTouchEvents are
broken up according to item</div>
<div class="">boundaries, so that you can touch multiple Items at
the same time with</div>
<div class="">different fingers. This complexity was already
there in QQuickWindow, but I</div>
<div class="">had to add a lot more code to Flickable and
MouseArea. It took a really long</div>
<div class="">time to get all the tests to pass again. Frederik
was supportive, understood</div>
<div class="">the point of what I was doing, and helped with it.
Finally this work was ready</div>
<div class="">to go into 5.5, but then reviewers still had too
many doubts. From one side it</div>
<div class="">doesn't make a lot of sense to take a component
called MouseArea, with all the</div>
<div class="">limitations that name implies, and try to make it do
the right things with</div>
<div class="">touch events too. (Even though users already
expected it to handle taps and</div>
<div class="">drags on touchscreens, because the touch->mouse
synthesis had always been</div>
<div class="">there.) It was a lot of code to read and
understand. So we left it broken.</div>
<div class="">And customers keep asking for those patches, so they
still exist on a personal</div>
<div class="">branch somewhere, which I haven't updated for quite
a while. To this day, if</div>
<div class="">you use any touch-handling Item or pointer handler
inside a Flickable, the</div>
<div class="">results are often not very satisfying. If you turn
on pressDelay, it gets</div>
<div class="">worse. (Flickable never saw the touch press, only a
synth-mouse press. So it</div>
<div class="">cannot replay a touch press either. So the children
will see a synthetic mouse</div>
<div class="">press followed by a series of touch events, and will
be required to see through</div>
<div class="">the synth-mouse crap and treat the whole series as
if the press had been a</div>
<div class="">touch event too. But… should filtering events that
would otherwise go to the</div>
<div class="">children really be Flickable’s responsibility? What
about replaying events</div>
<div class="">after a press delay: monolithic Flickable should
really do that too?) And </div>
<div class="">because of another architectural abomination, making
Item Views inherit </div>
<div class="">Flickable, that affects even more use cases with
ListView and TableView </div>
<div class="">delegates. (I have some hope of eventually
rewriting Flickable using </div>
<div class="">Pointer Handlers (that’s what FakeFlickable.qml
demonstrates), but </div>
<div class="">keeping it working the same both for subclasses and
for end-users is quite</div>
<div class="">a high bar.)</div>
<div class=""><br class="">
</div>
<div class="">That experience taught me that we can only fix touch
and mouse and Wacom tablet</div>
<div class="">event delivery by making it the same for all of
them. That means we must make</div>
<div class="">the events look enough alike that the same delivery
code will work for all of</div>
<div class="">them. It's not possible with the leftover
QInputEvent hierarchy from Qt 4 and</div>
<div class="">earlier. There is not even a consistently-named set
of accessors for getting</div>
<div class="">the coordinates from the various event types.</div>
<div class=""><br class="">
</div>
<div class="">Continuing with the touch->mouse synthesis
approach could maybe have been</div>
<div class="">justified if we had support for multiple mice in Qt
(so that there could be a</div>
<div class="">virtual mouse for each touchpoint), and if we could
agree that it's ok to</div>
<div class="">disassociate touchpoints from each other and deliver
them as separate events.</div>
<div class="">I had a series of patches to deliver touch events
that way. It worked fine in</div>
<div class="">practice, but for that prototype I had done some
non-BC modifications in</div>
<div class="">qevent.h (which could have been mitigated with
differently-designed wrapper</div>
<div class="">events). But when we discussed it with Lars, he was
very much against the idea</div>
<div class="">of disassociating touchpoints, feeling strongly that
points which belong to the</div>
<div class="">same gesture need to be kept together. As said,
touch events get broken up</div>
<div class="">during delivery in QQuickWindow; but if PinchHandler
for example received</div>
<div class="">multiple events, one for each finger involved in the
pinch, it would have to</div>
<div class="">update the gesture each time. We could have
mitigated that by adding an</div>
<div class="">incrementing frame counter so that touchpoints could
be re-associated.</div>
<div class=""><br class="">
</div>
<div class="">But at that time, we concluded that we will go the
other way in Qt Quick: every</div>
<div class="">"pointer event" will have API appropriate for
multiple points. QMouseEvent can</div>
<div class="">have hard-coded accessors for the single point that
it carries; but touch</div>
<div class="">events carry multiple points. This is how we can
eventually refactor the</div>
<div class="">delivery code so that mouse and touch events are
delivered the same way. And</div>
<div class="">we agreed to make the Qt Quick events a prototype of
how we would refactor the</div>
<div class="">QEvents in Qt 6. So since Qt 5.8, Qt Quick has been
delivering wrapper events</div>
<div class="">instead: QQuickPointerEvent which contains instances
of QQuickEventPoint. Some</div>
<div class="">of the delivery refactoring has been done:
conservatively, because although few</div>
<div class="">are willing to help, a lot more complain loudly when
any existing usecase</div>
<div class="">breaks. And there are so many applications already.
But the wrapper events</div>
<div class="">made it possible to develop Pointer Handlers; and
the goal has always been that</div>
<div class="">those would retain QML source compatibility in Qt 6.
The delivery mechanism</div>
<div class="">for those adds a lot of flexibility. After enough
use cases have been ported</div>
<div class="">over to using them, maybe we can eventually
deprecate some of the most</div>
<div class="">pernicious features that depend on complex delivery
code that I'd like to get</div>
<div class="">rid of in QQuickWindow; but progress has been so
slow in other modules outside</div>
<div class="">of Qt Quick itself, that it still seems too early to
consider doing that in Qt</div>
<div class="">6, because it would require heroic effort by a
number of people over a short</div>
<div class="">time period.</div>
<div class=""><br class="">
</div>
<div class="">Anyway, the time has come to at least get the QEvent
refactoring done, so that</div>
<div class="">Qt Quick can go back to delivering them without
wrappers, and so that Items can</div>
<div class="">receive pointer events directly. We have discussed
this a few times already at</div>
<div class="">various events. At one QtCS Qt 6 planning session,
I think in 2018 (or was it</div>
<div class="">earlier?), I promised to do the refactoring for Qt
6. The goal is to break</div>
<div class="">nothing in widgets: that is, QMouseEvent needs to
keep its existing accessors.</div>
<div class="">We will add new ones, and deprecate the ones that
are named inconsistently and</div>
<div class="">the ones that provide integer coordinates. The same
for the other event types.</div>
<div class=""> QTouchEvent::TouchPoint is a bit special: it will
be replaced by the</div>
<div class="">QEventPoint that every QPointerEvent contains at
least one of. So far it looks</div>
<div class="">like I can use "using" to make
QTouchEvent::TouchPoint an alias of QEventPoint,</div>
<div class="">for the sake of source compatibility.</div>
<div class=""><br class="">
</div>
<div class="">I think the result will look something like this:</div>
<div class=""><br class="">
</div>
<div class=""><img apple-inline="yes"
id="4B81B323-AB51-4D9D-8C3B-E9D1AD187F96"
src="cid:part1.4D329614.AF7284E1@tungware.se" class=""></div>
<div class=""><br class="">
</div>
<div class="">What I started with a few months ago was adding
const QInputDevice *device() to</div>
<div class="">QInputEvent. We have seen that the MouseEventSource
enum does not provide</div>
<div class="">enough information. E.g. in Controls we had to
assume in some places that if a</div>
<div class="">mouse event is SynthesizedByQt, then it's
synthesized from a touchscreen by</div>
<div class="">QQuickWindow during delivery of the original
QTouchEvent. That's not always</div>
<div class="">true (there are other places where synthesis
occurs), and resulted in some</div>
<div class="">bugs. Now that we're trying to fully support Wacom
tablets in Qt Quick, a</div>
<div class="">synth-mouse event could come from that. So I want
to completely replace</div>
<div class="">MouseEventSource with the device pointer, so that
the event consumer can see</div>
<div class="">specifically which device the event came from, and
thus can adjust behavior</div>
<div class="">depending on the specific type of device, its
capabilities, the screen area</div>
<div class="">that the device can access (e.g. a touchscreen input
device or Wacom tablet is</div>
<div class="">probably mapped to a specific QScreen or QWindow),
etc. This way we can also</div>
<div class="">begin to support multiple mice and multiple "seats"
(in the Wayland sense) at</div>
<div class="">the same time. But it imposes a new requirement on
platform plugins: to create</div>
<div class="">the QInputDevice instances. The plugins that I know
about all do device</div>
<div class="">discovery anyway, though; they have just been using
internal ad-hoc data</div>
<div class="">structures of their own, and not exposing those
devices to</div>
<div class="">QWindowSystemInterface. I've been working on the
xcb plugin so far, since I</div>
<div class="">understand that one the best, and it already
supports multiple seats after a</div>
<div class="">fashion (there can be multiple core pointers and
core keyboards, and they can</div>
<div class="">be associated with each other; there just isn't a
seat name, but I can make one</div>
<div class="">up).</div>
<div class=""><br class="">
</div>
<div class="">The fantastic result of that should be that event
delivery code can finally be</div>
<div class="">device-agnostic! QQuickWindow and QQuickFlickable
will no longer need to treat</div>
<div class="">mouse and touch events differently, and Wacom tablet
events will go through the</div>
<div class="">same way too. Flickable should be able to blindly
replay a copy of whatever event</div>
<div class="">it got when the pressDelay timer fires, without
caring about every piece of data </div>
<div class="">inside. Only the final event consumer (QQuickItem or
Pointer Handler or even</div>
<div class="">a QWidget subclass) will need to care about the
device-specific details, and it</div>
<div class="">will have all the information necessary for very
finely-tuned behavior. Now we</div>
<div class="">can finally add virtual functions to QQuickItem to
handle pointer events, so</div>
<div class="">not only Pointer Handlers will be able to do that.
And we will open the</div>
<div class="">possibility to refactor event delivery code in other
parts of Qt later on. It</div>
<div class="">should become possible to fix most of the open bugs
related to handling mouse</div>
<div class="">and touch events in Qt Quick and Controls during the
Qt 6 series.</div>
<div class=""><br class="">
</div>
<div class="">Because we will make QPointerEvent look as much as
possible like</div>
<div class="">QQuickPointerEvent, we will maintain QML source
compatibility for anyone who</div>
<div class="">just started using pointer handlers. Of course the
goal is for older stuff</div>
<div class="">like MouseArea and Flickable and Controls that we
can choose appropriate API</div>
<div class="">changes, not be required to make them because of
event changes. QPointerEvent</div>
<div class="">will be a gadget instead of a QObject wrapper, but
it will have the same</div>
<div class="">properties, so to the extent that it's exposed in
QML API (which is not much),</div>
<div class="">it will look the same. It will also look enough
like a QMouseEvent and enough</div>
<div class="">like a QTouchEvent that we will have source
compatibility in virtual functions</div>
<div class="">that handle those, too. Hopefully.</div>
<div class=""><br class="">
</div>
<div class="">After proving that we have also maintained source
compatibility as much as</div>
<div class="">possible (including in the great heap of widget code
in the world), we still</div>
<div class="">end up with a lot of deprecated methods that should
be replaced over time</div>
<div class="">(QPoint pos() -> QPointF position() and such).
For that purpose I want to add</div>
<div class="">a feature to clazy or develop some other clang-based
tooling which can fix all</div>
<div class="">of our modules, and also be available to customers
to make the same</div>
<div class="">replacements in their code bases. If we end up with
any SC breaks, it's a</div>
<div class="">possible fallback position that at least we can
deliver a tool to fix them.</div>
<div class=""><br class="">
</div>
<div class="">Beyond that, we probably ought to do something about
native gestures. Another</div>
<div class="">reason Qt Quick is so complex is that it started out
assuming it will be given</div>
<div class="">only raw touch events and needs to do gesture
recognition itself; but now</div>
<div class="">gestures have gone mainstream on most platforms, so
we could be getting</div>
<div class="">QNativeGestureEvents from most of them, especially
from touchpads. But I</div>
<div class="">didn't get as far as I should have over the last
couple of years just exploring</div>
<div class="">how to improve that aspect of Qt, and the platform
plugin maintainers</div>
<div class="">have not gotten around to adding support for native
gestures to all the</div>
<div class="">platforms that could have them, either. I wish we
could get rid of the gesture</div>
<div class="">recognizer in the widgets module completely; but
customers will not be</div>
<div class="">satisfied unless we then have native gesture
recognition on all platforms where</div>
<div class="">it's possible. Some of them want to continue doing
custom gesture recognition,</div>
<div class="">too. But we have QGestureEvent (for the widget
gesture recognizer) and</div>
<div class="">QNativeGestureEvent (for gesture events that come
from the QPA plugin) as</div>
<div class="">separate types. We're running out of time to figure
out whether we can unify</div>
<div class="">those two, just to make it less confusing for
applications. I guess it's not</div>
<div class="">so terrible to keep the events separate if we still
have to keep the old</div>
<div class="">gesture framework intact; but do we?</div>
<div class=""><br class="">
</div>
<div class="">So that's the status of pointer event handling. And
I'm still working mostly</div>
<div class="">alone on it. It seems with our schedule that the
QEvent API, and all other</div>
<div class="">APIs that need to change as a result of that, need
to be stabilized by the end</div>
<div class="">of June. I still think I can get the broad strokes
done if nobody and no</div>
<div class="">unexpected bugs get in the way this time, and the
+2's come quickly (keeping in</div>
<div class="">mind that the perfect is the enemy of the good, and
every change is subject to</div>
<div class="">ongoing incremental changes later). (It looks like
my time is limited to make</div>
<div class="">other API changes in Qt Quick, since this is taking
most of it.) Is anyone</div>
<div class="">interested in helping?</div>
<br>
</blockquote>
Hi, I tried some QGestureEvents this winter in my first Qt iOS app,
and got bored having to use 3 fingers on my iPhone for swiping (1
finger seems to be the norm on Android and iPhones). And I
discovered that it was pretty easy to integrate the vanilla standard
iOS 1-finger swiping with Qt, see
<a class="moz-txt-link-freetext" href="https://bugreports.qt.io/browse/QTBUG-81042">https://bugreports.qt.io/browse/QTBUG-81042</a><br>
<br>
If you're thinking about refactoring also for iOS, maybe my
suggestion can help...<br>
<br>
Rgrds Henry<br>
<br>
</body>
</html>