Android: generate QTabletEvents for stylus devices such as the S Pen
For example the Galaxy Note series of devices. This makes possible drawing applications which handle stylus events differently from touch or mouse. As on any other platform, if the application does not accept the QTabletEvent, a QMouseEvent will be synthesized. Also fix the tablet manual test to show larger circles on hidpi devices. [ChangeLog][Android] stylus devices such as the S Pen generate QTabletEvents Task-number: QTBUG-38379 Change-Id: Ib594f453b8403cc06aa4e440a76f07afa3bac38c Reviewed-by: Paul Olav Tvete <paul.tvete@theqtcompany.com>
This commit is contained in:
parent
e227b8ecf6
commit
01d78ba86a
@ -43,6 +43,7 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.text.ClipboardManager;
|
import android.text.ClipboardManager;
|
||||||
|
import android.os.Build;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.ContextMenu;
|
import android.view.ContextMenu;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
@ -301,32 +302,49 @@ public class QtNative
|
|||||||
|
|
||||||
static public void sendTouchEvent(MotionEvent event, int id)
|
static public void sendTouchEvent(MotionEvent event, int id)
|
||||||
{
|
{
|
||||||
//@ANDROID-5
|
int pointerType = 0;
|
||||||
touchBegin(id);
|
|
||||||
for (int i=0;i<event.getPointerCount();i++) {
|
if (Build.VERSION.SDK_INT >= 14) {
|
||||||
touchAdd(id,
|
switch (event.getToolType(0)) {
|
||||||
event.getPointerId(i),
|
case MotionEvent.TOOL_TYPE_STYLUS:
|
||||||
getAction(i, event),
|
pointerType = 1; // QTabletEvent::Pen
|
||||||
i == 0,
|
break;
|
||||||
(int)event.getX(i),
|
case MotionEvent.TOOL_TYPE_ERASER:
|
||||||
(int)event.getY(i),
|
pointerType = 3; // QTabletEvent::Eraser
|
||||||
event.getSize(i),
|
break;
|
||||||
event.getPressure(i));
|
// TODO TOOL_TYPE_MOUSE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (event.getAction()) {
|
if (pointerType != 0) {
|
||||||
case MotionEvent.ACTION_DOWN:
|
tabletEvent(id, event.getDeviceId(), event.getEventTime(), event.getAction(), pointerType,
|
||||||
touchEnd(id,0);
|
event.getButtonState(), event.getX(), event.getY(), event.getPressure());
|
||||||
break;
|
} else {
|
||||||
|
touchBegin(id);
|
||||||
|
for (int i = 0; i < event.getPointerCount(); ++i) {
|
||||||
|
touchAdd(id,
|
||||||
|
event.getPointerId(i),
|
||||||
|
getAction(i, event),
|
||||||
|
i == 0,
|
||||||
|
(int)event.getX(i),
|
||||||
|
(int)event.getY(i),
|
||||||
|
event.getSize(i),
|
||||||
|
event.getPressure(i));
|
||||||
|
}
|
||||||
|
|
||||||
case MotionEvent.ACTION_UP:
|
switch (event.getAction()) {
|
||||||
touchEnd(id,2);
|
case MotionEvent.ACTION_DOWN:
|
||||||
break;
|
touchEnd(id, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
case MotionEvent.ACTION_UP:
|
||||||
touchEnd(id,1);
|
touchEnd(id, 2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
touchEnd(id, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//@ANDROID-5
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static public void sendTrackballEvent(MotionEvent event, int id)
|
static public void sendTrackballEvent(MotionEvent event, int id)
|
||||||
@ -592,6 +610,10 @@ public class QtNative
|
|||||||
public static native void longPress(int winId, int x, int y);
|
public static native void longPress(int winId, int x, int y);
|
||||||
// pointer methods
|
// pointer methods
|
||||||
|
|
||||||
|
// tablet methods
|
||||||
|
public static native void tabletEvent(int winId, int deviceId, long time, int action, int pointerType, int buttonState, float x, float y, float pressure);
|
||||||
|
// tablet methods
|
||||||
|
|
||||||
// keyboard methods
|
// keyboard methods
|
||||||
public static native void keyDown(int key, int unicode, int modifier, boolean autoRepeat);
|
public static native void keyDown(int key, int unicode, int modifier, boolean autoRepeat);
|
||||||
public static native void keyUp(int key, int unicode, int modifier, boolean autoRepeat);
|
public static native void keyUp(int key, int unicode, int modifier, boolean autoRepeat);
|
||||||
|
@ -238,6 +238,52 @@ namespace QtAndroidInput
|
|||||||
QWindowSystemInterface::handleTouchEvent(window, touchDevice, m_touchPoints);
|
QWindowSystemInterface::handleTouchEvent(window, touchDevice, m_touchPoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void tabletEvent(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint deviceId, jlong time, jint action,
|
||||||
|
jint pointerType, jint buttonState, jfloat x, jfloat y, jfloat pressure)
|
||||||
|
{
|
||||||
|
QPointF globalPosF(x, y);
|
||||||
|
QPoint globalPos((int)x, (int)y);
|
||||||
|
QWindow *tlw = topLevelWindowAt(globalPos);
|
||||||
|
QPointF localPos = tlw ? (globalPosF - tlw->position()) : globalPosF;
|
||||||
|
|
||||||
|
// Galaxy Note with plain Android:
|
||||||
|
// 0 1 0 stylus press
|
||||||
|
// 2 1 0 stylus drag
|
||||||
|
// 1 1 0 stylus release
|
||||||
|
// 0 1 2 stylus press with side-button held
|
||||||
|
// 2 1 2 stylus drag with side-button held
|
||||||
|
// 1 1 2 stylus release with side-button held
|
||||||
|
// Galaxy Note 4 with Samsung firmware:
|
||||||
|
// 0 1 0 stylus press
|
||||||
|
// 2 1 0 stylus drag
|
||||||
|
// 1 1 0 stylus release
|
||||||
|
// 211 1 2 stylus press with side-button held
|
||||||
|
// 213 1 2 stylus drag with side-button held
|
||||||
|
// 212 1 2 stylus release with side-button held
|
||||||
|
// when action == ACTION_UP (1) it's a release; otherwise we say which button is pressed
|
||||||
|
Qt::MouseButtons buttons = Qt::NoButton;
|
||||||
|
switch (action) {
|
||||||
|
case 1: // ACTION_UP
|
||||||
|
case 212: // stylus release while side-button held on Galaxy Note 4
|
||||||
|
buttons = Qt::NoButton;
|
||||||
|
break;
|
||||||
|
default: // action is press or drag
|
||||||
|
if (buttonState == 0)
|
||||||
|
buttons = Qt::LeftButton;
|
||||||
|
else // 2 means RightButton
|
||||||
|
buttons = Qt::MouseButtons(buttonState);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef QT_DEBUG_ANDROID_STYLUS
|
||||||
|
qDebug() << action << pointerType << buttonState << "@" << x << y << "pressure" << pressure << ": buttons" << buttons;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QWindowSystemInterface::handleTabletEvent(tlw, ulong(time),
|
||||||
|
localPos, globalPosF, QTabletEvent::Stylus, pointerType,
|
||||||
|
buttons, pressure, 0, 0, 0., 0., 0, deviceId, Qt::NoModifier);
|
||||||
|
}
|
||||||
|
|
||||||
static int mapAndroidKey(int key)
|
static int mapAndroidKey(int key)
|
||||||
{
|
{
|
||||||
// 0--9 0x00000007 -- 0x00000010
|
// 0--9 0x00000007 -- 0x00000010
|
||||||
@ -702,6 +748,7 @@ namespace QtAndroidInput
|
|||||||
{"mouseUp", "(III)V", (void *)mouseUp},
|
{"mouseUp", "(III)V", (void *)mouseUp},
|
||||||
{"mouseMove", "(III)V", (void *)mouseMove},
|
{"mouseMove", "(III)V", (void *)mouseMove},
|
||||||
{"longPress", "(III)V", (void *)longPress},
|
{"longPress", "(III)V", (void *)longPress},
|
||||||
|
{"tabletEvent", "(IIJIIIFFF)V", (void *)tabletEvent},
|
||||||
{"keyDown", "(IIIZ)V", (void *)keyDown},
|
{"keyDown", "(IIIZ)V", (void *)keyDown},
|
||||||
{"keyUp", "(IIIZ)V", (void *)keyUp},
|
{"keyUp", "(IIIZ)V", (void *)keyUp},
|
||||||
{"keyboardVisibilityChanged", "(Z)V", (void *)keyboardVisibilityChanged}
|
{"keyboardVisibilityChanged", "(Z)V", (void *)keyboardVisibilityChanged}
|
||||||
|
@ -100,17 +100,19 @@ EventReportWidget::EventReportWidget()
|
|||||||
void EventReportWidget::paintEvent(QPaintEvent *)
|
void EventReportWidget::paintEvent(QPaintEvent *)
|
||||||
{
|
{
|
||||||
QPainter p(this);
|
QPainter p(this);
|
||||||
|
int lineSpacing = fontMetrics().lineSpacing();
|
||||||
|
int halfLineSpacing = lineSpacing / 2;
|
||||||
const QRectF geom = QRectF(QPoint(0, 0), size());
|
const QRectF geom = QRectF(QPoint(0, 0), size());
|
||||||
p.fillRect(geom, Qt::white);
|
p.fillRect(geom, Qt::white);
|
||||||
p.drawRect(QRectF(geom.topLeft(), geom.bottomRight() - QPointF(1,1)));
|
p.drawRect(QRectF(geom.topLeft(), geom.bottomRight() - QPointF(1,1)));
|
||||||
p.setPen(Qt::white);
|
p.setPen(Qt::white);
|
||||||
QPainterPath ellipse;
|
QPainterPath ellipse;
|
||||||
ellipse.addEllipse(0, 0, 50, 10);
|
ellipse.addEllipse(0, 0, halfLineSpacing * 5, halfLineSpacing);
|
||||||
foreach (const TabletPoint &t, m_points) {
|
foreach (const TabletPoint &t, m_points) {
|
||||||
if (geom.contains(t.pos)) {
|
if (geom.contains(t.pos)) {
|
||||||
QPainterPath pp;
|
QPainterPath pp;
|
||||||
pp.addEllipse(t.pos, 8, 8);
|
pp.addEllipse(t.pos, halfLineSpacing, halfLineSpacing);
|
||||||
QRectF pointBounds(t.pos.x() - 10, t.pos.y() - 10, 20, 20);
|
QRectF pointBounds(t.pos.x() - halfLineSpacing, t.pos.y() - halfLineSpacing, lineSpacing, lineSpacing);
|
||||||
switch (t.type) {
|
switch (t.type) {
|
||||||
case TabletButtonPress:
|
case TabletButtonPress:
|
||||||
p.fillPath(pp, Qt::darkGreen);
|
p.fillPath(pp, Qt::darkGreen);
|
||||||
@ -133,7 +135,7 @@ void EventReportWidget::paintEvent(QPaintEvent *)
|
|||||||
p.drawPath(ellipse);
|
p.drawPath(ellipse);
|
||||||
p.restore();
|
p.restore();
|
||||||
} else {
|
} else {
|
||||||
p.drawEllipse(t.pos, t.pressure * 10.0, t.pressure * 10.0);
|
p.drawEllipse(t.pos, t.pressure * halfLineSpacing, t.pressure * halfLineSpacing);
|
||||||
}
|
}
|
||||||
p.setPen(Qt::white);
|
p.setPen(Qt::white);
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user