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:
parent
075422fc5e
commit
c4bb3d11fc
13 changed files with 964 additions and 0 deletions
|
@ -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
|
||||
|
|
125
cmake/modules/FindLibinput.cmake
Normal file
125
cmake/modules/FindLibinput.cmake
Normal 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."
|
||||
)
|
29
cmake/modules/FindUDev.cmake
Normal file
29
cmake/modules/FindUDev.cmake
Normal 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)
|
|
@ -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
|
||||
|
|
13
input.cpp
13
input.cpp
|
@ -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
137
libinput/connection.cpp
Normal 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
71
libinput/connection.h
Normal 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
111
libinput/context.cpp
Normal 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
92
libinput/context.h
Normal 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
165
libinput/events.cpp
Normal 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
113
libinput/events.h
Normal 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
|
|
@ -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
69
tests/libinputtest.cpp
Normal 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();
|
||||
}
|
Loading…
Reference in a new issue