Skip to content

Commit eeebf4f

Browse files
author
Raphael Dumusc
authored
Merge pull request #124 from rdumusc/master
QmlStreamer: bugfix and improvement for WebEngineView
2 parents df3ead0 + 9ca48f5 commit eeebf4f

4 files changed

Lines changed: 87 additions & 8 deletions

File tree

deflect/qt/QmlStreamer.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,12 @@ namespace qt
6565
*
6666
* When using a WebEngineView, users must call QtWebEngine::initialize() in the
6767
* QApplication before creating the streamer. Also, due to a limitiation in Qt,
68-
* the objectName property of any WebEngineView must be set to "webengineview"
69-
* for it to receive keyboard events.
68+
* the objectName property of any WebEngineView must be set to "webengineview".
69+
* This is necessary for it to receive keyboard events and to correct the
70+
* default behaviour of the tapAndHold gesture. Deflect will prevent the opening
71+
* of an on-screen context menu (which may crash the application) and instead
72+
* switch to a "mouse" interaction mode. This allows users to interact within
73+
* a WebGL canevas or select text instead of scrolling the page.
7074
*/
7175
class QmlStreamer : public QObject
7276
{

deflect/qt/QmlStreamerImpl.cpp

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ namespace
6262
const std::string DEFAULT_STREAM_ID( "QmlStreamer" );
6363
const QString GESTURES_CONTEXT_PROPERTY( "deflectgestures" );
6464
const QString WEBENGINEVIEW_OBJECT_NAME( "webengineview" );
65+
const int TOUCH_TAPANDHOLD_DIST_PX = 20;
66+
const int TOUCH_TAPANDHOLD_TIMEOUT_MS = 200;
6567
}
6668

