Support for relative pointer motion events

Summary:
If KWin interacts with Libinput the RelativePointerManager interface
gets created on the Wayland server. The ForwardInputEventFilter does
forward the relative motion events in addition to the normal motion
events.

In order to properly support the relative motion events as they are
expected by the Wayland protocol the handling of pointer motion events
got slightly adjusted:
* Libinput Pointer event extended by the additional data points
* Libinput Pointer event carries the delta as a QSizeF instead of
QPointF
* PointerInputRedirection adjusted to take a pointer motion event with
more arguments
* Custom QMouseEvent subclass adjusted to carry the additional members

The DebugConsole is adjusted to show the relative motion events in
addition to the global position.

Test Plan:
Verified the manager object is created and verified the
events in DebugConsole. Unfortunately not aware of any test application.

Reviewers: #kwin, #plasma_on_wayland

Subscribers: plasma-devel, kwin

Tags: #plasma_on_wayland, #kwin

Differential Revision: https://phabricator.kde.org/D2979
master
Martin Gräßlin 8 years ago
parent 7843974a8a
commit cc2f4e3240

@ -58,7 +58,7 @@ void InputEventsTest::testInitMouseEvent()
QFETCH(QEvent::Type, type);
// now create our own event
MouseEvent event(type, QPointF(100, 200), Qt::LeftButton, Qt::LeftButton | Qt::RightButton,
Qt::ShiftModifier | Qt::ControlModifier, 300, &d);
Qt::ShiftModifier | Qt::ControlModifier, 300, QSizeF(1, 2), QSizeF(3, 4), quint64(-1), &d);
// and verify the contract of QMouseEvent
QCOMPARE(event.type(), type);
QCOMPARE(event.globalPos(), QPoint(100, 200));
@ -70,6 +70,9 @@ void InputEventsTest::testInitMouseEvent()
QCOMPARE(event.timestamp(), 300ul);
// and our custom argument
QCOMPARE(event.device(), &d);
QCOMPARE(event.delta(), QSizeF(1, 2));
QCOMPARE(event.deltaUnaccelerated(), QSizeF(3, 4));
QCOMPARE(event.timestampMicroseconds(), quint64(-1));
}
void InputEventsTest::testInitKeyEvent_data()

@ -450,11 +450,26 @@ double libinput_event_pointer_get_dy(struct libinput_event_pointer *event)
return event->delta.height();
}
double libinput_event_pointer_get_dx_unaccelerated(struct libinput_event_pointer *event)
{
return event->delta.width();
}
double libinput_event_pointer_get_dy_unaccelerated(struct libinput_event_pointer *event)
{
return event->delta.height();
}
uint32_t libinput_event_pointer_get_time(struct libinput_event_pointer *event)
{
return event->time;
}
uint64_t libinput_event_pointer_get_time_usec(struct libinput_event_pointer *event)
{
return quint64(event->time * 1000);
}
uint32_t libinput_event_pointer_get_button(struct libinput_event_pointer *event)
{
return event->button;

@ -128,6 +128,7 @@ void TestLibinputPointerEvent::testButton()
QTEST(pe->buttonState(), "expectedButtonState");
QCOMPARE(pe->button(), button);
QCOMPARE(pe->time(), time);
QCOMPARE(pe->timeMicroseconds(), quint64(time * 1000));
}
void TestLibinputPointerEvent::testAxis_data()
@ -183,7 +184,7 @@ void TestLibinputPointerEvent::testMotion()
QVERIFY(pe);
QCOMPARE(pe->type(), LIBINPUT_EVENT_POINTER_MOTION);
QCOMPARE(pe->time(), 500u);
QCOMPARE(pe->delta(), QPointF(2.1, 4.5));
QCOMPARE(pe->delta(), QSizeF(2.1, 4.5));
}
void TestLibinputPointerEvent::testAbsoluteMotion()

