Initial support for libinput

Libinput is an optional dependency for getting low level input events.
As opening the input devices requires root privs this is rather
pointless in the current state. But there is a small added test app which
can be executed with root privs to demonstrate the functionality. To
properly get input events we need a wrapper like it's used in weston.

So far the following is setup:
* opening devices found by udev
* forwarding keyboard events to InputRedirection
* forwarding pointer button events to InputRedirection
* forwarding pointer axis events to InputRedirection
* signals emitted for pointer motion events

Pointer motion events need some further work as they are provided
as delta events. We need to track that and map them properly.

Also missing are touch events due to me not having a touch screen.
It should be fairly simple to setup the touch events, though.

Also hotplugging of devices is not yet implemented.
This commit is contained in:
Martin Gräßlin 2014-08-14 14:43:57 +02:00
parent 075422fc5e
commit c4bb3d11fc
13 changed files with 964 additions and 0 deletions

View file

@ -147,6 +147,20 @@ set_package_properties(XKB PROPERTIES
PURPOSE "Required for building KWin with Wayland support"
)
find_package(Libinput 0.5)
set_package_properties(Libinput PROPERTIES TYPE OPTIONAL PURPOSE "Required for input handling on Wayland.")
find_package(UDev)
set_package_properties(UDev PROPERTIES URL "http://www.freedesktop.org/software/systemd/libudev/"
DESCRIPTION "Linux device library."
TYPE OPTIONAL
PURPOSE "Required for input handling on Wayland."
)
set(HAVE_INPUT FALSE)
if (Libinput_FOUND AND UDEV_FOUND)
set(HAVE_INPUT TRUE)
endif()
find_package(X11)
set_package_properties(X11 PROPERTIES DESCRIPTION "X11 libraries"
URL "http://www.x.org"
@ -410,6 +424,15 @@ if(HAVE_WAYLAND)
endif()
endif()
if(HAVE_INPUT)
set(kwin_KDEINIT_SRCS
${kwin_KDEINIT_SRCS}
libinput/context.cpp
libinput/connection.cpp
libinput/events.cpp
)
endif()
kconfig_add_kcfg_files(kwin_KDEINIT_SRCS settings.kcfgc)
qt5_add_dbus_adaptor( kwin_KDEINIT_SRCS org.kde.KWin.xml dbusinterface.h KWin::DBusInterface )
@ -515,6 +538,10 @@ if(HAVE_WAYLAND)
endif()
endif()
if(HAVE_INPUT)
set(kwinLibs ${kwinLibs} Libinput::Libinput ${UDEV_LIBS})
endif()
add_library(kwin SHARED ${kwin_KDEINIT_SRCS})
set_target_properties(kwin PROPERTIES

View file

@ -0,0 +1,125 @@
#.rst:
# FindLibinput
# -------
#
# Try to find libinput on a Unix system.
#
# This will define the following variables:
#
# ``Libinput_FOUND``
# True if (the requested version of) libinput is available
# ``Libinput_VERSION``
# The version of libinput
# ``Libinput_LIBRARIES``
# This can be passed to target_link_libraries() instead of the ``Libinput::Libinput``
# target
# ``Libinput_INCLUDE_DIRS``
# This should be passed to target_include_directories() if the target is not
# used for linking
# ``Libinput_DEFINITIONS``
# This should be passed to target_compile_options() if the target is not
# used for linking
#
# If ``Libinput_FOUND`` is TRUE, it will also define the following imported target:
#
# ``Libinput::Libinput``
# The libinput library
#
# In general we recommend using the imported target, as it is easier to use.
# Bear in mind, however, that if the target is in the link interface of an
# exported library, it must be made available by the package config file.
#=============================================================================
# Copyright 2014 Alex Merry <alex.merry@kde.org>
# Copyright 2014 Martin Gräßlin <mgraesslin@kde.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. The name of the author may not be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#=============================================================================
if(CMAKE_VERSION VERSION_LESS 2.8.12)
message(FATAL_ERROR "CMake 2.8.12 is required by FindLibinput.cmake")
endif()
if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.12)
message(AUTHOR_WARNING "Your project should require at least CMake 2.8.12 to use FindLibinput.cmake")
endif()
if(NOT WIN32)
# Use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
find_package(PkgConfig)
pkg_check_modules(PKG_Libinput QUIET libinput)
set(Libinput_DEFINITIONS ${PKG_Libinput_CFLAGS_OTHER})
set(Libinput_VERSION ${PKG_Libinput_VERSION})
find_path(Libinput_INCLUDE_DIR
NAMES
libinput.h
HINTS
${PKG_Libinput_INCLUDE_DIRS}
)
find_library(Libinput_LIBRARY
NAMES
input
HINTS
${PKG_Libinput_LIBRARY_DIRS}
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Libinput
FOUND_VAR
Libinput_FOUND
REQUIRED_VARS
Libinput_LIBRARY
Libinput_INCLUDE_DIR
VERSION_VAR
Libinput_VERSION
)
if(Libinput_FOUND AND NOT TARGET Libinput::Libinput)
add_library(Libinput::Libinput UNKNOWN IMPORTED)
set_target_properties(Libinput::Libinput PROPERTIES
IMPORTED_LOCATION "${Libinput_LIBRARY}"
INTERFACE_COMPILE_OPTIONS "${Libinput_DEFINITIONS}"
INTERFACE_INCLUDE_DIRECTORIES "${Libinput_INCLUDE_DIR}"
)
endif()
mark_as_advanced(Libinput_LIBRARY Libinput_INCLUDE_DIR)
# compatibility variables
set(Libinput_LIBRARIES ${Libinput_LIBRARY})
set(Libinput_INCLUDE_DIRS ${Libinput_INCLUDE_DIR})
set(Libinput_VERSION_STRING ${Libinput_VERSION})
else()
message(STATUS "FindLibinput.cmake cannot find libinput on Windows systems.")
set(Libinput_FOUND FALSE)
endif()
include(FeatureSummary)
set_package_properties(Libinput PROPERTIES
URL "http://www.freedesktop.org/wiki/Software/libinput/"
DESCRIPTION "Library to handle input devices in Wayland compositors and to provide a generic X.Org input driver."
)

View file

@ -0,0 +1,29 @@
# - Try to find the UDev library
# Once done this will define
#
# UDEV_FOUND - system has UDev
# UDEV_INCLUDE_DIR - the libudev include directory
# UDEV_LIBS - The libudev libraries
# Copyright (c) 2010, Rafael Fernández López, <ereslibre@kde.org>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
find_path(UDEV_INCLUDE_DIR libudev.h)
find_library(UDEV_LIBS udev)
if(UDEV_INCLUDE_DIR AND UDEV_LIBS)
include(CheckFunctionExists)
include(CMakePushCheckState)
cmake_push_check_state()
set(CMAKE_REQUIRED_LIBRARIES ${UDEV_LIBS} )
cmake_pop_check_state()
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(UDev DEFAULT_MSG UDEV_INCLUDE_DIR UDEV_LIBS)
mark_as_advanced(UDEV_INCLUDE_DIR UDEV_LIBS)

View file

@ -12,6 +12,7 @@
#cmakedefine01 HAVE_WAYLAND
#cmakedefine01 HAVE_WAYLAND_EGL
#cmakedefine01 HAVE_XKB
#cmakedefine01 HAVE_INPUT
/* Define to 1 if you have the <unistd.h> header file. */
#cmakedefine HAVE_UNISTD_H 1

View file

@ -26,6 +26,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#endif
#include "unmanaged.h"
#include "workspace.h"
#if HAVE_INPUT
#include "libinput/connection.h"
#endif
// KDE
#include <kkeyserver.h>
// TODO: remove xtest
@ -166,6 +169,16 @@ InputRedirection::InputRedirection(QObject *parent)
, m_pointerWindow()
, m_shortcuts(new GlobalShortcutsManager(this))
{
#if HAVE_INPUT
LibInput::Connection *conn = LibInput::Connection::create(this);
if (conn) {
// TODO: connect the motion notifiers
conn->setup();
connect(conn, &LibInput::Connection::pointerButtonChanged, this, &InputRedirection::processPointerButton);
connect(conn, &LibInput::Connection::pointerAxisChanged, this, &InputRedirection::processPointerAxis);
connect(conn, &LibInput::Connection::keyChanged, this, &InputRedirection::processKeyboardKey);
}
#endif
}
InputRedirection::~InputRedirection()

137
libinput/connection.cpp Normal file
View file

@ -0,0 +1,137 @@
/********************************************************************
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 "connection.h"
#include "context.h"
#include "events.h"
#include <QDebug>
#include <QSocketNotifier>
#include <libinput.h>
namespace KWin
{
namespace LibInput
{
Connection *Connection::s_self = nullptr;
static Context *s_context = nullptr;
Connection::Connection(QObject *parent) = delete;
Connection *Connection::create(QObject *parent)
{
Q_ASSERT(!s_self);
static Udev s_udev;
if (!s_udev.isValid()) {
qWarning() << "Failed to initialize udev";
return nullptr;
}
if (!s_context) {
s_context = new Context(s_udev);
if (!s_context->isValid()) {
qWarning() << "Failed to create context from udev";
delete s_context;
s_context = nullptr;
return nullptr;
}
// TODO: don't hardcode seat name
if (!s_context->assignSeat("seat0")) {
qWarning() << "Failed to assign seat seat0";
delete s_context;
s_context = nullptr;
return nullptr;
}
}
s_self = new Connection(s_context, parent);
return s_self;
}
Connection::Connection(Context *input, QObject *parent)
: QObject(parent)
, m_input(input)
, m_notifier(nullptr)
{
Q_ASSERT(m_input);
}
Connection::~Connection()
{
s_self = nullptr;
delete s_context;
s_context = nullptr;
}
void Connection::setup()
{
Q_ASSERT(!m_notifier);
m_notifier = new QSocketNotifier(m_input->fileDescriptor(), QSocketNotifier::Read, this);
connect(m_notifier, &QSocketNotifier::activated, this, &Connection::handleEvent);
}
void Connection::handleEvent()
{
do {
m_input->dispatch();
QScopedPointer<Event> event(m_input->event());
if (event.isNull()) {
break;
}
switch (event->type()) {
case LIBINPUT_EVENT_KEYBOARD_KEY: {
KeyEvent *ke = static_cast<KeyEvent*>(event.data());
emit keyChanged(ke->key(), ke->state(), ke->time());
break;
}
case LIBINPUT_EVENT_POINTER_AXIS: {
PointerEvent *pe = static_cast<PointerEvent*>(event.data());
emit pointerAxisChanged(pe->axis(), pe->axisValue(), pe->time());
break;
}
case LIBINPUT_EVENT_POINTER_BUTTON: {
PointerEvent *pe = static_cast<PointerEvent*>(event.data());
emit pointerButtonChanged(pe->button(), pe->buttonState(), pe->time());
break;
}
case LIBINPUT_EVENT_POINTER_MOTION: {
PointerEvent *pe = static_cast<PointerEvent*>(event.data());
emit pointerMotion(pe->delta(), pe->time());
break;
}
case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: {
PointerEvent *pe = static_cast<PointerEvent*>(event.data());
emit pointerMotionAbsolute(pe->absolutePos(), pe->absolutePos(m_size), pe->time());
break;
}
default:
// nothing
break;
}
} while (true);
}
void Connection::setScreenSize(const QSize &size)
{
m_size = size;
}
}
}

71
libinput/connection.h Normal file
View file

@ -0,0 +1,71 @@
/********************************************************************
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/>.
*********************************************************************/
#ifndef KWIN_LIBINPUT_CONNECTION_H
#define KWIN_LIBINPUT_CONNECTION_H
#include "../input.h"
#include <kwinglobals.h>
#include <QObject>
#include <QSize>
class QSocketNotifier;
namespace KWin
{
namespace LibInput
{
class Context;
class Connection : public QObject
{
Q_OBJECT
public:
~Connection();
void setup();
/**
* Sets the screen @p size. This is needed for mapping absolute pointer events to
* the screen data.
**/
void setScreenSize(const QSize &size);
Q_SIGNALS:
void keyChanged(uint32_t key, InputRedirection::KeyboardKeyState, uint32_t time);
void pointerButtonChanged(uint32_t button, InputRedirection::PointerButtonState state, uint32_t time);
void pointerMotionAbsolute(QPointF orig, QPointF screen, uint32_t time);
void pointerMotion(QPointF delta, uint32_t time);
void pointerAxisChanged(InputRedirection::PointerAxis axis, qreal delta, uint32_t time);
private:
Connection(Context *input, QObject *parent = nullptr);
void handleEvent();
Context *m_input;
QSocketNotifier *m_notifier;
QSize m_size;
KWIN_SINGLETON(Connection)
};
}
}
#endif

111
libinput/context.cpp Normal file
View file

@ -0,0 +1,111 @@
/********************************************************************
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 "context.h"
#include "events.h"
#include <libudev.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
namespace KWin
{
namespace LibInput
{
Udev::Udev()
: m_udev(udev_new())
{
}
Udev::~Udev()
{
if (m_udev) {
udev_unref(m_udev);
}
}
Context::Context(const Udev &udev)
: m_libinput(libinput_udev_create_context(&Context::s_interface, this, udev))
{
libinput_log_set_priority(m_libinput, LIBINPUT_LOG_PRIORITY_DEBUG);
}
Context::~Context()
{
if (m_libinput) {
libinput_unref(m_libinput);
}
}
bool Context::assignSeat(const char *seat)
{
if (!isValid()) {
return false;
}
return libinput_udev_assign_seat(m_libinput, seat) == 0;
}
int Context::fileDescriptor()
{
if (!isValid()) {
return 0;
}
return libinput_get_fd(m_libinput);
}
void Context::dispatch()
{
libinput_dispatch(m_libinput);
}
const struct libinput_interface Context::s_interface = {
Context::openRestrictedCallback,
Context::closeRestrictedCallBack
};
int Context::openRestrictedCallback(const char *path, int flags, void *user_data)
{
return ((Context*)user_data)->openRestricted(path, flags);
}
void Context::closeRestrictedCallBack(int fd, void *user_data)
{
((Context*)user_data)->closeRestricted(fd);
}
int Context::openRestricted(const char *path, int flags)
{
int fd = open(path, flags);
return fd < 0 ? -errno : fd;
}
void Context::closeRestricted(int fd)
{
close(fd);
}
Event *Context::event()
{
return Event::create(libinput_get_event(m_libinput));
}
}
}

92
libinput/context.h Normal file
View file

@ -0,0 +1,92 @@
/********************************************************************
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/>.
*********************************************************************/
#ifndef KWIN_LIBINPUT_CONTEXT_H
#define KWIN_LIBINPUT_CONTEXT_H
#include <libinput.h>
struct udev;
namespace KWin
{
namespace LibInput
{
class Event;
class Udev
{
public:
Udev();
~Udev();
bool isValid() const {
return m_udev != nullptr;
}
operator udev*() const {
return m_udev;
}
operator udev*() {
return m_udev;
}
private:
struct udev *m_udev;
};
class Context
{
public:
Context(const Udev &udev);
~Context();
bool assignSeat(const char *seat);
bool isValid() const {
return m_libinput != nullptr;
}
int fileDescriptor();
void dispatch();
operator libinput*() {
return m_libinput;
}
operator libinput*() const {
return m_libinput;
}
/**
* Gets the next event, if there is no new event @c null is returned.
* The caller takes ownership of the returned pointer.
**/
Event *event();
static int openRestrictedCallback(const char *path, int flags, void *user_data);
static void closeRestrictedCallBack(int fd, void *user_data);
static const struct libinput_interface s_interface;
private:
int openRestricted(const char *path, int flags);
void closeRestricted(int fd);
struct libinput *m_libinput;
};
}
}
#endif

165
libinput/events.cpp Normal file
View file

@ -0,0 +1,165 @@
/********************************************************************
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 <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);
default:
return new Event(event, t);
}
}
Event::Event(libinput_event *event, libinput_event_type type)
: m_event(event)
, m_type(type)
{
}
Event::~Event()
{
libinput_event_destroy(m_event);
}
libinput_device *Event::device() const
{
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()));
}
QPointF 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));
}
uint32_t PointerEvent::time() const
{
return libinput_event_pointer_get_time(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();
}
InputRedirection::PointerAxis PointerEvent::axis() const
{
Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_AXIS);
switch (libinput_event_pointer_get_axis(m_pointerEvent)) {
case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL:
return InputRedirection::PointerAxisHorizontal;
case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL:
return InputRedirection::PointerAxisVertical;
}
abort();
}
qreal PointerEvent::axisValue() const
{
Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_AXIS);
return libinput_event_pointer_get_axis_value(m_pointerEvent);
}
}
}

113
libinput/events.h Normal file
View file

@ -0,0 +1,113 @@
/********************************************************************
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/>.
*********************************************************************/
#ifndef KWIN_LIBINPUT_EVENTS_H
#define KWIN_LIBINPUT_EVENTS_H
#include "../input.h"
#include <libinput.h>
namespace KWin
{
namespace LibInput
{
class Event
{
public:
virtual ~Event();
libinput_event_type type() const;
libinput_device *device() const;
operator libinput_event*() {
return m_event;
}
operator libinput_event*() const {
return m_event;
}
static Event *create(libinput_event *event);
protected:
Event(libinput_event *event, libinput_event_type type);
private:
libinput_event *m_event;
libinput_event_type m_type;
};
class KeyEvent : public Event
{
public:
KeyEvent(libinput_event *event);
virtual ~KeyEvent();
uint32_t key() const;
InputRedirection::KeyboardKeyState state() const;
uint32_t time() const;
operator libinput_event_keyboard*() {
return m_keyboardEvent;
}
operator libinput_event_keyboard*() const {
return m_keyboardEvent;
}
private:
libinput_event_keyboard *m_keyboardEvent;
};
class PointerEvent : public Event
{
public:
PointerEvent(libinput_event* event, libinput_event_type type);
virtual ~PointerEvent();
QPointF absolutePos() const;
QPointF absolutePos(const QSize &size) const;
QPointF delta() const;
uint32_t button() const;
InputRedirection::PointerButtonState buttonState() const;
uint32_t time() const;
InputRedirection::PointerAxis axis() const;
qreal axisValue() const;
operator libinput_event_pointer*() {
return m_pointerEvent;
}
operator libinput_event_pointer*() const {
return m_pointerEvent;
}
private:
libinput_event_pointer *m_pointerEvent;
};
inline
libinput_event_type Event::type() const
{
return m_type;
}
}
}
#endif

View file

@ -17,3 +17,14 @@ if (Wayland_Client_FOUND AND XKB_FOUND AND KF5Wayland_FOUND)
add_executable(waylandclienttest ${waylandclienttest_SRCS})
target_link_libraries(waylandclienttest Qt5::Core Qt5::Gui Wayland::Client KF5::WaylandClient)
endif()
if (HAVE_INPUT)
set(libinputtest_SRCS
libinputtest.cpp
${KWIN_SOURCE_DIR}/libinput/context.cpp
${KWIN_SOURCE_DIR}/libinput/connection.cpp
${KWIN_SOURCE_DIR}/libinput/events.cpp
)
add_executable(libinputtest ${libinputtest_SRCS})
target_link_libraries(libinputtest Qt5::Core Libinput::Libinput ${UDEV_LIBS})
endif()

69
tests/libinputtest.cpp Normal file
View file

@ -0,0 +1,69 @@
/*
* Copyright 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 "../input.h"
#include "../libinput/connection.h"
#include <QCoreApplication>
#include <linux/input.h>
#include <iostream>
int main(int argc, char **argv)
{
using namespace KWin::LibInput;
QCoreApplication app(argc, argv);
Connection *conn = Connection::create(&app);
if (!conn) {
std::cerr << "Failed to create LibInput integration" << std::endl;
return 1;
}
conn->setScreenSize(QSize(100, 100));
conn->setup();
QObject::connect(conn, &Connection::keyChanged,
[](uint32_t key, KWin::InputRedirection::KeyboardKeyState state) {
std::cout << "Got key event" << std::endl;;
if (key == KEY_Q && state == KWin::InputRedirection::KeyboardKeyReleased) {
QCoreApplication::instance()->quit();
}
}
);
QObject::connect(conn, &Connection::pointerButtonChanged,
[](uint32_t button, KWin::InputRedirection::PointerButtonState state) {
std::cout << "Got pointer button event" << std::endl;
if (button == BTN_MIDDLE && state == KWin::InputRedirection::PointerButtonReleased) {
QCoreApplication::instance()->quit();
}
}
);
QObject::connect(conn, &Connection::pointerMotion,
[](QPointF delta) {
std::cout << "Got pointer motion: " << delta.x() << "/" << delta.y() << std::endl;
}
);
QObject::connect(conn, &Connection::pointerAxisChanged,
[](KWin::InputRedirection::PointerAxis axis, qreal delta) {
std::cout << "Axis: " << axis << " with delta" << delta << std::endl;
}
);
return app.exec();
}