Commit ff050263 authored by Dmitry Kazakov's avatar Dmitry Kazakov
Browse files

Fixed the input manager on windows

There are two points there:
1) Windows defers the mouse events generated by the ignored tablet events,
   so the former ones arrive reordered.
2) The flow of tablet move events is too high, so there is a special option
   "hiResInputEvents" introduced in the action to handle it. All the actions
   except painting itself use compressed mouse move events instead.

BUG:306528
parent 5dbc8314
......@@ -85,6 +85,11 @@ void KisAbstractInputAction::mouseMoved(const QPointF &lastPos, const QPointF &p
Q_UNUSED(pos);
}
bool KisAbstractInputAction::supportsHiResInputEvents() const
{
return false;
}
KisInputManager* KisAbstractInputAction::inputManager() const
{
return d->inputManager;
......
......@@ -107,6 +107,15 @@ public:
*/
virtual void inputEvent(QEvent* event);
/**
* On some platforms (Windows in particular), tablet and mouse
* events generate different flows of messages. The amount of
* tablet events may be hard to process for some actions, so it is
* false by default. On Linux platform the flows are exactly the
* same so there is no difference between tablet and mouse events.
*/
virtual bool supportsHiResInputEvents() const;
/**
* The indexes of shortcut behaviours available.
*/
......
......@@ -61,7 +61,7 @@ public:
bool tryHidePopupPalette();
bool trySetMirrorMode(const QPointF &mousePosition);
void saveTabletEvent(const QTabletEvent *event);
void resetSavedTabletEvent();
void resetSavedTabletEvent(QEvent::Type type);
void addStrokeShortcut(KisAbstractInputAction* action, int index,
const QList<Qt::Key> &modifiers,
const QList<Qt::MouseButton> &buttons);
......@@ -283,10 +283,30 @@ void KisInputManager::Private::saveTabletEvent(const QTabletEvent *event)
event->uniqueId());
}
void KisInputManager::Private::resetSavedTabletEvent()
void KisInputManager::Private::resetSavedTabletEvent(QEvent::Type type)
{
delete lastTabletEvent;
lastTabletEvent = 0;
bool needResetSavedEvent = true;
#ifdef Q_OS_WIN
/**
* For linux platform each mouse event corresponds to a single
* tablet event so the saved tablet event is deleted after any
* mouse event.
*
* For windows platform the mouse events get compressed so one
* mouse event may correspond to a few tablet events, so we keep a
* saved tablet event till the end of the stroke, that is till
* mouseRelese event
*/
needResetSavedEvent = type == QEvent::MouseButtonRelease;
#else
Q_UNUSED(type);
#endif
if (needResetSavedEvent) {
delete lastTabletEvent;
lastTabletEvent = 0;
}
}
QTabletEvent* KisInputManager::lastTabletEvent() const
......@@ -344,13 +364,13 @@ bool KisInputManager::eventFilter(QObject* object, QEvent* event)
} else {
retval = d->matcher.buttonPressed(mouseEvent->button(), mouseEvent);
}
d->resetSavedTabletEvent();
d->resetSavedTabletEvent(event->type());
break;
}
case QEvent::MouseButtonRelease: {
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
retval = d->matcher.buttonReleased(mouseEvent->button(), mouseEvent);
d->resetSavedTabletEvent();
d->resetSavedTabletEvent(event->type());
break;
}
case QEvent::KeyPress: {
......@@ -389,7 +409,7 @@ bool KisInputManager::eventFilter(QObject* object, QEvent* event)
d->toolProxy->mouseMoveEvent(mouseEvent, widgetToPixel(mouseEvent->posF()));
}
retval = true;
d->resetSavedTabletEvent();
d->resetSavedTabletEvent(event->type());
break;
}
case QEvent::Wheel: {
......@@ -418,7 +438,22 @@ bool KisInputManager::eventFilter(QObject* object, QEvent* event)
//event.
QTabletEvent* tabletEvent = static_cast<QTabletEvent*>(event);
d->saveTabletEvent(tabletEvent);
#ifdef Q_OS_WIN
if (event->type() == QEvent::TabletMove) {
retval = d->matcher.tabletMoved(static_cast<QTabletEvent*>(event));
}
if (retval) {
event->accept();
} else {
event->ignore();
}
#else
event->ignore();
#endif
break;
}
default:
......
......@@ -19,6 +19,7 @@
#include "kis_shortcut_matcher.h"
#include <QMouseEvent>
#include <QTabletEvent>
#include "kis_abstract_input_action.h"
#include "kis_stroke_shortcut.h"
......@@ -174,6 +175,33 @@ bool KisShortcutMatcher::mouseMoved(QMouseEvent *event)
return true;
}
Qt::MouseButtons listToFlags(const QList<Qt::MouseButton> &list) {
Qt::MouseButtons flags;
foreach (Qt::MouseButton b, list) {
flags |= b;
}
return flags;
}
bool KisShortcutMatcher::tabletMoved(QTabletEvent *event)
{
if (!m_d->runningShortcut) return false;
bool retval = false;
KisAbstractInputAction *action = m_d->runningShortcut->action();
if (action->supportsHiResInputEvents()) {
QMouseEvent mouseEvent(QEvent::MouseMove,
event->pos(),
Qt::NoButton,
listToFlags(m_d->buttons),
event->modifiers());
action->inputEvent(&mouseEvent);
retval = true;
}
return retval;
}
void KisShortcutMatcher::reset()
{
m_d->keys.clear();
......
......@@ -27,6 +27,7 @@
class QMouseEvent;
class QKeyEvent;
class QWheelEvent;
class QTabletEvent;
class KisStrokeShortcut;
class KisAbstractInputAction;
......@@ -154,6 +155,17 @@ public:
*/
bool mouseMoved(QMouseEvent *event);
/**
* Handles the High Resolution tablet events
* (used on Windows only)
*
* \param event the event that caused this call
*
* \return whether the event has been handled successfully and
* should be eaten by the events filter
*/
bool tabletMoved(QTabletEvent *event);
/**
* Resets the internal state of the matcher
*
......
......@@ -130,8 +130,14 @@ void KisToolInvocationAction::inputEvent(QEvent* event)
}
}
bool KisToolInvocationAction::supportsHiResInputEvents() const
{
return true;
}
QPointF KisToolInvocationAction::Private::tabletToPixel(const QPointF &globalPos)
{
const QPointF pos = globalPos - q->inputManager()->canvas()->canvasWidget()->mapToGlobal(QPoint(0, 0));
return q->inputManager()->widgetToPixel(pos);
}
......@@ -42,6 +42,8 @@ public:
void end(QEvent *event);
void inputEvent(QEvent* event);
bool supportsHiResInputEvents() const;
private:
class Private;
Private * const d;
......
......@@ -72,7 +72,7 @@ void KisInputManagerTest::testStrokeShortcut()
struct TestingAction : public KisAbstractInputAction
{
TestingAction() : KisAbstractInputAction(0) { reset(); }
TestingAction() : KisAbstractInputAction(0), m_isHighResolution(false) { reset(); }
~TestingAction() {}
void begin(int shortcut, QEvent *event) { m_beginIndex = shortcut; m_beginNonNull = event;}
......@@ -87,12 +87,21 @@ struct TestingAction : public KisAbstractInputAction
m_endNonNull = false;
}
bool supportsHiResInputEvents() const {
return m_isHighResolution;
}
void setHighResInputEvents(bool value) {
m_isHighResolution = value;
}
int m_beginIndex;
bool m_ended;
bool m_gotInput;
bool m_beginNonNull;
bool m_endNonNull;
bool m_isHighResolution;
};
KisSingleActionShortcut* createKeyShortcut(KisAbstractInputAction *action,
......@@ -344,6 +353,28 @@ void KisInputManagerTest::testMouseMoves()
QCOMPARE(a->m_gotInput, true);
a->reset();
// Check High Resolution events for usual action
QTabletEvent tabletEvent(QEvent::TabletMove, QPoint(), QPoint(), QPointF(),
0, 0, 0.0, 0, 0, 0.0, 0.0, 0, Qt::NoModifier, 0);
QVERIFY(!m.tabletMoved(&tabletEvent));
QCOMPARE(a->m_gotInput, false);
a->reset();
// Check usual events for High Resolution actions
a->setHighResInputEvents(true);
QVERIFY(m.mouseMoved(&mouseEvent));
QCOMPARE(a->m_gotInput, true);
a->reset();
a->setHighResInputEvents(false);
// Check High Resolution for High Resolution actions
a->setHighResInputEvents(true);
QVERIFY(m.tabletMoved(&tabletEvent));
QCOMPARE(a->m_gotInput, true);
a->reset();
a->setHighResInputEvents(false);
// Release Ctrl
QVERIFY(!m.keyReleased(Qt::Key_Control));
QCOMPARE(a->m_beginIndex, -1);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment