7f593a67ad
Summary: So far KWin didn't send axis_source, axis_discrete, and axis_stop. Even though most of those events are optional, clients need them to work as expected. For example, one needs axis_source and axis_stop to implement kinetic scrolling; Xwayland needs axis_discrete to prevent multiple scroll events when the compositor sends axis deltas greater than 10, etc. BUG: 404152 FIXED-IN: 5.17.0 Test Plan: * Content of a webpage in Firefox is moved by one line per each mouse wheel "click"; * Scrolled gedit using 2 fingers on GNOME Shell, sway, and KDE Plasma; in all three cases wayland debug looked the same (except diagonal scroll motions). Reviewers: #kwin, davidedmundson Reviewed By: #kwin, davidedmundson Subscribers: davidedmundson, kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D19000
356 lines
10 KiB
C++
356 lines
10 KiB
C++
/********************************************************************
|
|
KWin - the KDE window manager
|
|
This file is part of the KDE project.
|
|
|
|
Copyright (C) 2014 Martin Gräßlin <mgraesslin@kde.org>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
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 "events.h"
|
|
#include "device.h"
|
|
|
|
#include <QSize>
|
|
|
|
namespace KWin
|
|
{
|
|
namespace LibInput
|
|
{
|
|
|
|
Event *Event::create(libinput_event *event)
|
|
{
|
|
if (!event) {
|
|
return nullptr;
|
|
}
|
|
const auto t = libinput_event_get_type(event);
|
|
// TODO: add touch events
|
|
// TODO: add device notify events
|
|
switch (t) {
|
|
case LIBINPUT_EVENT_KEYBOARD_KEY:
|
|
return new KeyEvent(event);
|
|
case LIBINPUT_EVENT_POINTER_AXIS:
|
|
case LIBINPUT_EVENT_POINTER_BUTTON:
|
|
case LIBINPUT_EVENT_POINTER_MOTION:
|
|
case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
|
|
return new PointerEvent(event, t);
|
|
case LIBINPUT_EVENT_TOUCH_DOWN:
|
|
case LIBINPUT_EVENT_TOUCH_UP:
|
|
case LIBINPUT_EVENT_TOUCH_MOTION:
|
|
case LIBINPUT_EVENT_TOUCH_CANCEL:
|
|
case LIBINPUT_EVENT_TOUCH_FRAME:
|
|
return new TouchEvent(event, t);
|
|
case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN:
|
|
case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
|
|
case LIBINPUT_EVENT_GESTURE_SWIPE_END:
|
|
return new SwipeGestureEvent(event, t);
|
|
case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN:
|
|
case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE:
|
|
case LIBINPUT_EVENT_GESTURE_PINCH_END:
|
|
return new PinchGestureEvent(event, t);
|
|
case LIBINPUT_EVENT_SWITCH_TOGGLE:
|
|
return new SwitchEvent(event, t);
|
|
default:
|
|
return new Event(event, t);
|
|
}
|
|
}
|
|
|
|
Event::Event(libinput_event *event, libinput_event_type type)
|
|
: m_event(event)
|
|
, m_type(type)
|
|
, m_device(nullptr)
|
|
{
|
|
}
|
|
|
|
Event::~Event()
|
|
{
|
|
libinput_event_destroy(m_event);
|
|
}
|
|
|
|
Device *Event::device() const
|
|
{
|
|
if (!m_device) {
|
|
m_device = Device::getDevice(libinput_event_get_device(m_event));
|
|
}
|
|
return m_device;
|
|
}
|
|
|
|
libinput_device *Event::nativeDevice() const
|
|
{
|
|
if (m_device) {
|
|
return m_device->device();
|
|
}
|
|
return libinput_event_get_device(m_event);
|
|
}
|
|
|
|
KeyEvent::KeyEvent(libinput_event *event)
|
|
: Event(event, LIBINPUT_EVENT_KEYBOARD_KEY)
|
|
, m_keyboardEvent(libinput_event_get_keyboard_event(event))
|
|
{
|
|
}
|
|
|
|
KeyEvent::~KeyEvent() = default;
|
|
|
|
uint32_t KeyEvent::key() const
|
|
{
|
|
return libinput_event_keyboard_get_key(m_keyboardEvent);
|
|
}
|
|
|
|
InputRedirection::KeyboardKeyState KeyEvent::state() const
|
|
{
|
|
switch (libinput_event_keyboard_get_key_state(m_keyboardEvent)) {
|
|
case LIBINPUT_KEY_STATE_PRESSED:
|
|
return InputRedirection::KeyboardKeyPressed;
|
|
case LIBINPUT_KEY_STATE_RELEASED:
|
|
return InputRedirection::KeyboardKeyReleased;
|
|
}
|
|
abort();
|
|
}
|
|
|
|
uint32_t KeyEvent::time() const
|
|
{
|
|
return libinput_event_keyboard_get_time(m_keyboardEvent);
|
|
}
|
|
|
|
PointerEvent::PointerEvent(libinput_event *event, libinput_event_type type)
|
|
: Event(event, type)
|
|
, m_pointerEvent(libinput_event_get_pointer_event(event))
|
|
{
|
|
}
|
|
|
|
PointerEvent::~PointerEvent() = default;
|
|
|
|
QPointF PointerEvent::absolutePos() const
|
|
{
|
|
Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE);
|
|
return QPointF(libinput_event_pointer_get_absolute_x(m_pointerEvent),
|
|
libinput_event_pointer_get_absolute_y(m_pointerEvent));
|
|
}
|
|
|
|
QPointF PointerEvent::absolutePos(const QSize &size) const
|
|
{
|
|
Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE);
|
|
return QPointF(libinput_event_pointer_get_absolute_x_transformed(m_pointerEvent, size.width()),
|
|
libinput_event_pointer_get_absolute_y_transformed(m_pointerEvent, size.height()));
|
|
}
|
|
|
|
QSizeF PointerEvent::delta() const
|
|
{
|
|
Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_MOTION);
|
|
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
|
|
{
|
|
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);
|
|
return libinput_event_pointer_get_button(m_pointerEvent);
|
|
}
|
|
|
|
InputRedirection::PointerButtonState PointerEvent::buttonState() const
|
|
{
|
|
Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_BUTTON);
|
|
switch (libinput_event_pointer_get_button_state(m_pointerEvent)) {
|
|
case LIBINPUT_BUTTON_STATE_PRESSED:
|
|
return InputRedirection::PointerButtonPressed;
|
|
case LIBINPUT_BUTTON_STATE_RELEASED:
|
|
return InputRedirection::PointerButtonReleased;
|
|
}
|
|
abort();
|
|
}
|
|
|
|
QVector<InputRedirection::PointerAxis> PointerEvent::axis() const
|
|
{
|
|
Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_AXIS);
|
|
QVector<InputRedirection::PointerAxis> a;
|
|
if (libinput_event_pointer_has_axis(m_pointerEvent, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) {
|
|
a << InputRedirection::PointerAxisHorizontal;
|
|
}
|
|
if (libinput_event_pointer_has_axis(m_pointerEvent, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) {
|
|
a << InputRedirection::PointerAxisVertical;
|
|
}
|
|
return a;
|
|
}
|
|
|
|
qreal PointerEvent::axisValue(InputRedirection::PointerAxis axis) const
|
|
{
|
|
Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_AXIS);
|
|
const libinput_pointer_axis a = axis == InputRedirection::PointerAxisHorizontal
|
|
? LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL
|
|
: LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
|
|
return libinput_event_pointer_get_axis_value(m_pointerEvent, a);
|
|
}
|
|
|
|
qint32 PointerEvent::discreteAxisValue(InputRedirection::PointerAxis axis) const
|
|
{
|
|
Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_AXIS);
|
|
const libinput_pointer_axis a = (axis == InputRedirection::PointerAxisHorizontal)
|
|
? LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL
|
|
: LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
|
|
return libinput_event_pointer_get_axis_value_discrete(m_pointerEvent, a);
|
|
}
|
|
|
|
InputRedirection::PointerAxisSource PointerEvent::axisSource() const
|
|
{
|
|
Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_AXIS);
|
|
switch (libinput_event_pointer_get_axis_source(m_pointerEvent)) {
|
|
case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL:
|
|
return InputRedirection::PointerAxisSourceWheel;
|
|
case LIBINPUT_POINTER_AXIS_SOURCE_FINGER:
|
|
return InputRedirection::PointerAxisSourceFinger;
|
|
case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS:
|
|
return InputRedirection::PointerAxisSourceContinuous;
|
|
case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL_TILT:
|
|
return InputRedirection::PointerAxisSourceWheelTilt;
|
|
default:
|
|
return InputRedirection::PointerAxisSourceUnknown;
|
|
}
|
|
}
|
|
|
|
TouchEvent::TouchEvent(libinput_event *event, libinput_event_type type)
|
|
: Event(event, type)
|
|
, m_touchEvent(libinput_event_get_touch_event(event))
|
|
{
|
|
}
|
|
|
|
TouchEvent::~TouchEvent() = default;
|
|
|
|
quint32 TouchEvent::time() const
|
|
{
|
|
return libinput_event_touch_get_time(m_touchEvent);
|
|
}
|
|
|
|
QPointF TouchEvent::absolutePos() const
|
|
{
|
|
Q_ASSERT(type() == LIBINPUT_EVENT_TOUCH_DOWN || type() == LIBINPUT_EVENT_TOUCH_MOTION);
|
|
return QPointF(libinput_event_touch_get_x(m_touchEvent),
|
|
libinput_event_touch_get_y(m_touchEvent));
|
|
}
|
|
|
|
QPointF TouchEvent::absolutePos(const QSize &size) const
|
|
{
|
|
Q_ASSERT(type() == LIBINPUT_EVENT_TOUCH_DOWN || type() == LIBINPUT_EVENT_TOUCH_MOTION);
|
|
return QPointF(libinput_event_touch_get_x_transformed(m_touchEvent, size.width()),
|
|
libinput_event_touch_get_y_transformed(m_touchEvent, size.height()));
|
|
}
|
|
|
|
qint32 TouchEvent::id() const
|
|
{
|
|
Q_ASSERT(type() != LIBINPUT_EVENT_TOUCH_CANCEL && type() != LIBINPUT_EVENT_TOUCH_FRAME);
|
|
|
|
const qint32 slot = libinput_event_touch_get_slot(m_touchEvent);
|
|
|
|
return slot == -1 ? 0 : slot;
|
|
}
|
|
|
|
GestureEvent::GestureEvent(libinput_event *event, libinput_event_type type)
|
|
: Event(event, type)
|
|
, m_gestureEvent(libinput_event_get_gesture_event(event))
|
|
{
|
|
}
|
|
|
|
GestureEvent::~GestureEvent() = default;
|
|
|
|
quint32 GestureEvent::time() const
|
|
{
|
|
return libinput_event_gesture_get_time(m_gestureEvent);
|
|
}
|
|
|
|
int GestureEvent::fingerCount() const
|
|
{
|
|
return libinput_event_gesture_get_finger_count(m_gestureEvent);
|
|
}
|
|
|
|
QSizeF GestureEvent::delta() const
|
|
{
|
|
return QSizeF(libinput_event_gesture_get_dx(m_gestureEvent),
|
|
libinput_event_gesture_get_dy(m_gestureEvent));
|
|
}
|
|
|
|
bool GestureEvent::isCancelled() const
|
|
{
|
|
return libinput_event_gesture_get_cancelled(m_gestureEvent) != 0;
|
|
}
|
|
|
|
PinchGestureEvent::PinchGestureEvent(libinput_event *event, libinput_event_type type)
|
|
: GestureEvent(event, type)
|
|
{
|
|
}
|
|
|
|
PinchGestureEvent::~PinchGestureEvent() = default;
|
|
|
|
qreal PinchGestureEvent::scale() const
|
|
{
|
|
return libinput_event_gesture_get_scale(m_gestureEvent);
|
|
}
|
|
|
|
qreal PinchGestureEvent::angleDelta() const
|
|
{
|
|
return libinput_event_gesture_get_angle_delta(m_gestureEvent);
|
|
}
|
|
|
|
SwipeGestureEvent::SwipeGestureEvent(libinput_event *event, libinput_event_type type)
|
|
: GestureEvent(event, type)
|
|
{
|
|
}
|
|
|
|
SwipeGestureEvent::~SwipeGestureEvent() = default;
|
|
|
|
SwitchEvent::SwitchEvent(libinput_event *event, libinput_event_type type)
|
|
: Event(event, type)
|
|
, m_switchEvent(libinput_event_get_switch_event(event))
|
|
{
|
|
}
|
|
|
|
SwitchEvent::~SwitchEvent() = default;
|
|
|
|
SwitchEvent::State SwitchEvent::state() const
|
|
{
|
|
switch (libinput_event_switch_get_switch_state(m_switchEvent))
|
|
{
|
|
case LIBINPUT_SWITCH_STATE_OFF:
|
|
return State::Off;
|
|
case LIBINPUT_SWITCH_STATE_ON:
|
|
return State::On;
|
|
default:
|
|
Q_UNREACHABLE();
|
|
}
|
|
return State::Off;
|
|
}
|
|
|
|
quint32 SwitchEvent::time() const
|
|
{
|
|
return libinput_event_switch_get_time(m_switchEvent);
|
|
}
|
|
|
|
quint64 SwitchEvent::timeMicroseconds() const
|
|
{
|
|
return libinput_event_switch_get_time_usec(m_switchEvent);
|
|
}
|
|
|
|
}
|
|
}
|