summaryrefslogtreecommitdiffstats
path: root/xbmc/platform/linux/input/LibInputHandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/platform/linux/input/LibInputHandler.cpp')
-rw-r--r--xbmc/platform/linux/input/LibInputHandler.cpp301
1 files changed, 301 insertions, 0 deletions
diff --git a/xbmc/platform/linux/input/LibInputHandler.cpp b/xbmc/platform/linux/input/LibInputHandler.cpp
new file mode 100644
index 0000000..a8c39f5
--- /dev/null
+++ b/xbmc/platform/linux/input/LibInputHandler.cpp
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "LibInputHandler.h"
+
+#include "LibInputKeyboard.h"
+#include "LibInputPointer.h"
+#include "LibInputSettings.h"
+#include "LibInputTouch.h"
+#include "ServiceBroker.h"
+#include "interfaces/AnnouncementManager.h"
+#include "utils/log.h"
+
+#include <algorithm>
+#include <string.h>
+
+#include <fcntl.h>
+#include <linux/input.h>
+#include <sys/epoll.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+static int open_restricted(const char *path, int flags, void __attribute__((unused)) *user_data)
+{
+ int fd = open(path, flags);
+
+ if (fd < 0)
+ {
+ CLog::Log(LOGERROR, "{} - failed to open {} ({})", __FUNCTION__, path, strerror(errno));
+ return -errno;
+ }
+
+ auto ret = ioctl(fd, EVIOCGRAB, (void*)1);
+ if (ret < 0)
+ {
+ CLog::Log(LOGDEBUG, "{} - grab requested, but failed for {} ({})", __FUNCTION__, path,
+ strerror(errno));
+ }
+
+ return fd;
+}
+
+static void close_restricted(int fd, void __attribute__((unused)) *user_data)
+{
+ close(fd);
+}
+
+static const struct libinput_interface m_interface =
+{
+ open_restricted,
+ close_restricted,
+};
+
+static void LogHandler(libinput __attribute__((unused)) *libinput, libinput_log_priority priority, const char *format, va_list args)
+{
+ if (priority == LIBINPUT_LOG_PRIORITY_DEBUG)
+ {
+ char buf[512];
+ int n = vsnprintf(buf, sizeof(buf), format, args);
+ if (n > 0)
+ CLog::Log(LOGDEBUG, "libinput: {}", buf);
+ }
+}
+
+CLibInputHandler::CLibInputHandler() : CThread("libinput")
+{
+ m_udev = udev_new();
+ if (!m_udev)
+ {
+ CLog::Log(LOGERROR, "CLibInputHandler::{} - failed to get udev context for libinput",
+ __FUNCTION__);
+ return;
+ }
+
+ m_li = libinput_udev_create_context(&m_interface, nullptr, m_udev);
+ if (!m_li)
+ {
+ CLog::Log(LOGERROR, "CLibInputHandler::{} - failed to get libinput context", __FUNCTION__);
+ return;
+ }
+
+ libinput_log_set_handler(m_li, LogHandler);
+ libinput_log_set_priority(m_li, LIBINPUT_LOG_PRIORITY_DEBUG);
+
+ auto ret = libinput_udev_assign_seat(m_li, "seat0");
+ if (ret < 0)
+ CLog::Log(LOGERROR, "CLibInputHandler::{} - failed to assign seat", __FUNCTION__);
+
+ m_liFd = libinput_get_fd(m_li);
+
+ m_keyboard.reset(new CLibInputKeyboard());
+ m_pointer.reset(new CLibInputPointer());
+ m_touch.reset(new CLibInputTouch());
+ m_settings.reset(new CLibInputSettings(this));
+
+ CServiceBroker::GetAnnouncementManager()->AddAnnouncer(this);
+}
+
+CLibInputHandler::~CLibInputHandler()
+{
+ CServiceBroker::GetAnnouncementManager()->RemoveAnnouncer(this);
+ StopThread();
+
+ libinput_unref(m_li);
+ udev_unref(m_udev);
+}
+
+void CLibInputHandler::Announce(ANNOUNCEMENT::AnnouncementFlag flag,
+ const std::string& sender,
+ const std::string& message,
+ const CVariant& data)
+{
+ if (flag & (ANNOUNCEMENT::System))
+ {
+ if (message == "OnSleep")
+ libinput_suspend(m_li);
+ else if (message == "OnWake")
+ {
+ auto ret = libinput_resume(m_li);
+ if (ret < 0)
+ CLog::Log(LOGERROR, "CLibInputHandler::{} - failed to resume monitoring", __FUNCTION__);
+ }
+ }
+}
+
+bool CLibInputHandler::SetKeymap(const std::string& layout)
+{
+ return m_keyboard->SetKeymap(layout);
+}
+
+void CLibInputHandler::Start()
+{
+ Create();
+ SetPriority(ThreadPriority::LOWEST);
+}
+
+void CLibInputHandler::Process()
+{
+ int epollFd = epoll_create1(EPOLL_CLOEXEC);
+ if (epollFd < 0)
+ {
+ CLog::Log(LOGERROR, "CLibInputHandler::{} - failed to create epoll file descriptor: {}",
+ __FUNCTION__, strerror(-errno));
+ return;
+ }
+
+ epoll_event event;
+ event.events = EPOLLIN;
+ event.data.fd = m_liFd;
+
+ auto ret = epoll_ctl(epollFd, EPOLL_CTL_ADD, m_liFd, &event);
+ if (ret < 0)
+ {
+ CLog::Log(LOGERROR, "CLibInputHandler::{} - failed to add file descriptor to epoll: {}",
+ __FUNCTION__, strerror(-errno));
+ close(epollFd);
+ return;
+ }
+
+ while (!m_bStop)
+ {
+ epoll_wait(epollFd, &event, 1, 200);
+
+ ret = libinput_dispatch(m_li);
+ if (ret < 0)
+ {
+ CLog::Log(LOGERROR, "CLibInputHandler::{} - libinput_dispatch failed: {}", __FUNCTION__,
+ strerror(-errno));
+ close(epollFd);
+ return;
+ }
+
+ libinput_event *ev;
+ while ((ev = libinput_get_event(m_li)) != nullptr)
+ {
+ ProcessEvent(ev);
+ libinput_event_destroy(ev);
+ }
+ }
+
+ ret = close(epollFd);
+ if (ret < 0)
+ {
+ CLog::Log(LOGERROR, "CLibInputHandler::{} - failed to close epoll file descriptor: {}",
+ __FUNCTION__, strerror(-errno));
+ return;
+ }
+}
+
+void CLibInputHandler::ProcessEvent(libinput_event *ev)
+{
+ libinput_event_type type = libinput_event_get_type(ev);
+ libinput_device *dev = libinput_event_get_device(ev);
+
+ switch (type)
+ {
+ case LIBINPUT_EVENT_DEVICE_ADDED:
+ DeviceAdded(dev);
+ break;
+ case LIBINPUT_EVENT_DEVICE_REMOVED:
+ DeviceRemoved(dev);
+ break;
+ case LIBINPUT_EVENT_POINTER_BUTTON:
+ m_pointer->ProcessButton(libinput_event_get_pointer_event(ev));
+ break;
+ case LIBINPUT_EVENT_POINTER_MOTION:
+ m_pointer->ProcessMotion(libinput_event_get_pointer_event(ev));
+ break;
+ case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
+ m_pointer->ProcessMotionAbsolute(libinput_event_get_pointer_event(ev));
+ break;
+ case LIBINPUT_EVENT_POINTER_AXIS:
+ m_pointer->ProcessAxis(libinput_event_get_pointer_event(ev));
+ break;
+ case LIBINPUT_EVENT_KEYBOARD_KEY:
+ m_keyboard->ProcessKey(libinput_event_get_keyboard_event(ev));
+ m_keyboard->UpdateLeds(dev);
+ break;
+ case LIBINPUT_EVENT_TOUCH_DOWN:
+ m_touch->ProcessTouchDown(libinput_event_get_touch_event(ev));
+ break;
+ case LIBINPUT_EVENT_TOUCH_MOTION:
+ m_touch->ProcessTouchMotion(libinput_event_get_touch_event(ev));
+ break;
+ case LIBINPUT_EVENT_TOUCH_UP:
+ m_touch->ProcessTouchUp(libinput_event_get_touch_event(ev));
+ break;
+ case LIBINPUT_EVENT_TOUCH_CANCEL:
+ m_touch->ProcessTouchCancel(libinput_event_get_touch_event(ev));
+ break;
+ case LIBINPUT_EVENT_TOUCH_FRAME:
+ m_touch->ProcessTouchFrame(libinput_event_get_touch_event(ev));
+ break;
+
+ default:
+ break;
+ }
+}
+
+void CLibInputHandler::DeviceAdded(libinput_device *dev)
+{
+ const char *sysname = libinput_device_get_sysname(dev);
+ const char *name = libinput_device_get_name(dev);
+
+ if (libinput_device_has_capability(dev, LIBINPUT_DEVICE_CAP_TOUCH))
+ {
+ CLog::Log(LOGDEBUG, "CLibInputHandler::{} - touch type device added: {} ({})", __FUNCTION__,
+ name, sysname);
+ m_devices.push_back(libinput_device_ref(dev));
+ }
+
+ if (libinput_device_has_capability(dev, LIBINPUT_DEVICE_CAP_POINTER))
+ {
+ CLog::Log(LOGDEBUG, "CLibInputHandler::{} - pointer type device added: {} ({})", __FUNCTION__,
+ name, sysname);
+ m_devices.push_back(libinput_device_ref(dev));
+ }
+
+ if (libinput_device_has_capability(dev, LIBINPUT_DEVICE_CAP_KEYBOARD))
+ {
+ CLog::Log(LOGDEBUG, "CLibInputHandler::{} - keyboard type device added: {} ({})", __FUNCTION__,
+ name, sysname);
+ m_devices.push_back(libinput_device_ref(dev));
+ m_keyboard->GetRepeat(dev);
+ }
+}
+
+void CLibInputHandler::DeviceRemoved(libinput_device *dev)
+{
+ const char *sysname = libinput_device_get_sysname(dev);
+ const char *name = libinput_device_get_name(dev);
+
+ if (libinput_device_has_capability(dev, LIBINPUT_DEVICE_CAP_TOUCH))
+ {
+ CLog::Log(LOGDEBUG, "CLibInputHandler::{} - touch type device removed: {} ({})", __FUNCTION__,
+ name, sysname);
+ auto device = std::find(m_devices.begin(), m_devices.end(), libinput_device_unref(dev));
+ m_devices.erase(device);
+ }
+
+ if (libinput_device_has_capability(dev, LIBINPUT_DEVICE_CAP_POINTER))
+ {
+ CLog::Log(LOGDEBUG, "CLibInputHandler::{} - pointer type device removed: {} ({})", __FUNCTION__,
+ name, sysname);
+ auto device = std::find(m_devices.begin(), m_devices.end(), libinput_device_unref(dev));
+ m_devices.erase(device);
+ }
+
+ if (libinput_device_has_capability(dev, LIBINPUT_DEVICE_CAP_KEYBOARD))
+ {
+ CLog::Log(LOGDEBUG, "CLibInputHandler::{} - keyboard type device removed: {} ({})",
+ __FUNCTION__, name, sysname);
+ auto device = std::find(m_devices.begin(), m_devices.end(), libinput_device_unref(dev));
+ m_devices.erase(device);
+ }
+}