summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSzabolcs David <davidsz@inf.u-szeged.hu>2017-09-12 18:53:59 +0200
committerSzabolcs David <davidsz@inf.u-szeged.hu>2017-11-03 00:46:30 +0000
commit0bbaf0d5d7b2d406eda57d40370b00fb79cc0aeb (patch)
treec23285ae71d4733c4bdd3d9c6749daba371610fb
parent18ea13a7f5e083538910646c52a96a5e4642d1f2 (diff)
Support tablet devices
Process QTabletEvents and forward them to Chromium in order to support pressure, tilting, rotation, eraser and similar features of tablet devices. Change-Id: I763d9e6e7036c29715a0b5531d3c6363eb4fcd8c Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
-rw-r--r--src/core/render_widget_host_view_qt.cpp103
-rw-r--r--src/core/render_widget_host_view_qt.h3
-rw-r--r--src/core/web_event_factory.cpp48
-rw-r--r--src/core/web_event_factory.h2
-rw-r--r--tests/manual/html/pointer-events.html69
5 files changed, 179 insertions, 46 deletions
diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp
index 9be5bd498..7ce71a81d 100644
--- a/src/core/render_widget_host_view_qt.cpp
+++ b/src/core/render_widget_host_view_qt.cpp
@@ -957,6 +957,12 @@ bool RenderWidgetHostViewQt::forwardEvent(QEvent *event)
case QEvent::TouchCancel:
handleTouchEvent(static_cast<QTouchEvent*>(event));
break;
+ case QEvent::TabletPress:
+ Focus(); // Fall through.
+ case QEvent::TabletRelease:
+ case QEvent::TabletMove:
+ handleTabletEvent(static_cast<QTabletEvent*>(event));
+ break;
#ifndef QT_NO_GESTURES
case QEvent::NativeGesture:
handleGestureEvent(static_cast<QNativeGestureEvent *>(event));
@@ -1089,49 +1095,7 @@ void RenderWidgetHostViewQt::handleMouseEvent(QMouseEvent* event)
// transformation done by Chromium.
if (event->source() == Qt::MouseEventSynthesizedBySystem)
return;
-
- blink::WebMouseEvent webEvent = WebEventFactory::toWebMouseEvent(event, dpiScale());
- if ((webEvent.GetType() == blink::WebInputEvent::kMouseDown || webEvent.GetType() == blink::WebInputEvent::kMouseUp)
- && webEvent.button == blink::WebMouseEvent::Button::kNoButton) {
- // Blink can only handle the 3 main mouse-buttons and may assert when processing mouse-down for no button.
- return;
- }
-
-
- if (event->type() == QMouseEvent::MouseButtonPress) {
- if (event->button() != m_clickHelper.lastPressButton
- || (event->timestamp() - m_clickHelper.lastPressTimestamp > static_cast<ulong>(qGuiApp->styleHints()->mouseDoubleClickInterval()))
- || (event->pos() - m_clickHelper.lastPressPosition).manhattanLength() > qGuiApp->styleHints()->startDragDistance())
- m_clickHelper.clickCounter = 0;
-
- m_clickHelper.lastPressTimestamp = event->timestamp();
- webEvent.click_count = ++m_clickHelper.clickCounter;
- m_clickHelper.lastPressButton = event->button();
- m_clickHelper.lastPressPosition = QPointF(event->pos()).toPoint();
- }
-
- webEvent.movement_x = event->globalX() - m_previousMousePosition.x();
- webEvent.movement_y = event->globalY() - m_previousMousePosition.y();
-
- if (IsMouseLocked())
- QCursor::setPos(m_previousMousePosition);
- else
- m_previousMousePosition = event->globalPos();
-
- if (m_imeInProgress && event->type() == QMouseEvent::MouseButtonPress) {
- m_imeInProgress = false;
- // Tell input method to commit the pre-edit string entered so far, and finish the
- // composition operation.
-#ifdef Q_OS_WIN
- // Yes the function name is counter-intuitive, but commit isn't actually implemented
- // by the Windows QPA, and reset does exactly what is necessary in this case.
- qApp->inputMethod()->reset();
-#else
- qApp->inputMethod()->commit();
-#endif
- }
-
- m_host->ForwardMouseEvent(webEvent);
+ handlePointerEvent<QMouseEvent>(event);
}
void RenderWidgetHostViewQt::handleKeyEvent(QKeyEvent *ev)
@@ -1483,6 +1447,59 @@ void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev)
}
}
+void RenderWidgetHostViewQt::handleTabletEvent(QTabletEvent *event)
+{
+ handlePointerEvent<QTabletEvent>(event);
+}
+
+template<class T>
+void RenderWidgetHostViewQt::handlePointerEvent(T *event)
+{
+ // Currently WebMouseEvent is a subclass of WebPointerProperties, so basically
+ // tablet events are mouse events with extra properties.
+ blink::WebMouseEvent webEvent = WebEventFactory::toWebMouseEvent(event, dpiScale());
+ if ((webEvent.GetType() == blink::WebInputEvent::kMouseDown || webEvent.GetType() == blink::WebInputEvent::kMouseUp)
+ && webEvent.button == blink::WebMouseEvent::Button::kNoButton) {
+ // Blink can only handle the 3 main mouse-buttons and may assert when processing mouse-down for no button.
+ return;
+ }
+
+ if (webEvent.GetType() == blink::WebInputEvent::kMouseDown) {
+ if (event->button() != m_clickHelper.lastPressButton
+ || (event->timestamp() - m_clickHelper.lastPressTimestamp > static_cast<ulong>(qGuiApp->styleHints()->mouseDoubleClickInterval()))
+ || (event->pos() - m_clickHelper.lastPressPosition).manhattanLength() > qGuiApp->styleHints()->startDragDistance())
+ m_clickHelper.clickCounter = 0;
+
+ m_clickHelper.lastPressTimestamp = event->timestamp();
+ webEvent.click_count = ++m_clickHelper.clickCounter;
+ m_clickHelper.lastPressButton = event->button();
+ m_clickHelper.lastPressPosition = QPointF(event->pos()).toPoint();
+ }
+
+ webEvent.movement_x = event->globalX() - m_previousMousePosition.x();
+ webEvent.movement_y = event->globalY() - m_previousMousePosition.y();
+
+ if (IsMouseLocked())
+ QCursor::setPos(m_previousMousePosition);
+ else
+ m_previousMousePosition = event->globalPos();
+
+ if (m_imeInProgress && webEvent.GetType() == blink::WebInputEvent::kMouseDown) {
+ m_imeInProgress = false;
+ // Tell input method to commit the pre-edit string entered so far, and finish the
+ // composition operation.
+#ifdef Q_OS_WIN
+ // Yes the function name is counter-intuitive, but commit isn't actually implemented
+ // by the Windows QPA, and reset does exactly what is necessary in this case.
+ qApp->inputMethod()->reset();
+#else
+ qApp->inputMethod()->commit();
+#endif
+ }
+
+ m_host->ForwardMouseEvent(webEvent);
+}
+
void RenderWidgetHostViewQt::handleHoverEvent(QHoverEvent *ev)
{
m_host->ForwardMouseEvent(WebEventFactory::toWebMouseEvent(ev, dpiScale()));
diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h
index 7d32cc645..74f14d0d4 100644
--- a/src/core/render_widget_host_view_qt.h
+++ b/src/core/render_widget_host_view_qt.h
@@ -186,6 +186,7 @@ public:
void handleKeyEvent(QKeyEvent*);
void handleWheelEvent(QWheelEvent*);
void handleTouchEvent(QTouchEvent*);
+ void handleTabletEvent(QTabletEvent *ev);
#ifndef QT_NO_GESTURES
void handleGestureEvent(QNativeGestureEvent *);
#endif
@@ -194,6 +195,8 @@ public:
void handleInputMethodEvent(QInputMethodEvent*);
void handleInputMethodQueryEvent(QInputMethodQueryEvent*);
+ template<class T> void handlePointerEvent(T*);
+
#if defined(OS_MACOSX)
void SetActive(bool active) override { QT_NOT_YET_IMPLEMENTED }
bool IsSpeaking() const override { QT_NOT_YET_IMPLEMENTED; return false; }
diff --git a/src/core/web_event_factory.cpp b/src/core/web_event_factory.cpp
index 18f8d393f..b785adec0 100644
--- a/src/core/web_event_factory.cpp
+++ b/src/core/web_event_factory.cpp
@@ -76,6 +76,7 @@
#include <QKeyEvent>
#include <QMouseEvent>
#include <QStyleHints>
+#include <QTabletEvent>
#include <QWheelEvent>
using namespace blink;
@@ -1032,7 +1033,8 @@ static inline double currentTimeForEvent(const QInputEvent* event)
return static_cast<double>(timer.elapsed()) / 1000;
}
-static WebMouseEvent::Button mouseButtonForEvent(QMouseEvent *event)
+template<class T>
+static WebMouseEvent::Button mouseButtonForEvent(T *event)
{
if (event->button() == Qt::LeftButton)
return WebMouseEvent::Button::kLeft;
@@ -1041,7 +1043,7 @@ static WebMouseEvent::Button mouseButtonForEvent(QMouseEvent *event)
else if (event->button() == Qt::MidButton)
return WebMouseEvent::Button::kMiddle;
- if (event->type() != QEvent::MouseMove)
+ if (event->type() != QEvent::MouseMove && event->type() != QEvent::TabletMove)
return WebMouseEvent::Button::kNoButton;
// This is technically wrong, mouse move should always have ButtonNone,
@@ -1147,14 +1149,17 @@ static WebInputEvent::Type webEventTypeForEvent(const QEvent* event)
{
switch (event->type()) {
case QEvent::MouseButtonPress:
+ case QEvent::TabletPress:
return WebInputEvent::kMouseDown;
case QEvent::MouseButtonRelease:
+ case QEvent::TabletRelease:
return WebInputEvent::kMouseUp;
case QEvent::Enter:
return WebInputEvent::kMouseEnter;
case QEvent::Leave:
return WebInputEvent::kMouseLeave;
case QEvent::MouseMove:
+ case QEvent::TabletMove:
return WebInputEvent::kMouseMove;
case QEvent::Wheel:
return WebInputEvent::kMouseWheel;
@@ -1178,6 +1183,20 @@ static WebInputEvent::Type webEventTypeForEvent(const QEvent* event)
}
}
+static WebPointerProperties::PointerType pointerTypeForTabletEvent(const QTabletEvent *ev)
+{
+ switch (ev->pointerType()) {
+ case QTabletEvent::UnknownPointer:
+ return WebPointerProperties::PointerType::kUnknown;
+ case QTabletEvent::Pen:
+ return WebPointerProperties::PointerType::kPen;
+ case QTabletEvent::Eraser:
+ return WebPointerProperties::PointerType::kEraser;
+ default:
+ return WebPointerProperties::PointerType::kMouse;
+ }
+}
+
WebMouseEvent WebEventFactory::toWebMouseEvent(QMouseEvent *ev, double dpiScale)
{
WebMouseEvent webKitEvent(webEventTypeForEvent(ev),
@@ -1188,7 +1207,7 @@ WebMouseEvent WebEventFactory::toWebMouseEvent(QMouseEvent *ev, double dpiScale)
modifiersForEvent(ev),
currentTimeForEvent(ev));
- webKitEvent.button = mouseButtonForEvent(ev);
+ webKitEvent.button = mouseButtonForEvent<QMouseEvent>(ev);
webKitEvent.click_count = 0;
return webKitEvent;
@@ -1208,6 +1227,29 @@ WebMouseEvent WebEventFactory::toWebMouseEvent(QHoverEvent *ev, double dpiScale)
return webKitEvent;
}
+WebMouseEvent WebEventFactory::toWebMouseEvent(QTabletEvent *ev, double dpiScale)
+{
+ WebMouseEvent webKitEvent(webEventTypeForEvent(ev),
+ ev->x() / dpiScale,
+ ev->y() / dpiScale,
+ ev->globalX(),
+ ev->globalY(),
+ modifiersForEvent(ev),
+ currentTimeForEvent(ev));
+
+ webKitEvent.force = ev->pressure();
+ webKitEvent.tilt_x = ev->xTilt();
+ webKitEvent.tilt_y = ev->yTilt();
+ webKitEvent.tangential_pressure = ev->tangentialPressure();
+ webKitEvent.twist = ev->rotation();
+ webKitEvent.pointer_type = pointerTypeForTabletEvent(ev);
+
+ webKitEvent.button = mouseButtonForEvent<QTabletEvent>(ev);
+ webKitEvent.click_count = 0;
+
+ return webKitEvent;
+}
+
#ifndef QT_NO_GESTURES
WebGestureEvent WebEventFactory::toWebGestureEvent(QNativeGestureEvent *ev, double dpiScale)
{
diff --git a/src/core/web_event_factory.h b/src/core/web_event_factory.h
index 259795c1f..c9ae86a73 100644
--- a/src/core/web_event_factory.h
+++ b/src/core/web_event_factory.h
@@ -53,6 +53,7 @@ QT_BEGIN_NAMESPACE
class QHoverEvent;
class QKeyEvent;
class QMouseEvent;
+class QTabletEvent;
class QWheelEvent;
#ifndef QT_NO_GESTURES
class QNativeGestureEvent;
@@ -64,6 +65,7 @@ class WebEventFactory {
public:
static blink::WebMouseEvent toWebMouseEvent(QMouseEvent*, double dpiScale);
static blink::WebMouseEvent toWebMouseEvent(QHoverEvent*, double dpiScale);
+ static blink::WebMouseEvent toWebMouseEvent(QTabletEvent*, double dpiScale);
#ifndef QT_NO_GESTURES
static blink::WebGestureEvent toWebGestureEvent(QNativeGestureEvent *, double dpiScale);
#endif
diff --git a/tests/manual/html/pointer-events.html b/tests/manual/html/pointer-events.html
new file mode 100644
index 000000000..c6e728662
--- /dev/null
+++ b/tests/manual/html/pointer-events.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Pointer event test</title>
+ </head>
+ <body>
+
+<p>
+ <canvas id="listener" width="500" height="500" style="border: silver 1px dotted;"></canvas>
+</p>
+<p>
+ Touch this circle with a stylus. Its size indicates your pressure; its position is the angle between your stylus and your tablet device; and the radius is the rotation - if your tablet supports it.
+</p>
+
+ </body>
+ <script>
+
+var canvas = document.getElementById("listener");
+var context = canvas.getContext('2d');
+
+var eventName = [
+ "pointerover",
+ "pointerenter",
+ "pointerdown",
+ "pointermove",
+ "pointerup",
+ "pointercancel",
+ "pointerout",
+ "pointerleave",
+ "gotpointercapture",
+ "lostpointercapture"
+];
+
+for (var i = 0; i < eventName.length; i++) {
+ canvas.addEventListener(eventName[i], function(ev) {
+ drawCircle(ev.pressure, ev.tiltX, ev.tiltY, ev.twist);
+ }, false);
+}
+
+drawCircle(0, 0, 0, 0);
+
+function drawCircle(pressure, tiltX, tiltY, twist) {
+ var centerX = canvas.width / 2 + tiltX;
+ var centerY = canvas.height / 2 + tiltY;
+ var radius = 100 + 100 * pressure;
+
+ context.clearRect(0, 0, canvas.width, canvas.height);
+ context.beginPath();
+ context.arc(centerX,
+ centerY,
+ radius,
+ 0,
+ 2 * Math.PI,
+ false);
+ context.fillStyle = 'lightblue';
+ context.fill();
+ context.lineWidth = 3;
+ context.strokeStyle = '#008B8B';
+ context.stroke();
+
+ context.beginPath();
+ context.moveTo(centerX, centerY);
+ context.lineTo(centerX + radius * Math.cos(twist), centerY + radius * Math.sin(twist));
+ context.stroke();
+}
+
+</script>
+</html>