6769
class RenderControl : public QQuickRenderControl
@@ -109,6 +111,7 @@ QmlStreamer::Impl::Impl( const QString& qmlFile, const std::string& streamHost,
109111
, _streaming( false )
110112
, _streamHost( streamHost )
111113
, _streamId( streamId )
114+
, _mouseMode( false )
112115
{
113116
// Expose stream gestures to qml objects
114117
_qmlEngine->rootContext()->setContextProperty( GESTURES_CONTEXT_PROPERTY,
@@ -135,6 +138,10 @@ QmlStreamer::Impl::Impl( const QString& qmlFile, const std::string& streamHost,
135138
#else
136139
qWarning() << "DeflectQt was not compiled with WebEngineView support";
137140
#endif
141+
connect( &_mouseModeTimer, &QTimer::timeout, [this]() {
142+
if( _touchIsTapAndHold( ))
143+
_switchFromTouchToMouseMode();
144+
});
138145

139146
// Pass _context->format(), not format_. Format does not specify and color
140147
// buffer sizes, while the context, that has just been created, reports a
@@ -280,28 +287,49 @@ void QmlStreamer::Impl::_onPressed( double x_, double y_ )
280287
auto touchPoint = _makeTouchPoint( 0, { x_, y_ });
281288
touchPoint.setState( Qt::TouchPointPressed );
282289

283-
auto* e = new QTouchEvent( QEvent::TouchBegin, &_device, Qt::NoModifier,
284-
Qt::TouchPointPressed, { touchPoint } );
290+
_startMouseModeSwitchDetection( touchPoint.pos( ));
291+
292+
auto e = new QTouchEvent( QEvent::TouchBegin, &_device, Qt::NoModifier,
293+
Qt::TouchPointPressed, { touchPoint } );
285294
QCoreApplication::postEvent( _quickWindow, e );
286295
}
287296

288297
void QmlStreamer::Impl::_onMoved( double x_, double y_ )
289298
{
299+
if( _mouseMode )
300+
{
301+
const QPoint pos( x_ * width(), y_ * height( ));
302+
_sendMouseEvent( QEvent::MouseMove, pos );
303+
return;
304+
}
305+
290306
auto touchPoint = _makeTouchPoint( 0, { x_, y_ });
291307
touchPoint.setState( Qt::TouchPointMoved );
292308

293-
auto* e = new QTouchEvent( QEvent::TouchUpdate, &_device, Qt::NoModifier,
294-
Qt::TouchPointMoved, { touchPoint } );
309+
if( _mouseModeTimer.isActive( ))
310+
_touchCurrentPos = touchPoint.pos();
311+
312+
auto e = new QTouchEvent( QEvent::TouchUpdate, &_device, Qt::NoModifier,
313+
Qt::TouchPointMoved, { touchPoint } );
295314
QCoreApplication::postEvent( _quickWindow, e );
296315
}
297316

298317
void QmlStreamer::Impl::_onReleased( double x_, double y_ )
299318
{
319+
_mouseModeTimer.stop();
320+
if( _mouseMode )
321+
{
322+
const QPoint pos( x_ * width(), y_ * height( ));
323+
_sendMouseEvent( QEvent::MouseButtonRelease, pos );
324+
_mouseMode = false;
325+
return;
326+
}
327+
300328
auto touchPoint = _makeTouchPoint( 0, { x_, y_ });
301329
touchPoint.setState( Qt::TouchPointReleased );
302330

303-
auto* e = new QTouchEvent( QEvent::TouchEnd, &_device, Qt::NoModifier,
304-
Qt::TouchPointReleased, { touchPoint } );
331+
auto e = new QTouchEvent( QEvent::TouchEnd, &_device, Qt::NoModifier,
332+
Qt::TouchPointReleased, { touchPoint } );
305333
QCoreApplication::postEvent( _quickWindow, e );
306334
}
307335

@@ -489,6 +517,39 @@ void QmlStreamer::Impl::_updateSizes( const QSize& size_ )
489517
}
490518
}
491519

520+
void QmlStreamer::Impl::_startMouseModeSwitchDetection( const QPointF& pos )
521+
{
522+
auto item = _rootItem->childAt( pos.x(), pos.y());
523+
if( item->objectName() == WEBENGINEVIEW_OBJECT_NAME )
524+
{
525+
_mouseModeTimer.start( TOUCH_TAPANDHOLD_TIMEOUT_MS );
526+
_touchStartPos = pos;
527+
_touchCurrentPos = pos;
528+
}
529+
}
530+
531+
bool QmlStreamer::Impl::_touchIsTapAndHold()
532+
{
533+
const auto distance = (_touchCurrentPos - _touchStartPos).manhattanLength();
534+
return distance < TOUCH_TAPANDHOLD_DIST_PX;
535+
}
536+
537+
void QmlStreamer::Impl::_switchFromTouchToMouseMode()
538+
{
539+
_onReleased( _touchCurrentPos.x() / width(),
540+
_touchCurrentPos.y() / height( ));
541+
_mouseMode = true;
542+
_sendMouseEvent( QEvent::MouseButtonPress, _touchCurrentPos );
543+
}
544+
545+
void QmlStreamer::Impl::_sendMouseEvent( const QEvent::Type eventType,
546+
const QPointF& pos )
547+
{
548+
auto e = new QMouseEvent( eventType, pos, Qt::LeftButton, Qt::LeftButton,
549+
Qt::NoModifier );
550+
QCoreApplication::postEvent( _quickWindow, e );
551+
}
552+
492553
QTouchEvent::TouchPoint
493554
QmlStreamer::Impl::_makeTouchPoint( const int id, const QPointF& normPos ) const
494555
{

deflect/qt/QmlStreamerImpl.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ private slots:
113113
void _updateSizes( const QSize& size );
114114
QTouchEvent::TouchPoint _makeTouchPoint( int id, const QPointF& pos ) const;
115115

116+
void _startMouseModeSwitchDetection( const QPointF& pos );
117+
bool _touchIsTapAndHold();
118+
void _switchFromTouchToMouseMode();
119+
void _sendMouseEvent( QEvent::Type eventType, const QPointF& pos );
120+
116121
QOpenGLContext* _context;
117122
QOffscreenSurface* _offscreenSurface;
118123
QQuickRenderControl* _renderControl;
@@ -134,6 +139,11 @@ private slots:
134139
SizeHints _sizeHints;
135140

136141
QTouchDevice _device;
142+
143+
QTimer _mouseModeTimer;
144+
bool _mouseMode;
145+
QPointF _touchStartPos;
146+
QPointF _touchCurrentPos;
137147
};
138148

139149
}

doc/Changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ Changelog {#Changelog}
55

66
### 0.12.0 (git master)
77

8+
* [124](https://github.com/BlueBrain/Deflect/pull/124):
9+
QmlStreamer: Users can now interact with WebGL content in a WebEngineView
10+
and no longer risk opening a system context menu with a long press (prevent
11+
crashes in certain offscreen applications).
812
* [123](https://github.com/BlueBrain/Deflect/pull/123):
913
QmlStreamer is now compatible with Qml WebEngineView items. Users must call
1014
QtWebEngine::initialize() in their QApplication before creating the stream.

0 commit comments

Comments
 (0)