bool WWidget::event(QEvent* e) { if (e->type() == QEvent::ToolTip) { updateTooltip(); } else if (isEnabled()) { switch(e->type()) { case QEvent::TouchBegin: case QEvent::TouchUpdate: case QEvent::TouchEnd: { QTouchEvent* touchEvent = dynamic_cast<QTouchEvent*>(e); if (touchEvent->deviceType() != QTouchEvent::TouchScreen) { break; } // fake a mouse event! QEvent::Type eventType = QEvent::None; switch (touchEvent->type()) { case QEvent::TouchBegin: eventType = QEvent::MouseButtonPress; if (touchIsRightButton()) { // touch is right click m_activeTouchButton = Qt::RightButton; } else { m_activeTouchButton = Qt::LeftButton; } break; case QEvent::TouchUpdate: eventType = QEvent::MouseMove; break; case QEvent::TouchEnd: eventType = QEvent::MouseButtonRelease; break; default: DEBUG_ASSERT(false); break; } const QTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().first(); QMouseEvent mouseEvent(eventType, touchPoint.pos().toPoint(), touchPoint.screenPos().toPoint(), m_activeTouchButton, // Button that causes the event Qt::NoButton, // Not used, so no need to fake a proper value. touchEvent->modifiers()); return QWidget::event(&mouseEvent); } default: break; } } return QWidget::event(e); }
bool KisToolProxy::forwardEvent(ActionState state, KisTool::ToolAction action, QEvent *event, QEvent *originalEvent, QTabletEvent *lastTabletEvent, const QPoint &canvasOriginWorkaround) { bool retval = true; QTabletEvent *tabletEvent = dynamic_cast<QTabletEvent*>(event); QTouchEvent *touchEvent = dynamic_cast<QTouchEvent*>(event); QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent*>(event); if (tabletEvent) { QPointF docPoint = tabletToDocument(tabletEvent->hiResGlobalPos(), canvasOriginWorkaround); tabletEvent->accept(); this->tabletEvent(tabletEvent, docPoint); forwardToTool(state, action, tabletEvent, docPoint); retval = tabletEvent->isAccepted(); } else if (touchEvent) { if (state == END && touchEvent->type() != QEvent::TouchEnd) { //Fake a touch end if we are "upgrading" a single-touch gesture to a multi-touch gesture. QTouchEvent fakeEvent(QEvent::TouchEnd, touchEvent->deviceType(), touchEvent->modifiers(), touchEvent->touchPointStates(), touchEvent->touchPoints()); this->touchEvent(&fakeEvent); } else { this->touchEvent(touchEvent); } } else if (mouseEvent) { if (lastTabletEvent) { QPointF docPoint = tabletToDocument(lastTabletEvent->hiResGlobalPos(), canvasOriginWorkaround); lastTabletEvent->accept(); this->tabletEvent(lastTabletEvent, docPoint); forwardToTool(state, action, lastTabletEvent, docPoint); retval = lastTabletEvent->isAccepted(); } else { QPointF docPoint = widgetToDocument(mouseEvent->posF()); mouseEvent->accept(); if (mouseEvent->type() == QEvent::MouseButtonPress) { mousePressEvent(mouseEvent, docPoint); } else if (mouseEvent->type() == QEvent::MouseButtonDblClick) { mouseDoubleClickEvent(mouseEvent, docPoint); } else if (mouseEvent->type() == QEvent::MouseButtonRelease) { mouseReleaseEvent(mouseEvent, docPoint); } else if (mouseEvent->type() == QEvent::MouseMove) { mouseMoveEvent(mouseEvent, docPoint); } forwardToTool(state, action, originalEvent, docPoint); retval = mouseEvent->isAccepted(); } } else if(event->type() == QEvent::KeyPress) { QKeyEvent* kevent = static_cast<QKeyEvent*>(event); keyPressEvent(kevent); } else if(event->type() == QEvent::KeyRelease) { QKeyEvent* kevent = static_cast<QKeyEvent*>(event); keyReleaseEvent(kevent); } return retval; }
// override QApplication::notify() for greatest control over event handling bool TouchApplication::notify(QObject* receiver, QEvent* event) { //DebugEventFilter::printEvent(receiver, event); QEvent::Type evtype = event->type(); // first, try to pass TabletPress/TouchBegin event and see if anyone accepts it // In Qt, events are first sent to a QWindow, which then figures out what widget they should be sent to. // Unfortunately, QWindow event handler always returns true and doesn't change accepted state of event (it // sends a copy of the event and discards the accepted state of the copy), so we must save result from // sending event to final widget (by incrementing acceptCount) // When faking mouse events, we must send them to the QWindow instead of a widget, since some of the // routing logic is there, e.g., for handling popup windows if((evtype == QEvent::TabletPress || evtype == QEvent::TouchBegin) && inputState == None) { if(receiver->isWindowType()) { int prevacceptcount = acceptCount; receiver = getRecvWindow(receiver); QApplication::notify(receiver, event); if(acceptCount > prevacceptcount) { acceptCount = prevacceptcount; inputState = PassThru; return true; } // else, fall through and resend as mouse event // we must send a tablet release to put QWidgetWindow in consistent state // doesn't appear to be necessary for TouchBegin if(evtype == QEvent::TabletPress) { QTabletEvent* tev = static_cast<QTabletEvent*>(event); QTabletEvent rlev(QEvent::TabletRelease, tev->posF(), tev->globalPosF(), tev->device(), tev->pointerType(), 0, 0, 0, 0, 0, 0, tev->modifiers(), tev->uniqueId()); QApplication::notify(receiver, &rlev); } } else { event->setAccepted(false); bool res = QApplication::notify(receiver, event); if(event->isAccepted()) acceptCount++; return res; } } switch(evtype) { // reject external mouse events if we are translating touch or tablet input case QEvent::MouseButtonRelease: case QEvent::MouseMove: case QEvent::MouseButtonPress: // QWidgetWindow always forwards mouse event to widget as spontaneous event (why?) if(inputState != None && event->spontaneous() && receiver->isWindowType()) return true; // qDebug("This event should be rejected!"); break; case QEvent::TabletRelease: if(inputState == PassThru) inputState = None; case QEvent::TabletMove: case QEvent::TabletPress: { // TODO: should this only be done if inputState == TabletInput? receiver = getRecvWindow(receiver); QTabletEvent* tabletevent = static_cast<QTabletEvent*>(event); QEvent::Type mevtype = QEvent::MouseMove; if(inputState == None && evtype == QEvent::TabletPress) { mevtype = QEvent::MouseButtonPress; inputState = TabletInput; } else if(inputState != TabletInput) // this covers PassThru break; if(evtype == QEvent::TabletRelease) { mevtype = QEvent::MouseButtonRelease; inputState = None; } return sendMouseEvent(receiver, mevtype, tabletevent->globalPos(), tabletevent->modifiers()); } #ifdef QT_5 case QEvent::TouchCancel: evtype = QEvent::TouchEnd; #endif case QEvent::TouchEnd: if(inputState == PassThru) // && touchPoints.count() == 1) inputState = None; case QEvent::TouchUpdate: case QEvent::TouchBegin: { receiver = getRecvWindow(receiver); QTouchEvent* touchevent = static_cast<QTouchEvent*>(event); QEvent::Type mevtype = QEvent::MouseMove; if(inputState == None && evtype == QEvent::TouchBegin && touchevent->touchPoints().size() == 1 && touchevent->device()->type() != QTouchDevice::TouchPad) { activeTouchId = touchevent->touchPoints().first().id(); mevtype = QEvent::MouseButtonPress; inputState = TouchInput; } else if(inputState != TouchInput) // this covers PassThru break; if(evtype == QEvent::TouchEnd) inputState = None; event->setAccepted(true); QList<QTouchEvent::TouchPoint> touchPoints = touchevent->touchPoints(); for(int ii = 0; ii < touchPoints.count(); ++ii) { const QTouchEvent::TouchPoint& touchpt = touchPoints.at(ii); if(touchpt.id() == activeTouchId) { if(touchpt.state() == Qt::TouchPointReleased) { mevtype = QEvent::MouseButtonRelease; activeTouchId = -1; } return sendMouseEvent(receiver, mevtype, touchpt.screenPos().toPoint(), touchevent->modifiers()); } } // swallow all touch events until TouchEnd // another option would be to propagate the touch event with the activeTouchId point removed, if >1 point return true; } default: break; } return QApplication::notify(receiver, event); }
bool MixxxApplication::notify(QObject* target, QEvent* event) { switch (event->type()) { case QEvent::TouchBegin: case QEvent::TouchUpdate: case QEvent::TouchEnd: { QTouchEvent* touchEvent = static_cast<QTouchEvent*>(event); QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints(); QEvent::Type eventType = QEvent::None; Qt::MouseButtons buttons = Qt::NoButton; QWidget* fakeMouseWidget = NULL; bool baseReturn; //qDebug() << "&" << touchEvent->type() << target; if (touchEvent->deviceType() != QTouchEvent::TouchScreen) { break; } switch (event->type()) { case QEvent::TouchBegin: // try to deliver as touch event baseReturn = QApplication::notify(target, event); if (dynamic_cast<MixxxMainWindow*>(touchEvent->widget())) { // the touchEvent has fallen trough to the MixxxMainWindow, because there // was no touch enabled widget found. // Now we resent this event and all following events for this touch point // as Mouse events. eventType = QEvent::MouseButtonPress; if (touchIsRightButton()) { // touch is right click m_activeTouchButton = Qt::RightButton; buttons = Qt::RightButton; } else { m_activeTouchButton = Qt::LeftButton; buttons = Qt::LeftButton; } m_fakeMouseSourcePointId = touchPoints.first().id(); m_fakeMouseWidget = dynamic_cast<QWidget*>(target); fakeMouseWidget = m_fakeMouseWidget; break; } return baseReturn; case QEvent::TouchUpdate: if (m_fakeMouseWidget) { eventType = QEvent::MouseMove; buttons = m_activeTouchButton; fakeMouseWidget = m_fakeMouseWidget; break; } return QApplication::notify(target, event); case QEvent::TouchEnd: if (m_fakeMouseWidget) { eventType = QEvent::MouseButtonRelease; m_fakeMouseSourcePointId = touchPoints.first().id(); fakeMouseWidget = m_fakeMouseWidget; m_fakeMouseWidget = NULL; break; } return QApplication::notify(target, event); default: return QApplication::notify(target, event); } for (int i = 0; i < touchPoints.count(); ++i) { const QTouchEvent::TouchPoint& touchPoint = touchPoints.at(i); if (touchPoint.id() == m_fakeMouseSourcePointId) { QMouseEvent mouseEvent(eventType, fakeMouseWidget->mapFromGlobal(touchPoint.screenPos().toPoint()), touchPoint.screenPos().toPoint(), m_activeTouchButton, // Button that causes the event buttons, touchEvent->modifiers()); //qDebug() << "#" << mouseEvent.type() << mouseEvent.button() << mouseEvent.buttons() << mouseEvent.pos() << mouseEvent.globalPos(); //if (m_fakeMouseWidget->focusPolicy() & Qt::ClickFocus) { // fakeMouseWidget->setFocus(); //} QApplication::notify(fakeMouseWidget, &mouseEvent); return true; } } //qDebug() << "return false"; return false; break; } case QEvent::MouseButtonRelease: { bool ret = QApplication::notify(target, event); if (m_fakeMouseWidget) { // It may happen the faked mouse event was grabbed by a non touch window. // eg.: if we have started to drag by touch. // In this case X11 generates a MouseButtonRelease instead of a TouchPointReleased Event. // QApplication still tracks the Touch point and prevent touch to other widgets // So we need to fake the Touch release event as well to clean up // QApplicationPrivate::widgetForTouchPointId and QApplicationPrivate::appCurrentTouchPoints; m_fakeMouseWidget = NULL; // Disable MouseButtonRelease fake QList<QTouchEvent::TouchPoint> touchPoints; QTouchEvent::TouchPoint tp; tp.setId(m_fakeMouseSourcePointId); tp.setState(Qt::TouchPointReleased); touchPoints.append(tp); qt_translateRawTouchEvent(NULL, QTouchEvent::TouchScreen, touchPoints); } return ret; } default: break; } // No touch event bool ret = QApplication::notify(target, event); return ret; }