@ -68,6 +68,11 @@ static QString timestampRow(quint32 timestamp)
return tableRow(i18n("Timestamp"), timestamp);
}
static QString timestampRowUsec(quint64 timestamp)
{
return tableRow(i18n("Timestamp (µsec)"), timestamp);
}
static QString buttonToString(Qt::MouseButton button)
{
switch (button) {
@ -171,14 +176,27 @@ bool DebugConsoleFilter::pointerEvent(QMouseEvent *event, quint32 nativeButton)
text.append(s_tableStart);
switch (event->type()) {
case QEvent::MouseMove:
case QEvent::MouseMove: {
text.append(tableHeaderRow(i18nc("A mouse pointer motion event", "Pointer Motion")));
auto e = static_cast<MouseEvent*>(event);
#if HAVE_INPUT
text.append(deviceRow(static_cast<MouseEvent*>(event)->device()));
text.append(deviceRow(e->device()));
#endif
text.append(timestamp);
if (e->timestampMicroseconds() != 0) {
text.append(timestampRowUsec(e->timestampMicroseconds()));
}
if (e->delta() != QSizeF()) {
text.append(tableRow(i18nc("The relative mouse movement", "Delta"),
QStringLiteral("%1/%2").arg(e->delta().width()).arg(e->delta().height())));
}
if (e->deltaUnaccelerated() != QSizeF()) {
text.append(tableRow(i18nc("The relative mouse movement", "Delta (not accelerated)"),
QStringLiteral("%1/%2").arg(e->deltaUnaccelerated().width()).arg(e->deltaUnaccelerated().height())));
}
text.append(tableRow(i18nc("The global mouse pointer position", "Global Position"), QStringLiteral("%1/%2").arg(event->pos().x()).arg(event->pos().y())));
break;
}
case QEvent::MouseButtonPress:
text.append(tableHeaderRow(i18nc("A mouse pointer button press event", "Pointer Button Press")));
#if HAVE_INPUT

@ -18,6 +18,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "input.h"
#include "input_event.h"
#include "keyboard_input.h"
#include "pointer_input.h"
#include "touch_input.h"
@ -43,6 +44,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <KWayland/Server/display.h>
#include <KWayland/Server/fakeinput_interface.h>
#include <KWayland/Server/seat_interface.h>
#include <KWayland/Server/relativepointer_interface.h>
#include <decorations/decoratedclient.h>
#include <KDecoration2/Decoration>
//screenlocker
@ -892,13 +894,18 @@ public:
auto seat = waylandServer()->seat();
seat->setTimestamp(event->timestamp());
switch (event->type()) {
case QEvent::MouseMove:
case QEvent::MouseMove: {
if (event->buttons() == Qt::NoButton) {
// update pointer window only if no button is pressed
input()->pointer()->update();
}
seat->setPointerPos(event->globalPos());
MouseEvent *e = static_cast<MouseEvent*>(event);
if (e->delta() != QSizeF()) {
seat->relativePointerMotion(e->delta(), e->deltaUnaccelerated(), e->timestampMicroseconds());
}
break;
}
case QEvent::MouseButtonPress:
seat->pointerButtonPressed(nativeButton);
break;
@ -1232,6 +1239,12 @@ void InputRedirection::setupLibInput()
LibInput::Connection *conn = LibInput::Connection::create(this);
m_libInput = conn;
if (conn) {
if (waylandServer()) {
// create relative pointer manager
waylandServer()->display()->createRelativePointerManager(KWayland::Server::RelativePointerInterfaceVersion::UnstableV1, waylandServer()->display())->create();
}
conn->setInputConfig(m_inputConfig);
conn->setup();
connect(conn, &LibInput::Connection::eventsRead, this,
@ -1251,8 +1264,8 @@ void InputRedirection::setupLibInput()
connect(conn, &LibInput::Connection::swipeGestureCancelled, m_pointer, &PointerInputRedirection::processSwipeGestureCancelled);
connect(conn, &LibInput::Connection::keyChanged, m_keyboard, &KeyboardInputRedirection::processKey);
connect(conn, &LibInput::Connection::pointerMotion, this,
[this] (QPointF delta, uint32_t time, LibInput::Device *device) {
m_pointer->processMotion(m_pointer->pos() + delta, time, device);
[this] (const QSizeF &delta, const QSizeF &deltaNonAccel, uint32_t time, quint64 timeMicroseconds, LibInput::Device *device) {
m_pointer->processMotion(m_pointer->pos() + QPointF(delta.width(), delta.height()), delta, deltaNonAccel, time, timeMicroseconds, device);
}
);
connect(conn, &LibInput::Connection::pointerMotionAbsolute, this,

@ -24,8 +24,12 @@ namespace KWin
MouseEvent::MouseEvent(QEvent::Type type, const QPointF &pos, Qt::MouseButton button,
Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers,
quint32 timestamp, LibInput::Device *device)
quint32 timestamp, const QSizeF &delta, const QSizeF &deltaNonAccelerated,
quint64 timestampMicroseconds, LibInput::Device *device)
: QMouseEvent(type, pos, pos, button, buttons, modifiers)
, m_delta(delta)
, m_deltaUnccelerated(deltaNonAccelerated)
, m_timestampMicroseconds(timestampMicroseconds)
, m_device(device)
{
setTimestamp(timestamp);

@ -33,13 +33,30 @@ class MouseEvent : public QMouseEvent
{
public:
explicit MouseEvent(QEvent::Type type, const QPointF &pos, Qt::MouseButton button, Qt::MouseButtons buttons,
Qt::KeyboardModifiers modifiers, quint32 timestamp, LibInput::Device *device);
Qt::KeyboardModifiers modifiers, quint32 timestamp,
const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 timestampMicroseconds,
LibInput::Device *device);
QSizeF delta() const {
return m_delta;
}
QSizeF deltaUnaccelerated() const {
return m_deltaUnccelerated;
}
quint64 timestampMicroseconds() const {
return m_timestampMicroseconds;
}
LibInput::Device *device() const {
return m_device;
}
private:
QSizeF m_delta;
QSizeF m_deltaUnccelerated;
quint64 m_timestampMicroseconds;
LibInput::Device *m_device;
};

@ -328,20 +328,24 @@ void Connection::processEvents()
}
case LIBINPUT_EVENT_POINTER_MOTION: {
PointerEvent *pe = static_cast<PointerEvent*>(event.data());
QPointF delta = pe->delta();
auto delta = pe->delta();
auto deltaNonAccel = pe->deltaUnaccelerated();
quint32 latestTime = pe->time();
quint64 latestTimeUsec = pe->timeMicroseconds();
auto it = m_eventQueue.begin();
while (it != m_eventQueue.end()) {
if ((*it)->type() == LIBINPUT_EVENT_POINTER_MOTION) {
QScopedPointer<PointerEvent> p(static_cast<PointerEvent*>(*it));
delta += p->delta();
deltaNonAccel += p->deltaUnaccelerated();
latestTime = p->time();
latestTimeUsec = p->timeMicroseconds();
it = m_eventQueue.erase(it);
} else {
break;
}
}
emit pointerMotion(delta, latestTime, pe->device());
emit pointerMotion(delta, deltaNonAccel, latestTime, latestTimeUsec, pe->device());
break;
}
case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: {

@ -86,7 +86,7 @@ Q_SIGNALS:
void keyChanged(quint32 key, KWin::InputRedirection::KeyboardKeyState, quint32 time, KWin::LibInput::Device *device);
void pointerButtonChanged(quint32 button, KWin::InputRedirection::PointerButtonState state, quint32 time, KWin::LibInput::Device *device);
void pointerMotionAbsolute(QPointF orig, QPointF screen, quint32 time, KWin::LibInput::Device *device);
void pointerMotion(QPointF delta, quint32 time, KWin::LibInput::Device *device);
void pointerMotion(const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint32 time, quint64 timeMicroseconds, KWin::LibInput::Device *device);
void pointerAxisChanged(KWin::InputRedirection::PointerAxis axis, qreal delta, quint32 time, KWin::LibInput::Device *device);
void touchFrame(KWin::LibInput::Device *device);
void touchCanceled(KWin::LibInput::Device *device);

@ -133,10 +133,16 @@ QPointF PointerEvent::absolutePos(const QSize &size) const
libinput_event_pointer_get_absolute_y_transformed(m_pointerEvent, size.height()));
}
QPointF PointerEvent::delta() const
QSizeF PointerEvent::delta() const
{
Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_MOTION);
return QPointF(libinput_event_pointer_get_dx(m_pointerEvent), libinput_event_pointer_get_dy(m_pointerEvent));
return QSizeF(libinput_event_pointer_get_dx(m_pointerEvent), libinput_event_pointer_get_dy(m_pointerEvent));
}
QSizeF PointerEvent::deltaUnaccelerated() const
{
Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_MOTION);
return QSizeF(libinput_event_pointer_get_dx_unaccelerated(m_pointerEvent), libinput_event_pointer_get_dy_unaccelerated(m_pointerEvent));
}
uint32_t PointerEvent::time() const
@ -144,6 +150,11 @@ uint32_t PointerEvent::time() const
return libinput_event_pointer_get_time(m_pointerEvent);
}
quint64 PointerEvent::timeMicroseconds() const
{
return libinput_event_pointer_get_time_usec(m_pointerEvent);
}
uint32_t PointerEvent::button() const
{
Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_BUTTON);

@ -89,10 +89,12 @@ public:
QPointF absolutePos() const;
QPointF absolutePos(const QSize &size) const;
QPointF delta() const;
QSizeF delta() const;
QSizeF deltaUnaccelerated() const;
uint32_t button() const;
InputRedirection::PointerButtonState buttonState() const;
uint32_t time() const;
quint64 timeMicroseconds() const;
QVector<InputRedirection::PointerAxis> axis() const;
qreal axisValue(InputRedirection::PointerAxis a) const;

@ -161,13 +161,19 @@ void PointerInputRedirection::init()
}
void PointerInputRedirection::processMotion(const QPointF &pos, uint32_t time, LibInput::Device *device)
{
processMotion(pos, QSizeF(), QSizeF(), time, 0, device);
}
void PointerInputRedirection::processMotion(const QPointF &pos, const QSizeF &delta, const QSizeF &deltaNonAccelerated, uint32_t time, quint64 timeUsec, LibInput::Device *device)
{
if (!m_inited) {
return;
}
updatePosition(pos);
MouseEvent event(QEvent::MouseMove, m_pos, Qt::NoButton, m_qtButtons,
m_input->keyboardModifiers(), time, device);
m_input->keyboardModifiers(), time,
delta, deltaNonAccelerated, timeUsec, device);
const auto &filters = m_input->filters();
for (auto it = filters.begin(), end = filters.end(); it != end; it++) {
@ -199,7 +205,7 @@ void PointerInputRedirection::processButton(uint32_t button, InputRedirection::P
}
MouseEvent event(type, m_pos, buttonToQtMouseButton(button), m_qtButtons,
m_input->keyboardModifiers(), time, device);
m_input->keyboardModifiers(), time, QSizeF(), QSizeF(), 0, device);
const auto &filters = m_input->filters();
for (auto it = filters.begin(), end = filters.end(); it != end; it++) {

@ -86,6 +86,10 @@ public:
* @internal
*/
void processMotion(const QPointF &pos, uint32_t time, LibInput::Device *device = nullptr);
/**
* @internal
**/
void processMotion(const QPointF &pos, const QSizeF &delta, const QSizeF &deltaNonAccelerated, uint32_t time, quint64 timeUsec, LibInput::Device *device);
/**
* @internal
*/

@ -75,8 +75,8 @@ int main(int argc, char **argv)
}
);
QObject::connect(conn, &Connection::pointerMotion,
[](QPointF delta) {
std::cout << "Got pointer motion: " << delta.x() << "/" << delta.y() << std::endl;
[](const QSizeF &delta) {
std::cout << "Got pointer motion: " << delta.width() << "/" << delta.height() << std::endl;
}
);
QObject::connect(conn, &Connection::pointerAxisChanged,

Loading…
Cancel
Save