From 3aa13f4c1bcf917ebb48d8f603ce0694fc9bfed4 Mon Sep 17 00:00:00 2001 From: Philipp Kerling Date: Thu, 29 Jun 2017 15:01:01 +0200 Subject: [PATCH 1/7] Implement wl_touch support --- xbmc/windowing/wayland/SeatInputProcessor.cpp | 88 ++++++++++++++++++- xbmc/windowing/wayland/SeatInputProcessor.h | 23 +++++ xbmc/windowing/wayland/WinSystemWayland.cpp | 9 +- 3 files changed, 118 insertions(+), 2 deletions(-) diff --git a/xbmc/windowing/wayland/SeatInputProcessor.cpp b/xbmc/windowing/wayland/SeatInputProcessor.cpp index ddf9c292f8f42..17c2bad1a65f2 100644 --- a/xbmc/windowing/wayland/SeatInputProcessor.cpp +++ b/xbmc/windowing/wayland/SeatInputProcessor.cpp @@ -28,6 +28,7 @@ #include #include "input/MouseStat.h" +#include "input/touch/generic/GenericTouchInputHandler.h" #include "SeatInputProcessor.h" #include "utils/log.h" @@ -344,7 +345,6 @@ XBMC_Event CSeatInputProcessor::SendKey(unsigned char scancode, XBMCKey key, std event.type = static_cast (pressed ? XBMC_KEYDOWN : XBMC_KEYUP); event.key.keysym = { - // The scancode is a char, which is not enough to hold the value from Wayland anyway .scancode = scancode, .sym = key, .mod = m_keymap->ActiveXBMCModifiers(), @@ -374,4 +374,90 @@ void CSeatInputProcessor::CKeyRepeatCallback::OnTimeout() void CSeatInputProcessor::HandleTouchCapability() { + m_touch.on_down() = [this](std::uint32_t serial, std::uint32_t time, wayland::surface_t surface, std::int32_t id, double x, double y) + { + // Find free Kodi pointer number + int kodiPointer = -1; + // Not optimal, but irrelevant for the small number of iterations + for (int testPointer = 0; testPointer < TOUCH_MAX_POINTERS; testPointer++) + { + if (std::all_of(m_touchPoints.cbegin(), m_touchPoints.cend(), + [=](decltype(m_touchPoints)::value_type const& pair) + { + return (pair.second.kodiPointerNumber != testPointer); + })) + { + kodiPointer = testPointer; + break; + } + } + + if (kodiPointer != -1) + { + auto it = m_touchPoints.emplace(std::piecewise_construct, std::forward_as_tuple(id), std::forward_as_tuple(time, kodiPointer, x * m_coordinateScale, y * m_coordinateScale, 0.0f)).first; + SendTouchPointEvent(TouchInputDown, it->second); + } + }; + m_touch.on_up() = [this](std::uint32_t serial, std::uint32_t time, std::int32_t id) + { + auto it = m_touchPoints.find(id); + if (it != m_touchPoints.end()) + { + auto& point = it->second; + point.lastEventTime = time; + SendTouchPointEvent(TouchInputUp, point); + m_touchPoints.erase(it); + } + }; + m_touch.on_motion() = [this](std::uint32_t time, std::int32_t id, double x, double y) + { + auto it = m_touchPoints.find(id); + if (it != m_touchPoints.end()) + { + auto& point = it->second; + point.x = x * m_coordinateScale; + point.y = y * m_coordinateScale; + point.lastEventTime = time; + SendTouchPointEvent(TouchInputMove, point); + } + }; + m_touch.on_cancel() = [this]() + { + // TouchInputAbort aborts for all pointers, so it does not matter which is specified + if (!m_touchPoints.empty()) + { + SendTouchPointEvent(TouchInputAbort, m_touchPoints.begin()->second); + } + m_touchPoints.clear(); + }; + m_touch.on_shape() = [this](std::int32_t id, double major, double minor) + { + auto it = m_touchPoints.find(id); + if (it != m_touchPoints.end()) + { + auto& point = it->second; + // Kodi only supports size without shape, so use average of both axes + point.size = ((major + minor) / 2.0) * m_coordinateScale; + UpdateTouchPoint(point); + } + }; +} + +void CSeatInputProcessor::SendTouchPointEvent(TouchInput event, const TouchPoint& point) +{ + if (event == TouchInputMove) + { + for (auto const& point : m_touchPoints) + { + // Contrary to the docs, this must be called before HandleTouchInput or the + // position will not be updated and gesture detection will not work + UpdateTouchPoint(point.second); + } + } + CGenericTouchInputHandler::GetInstance().HandleTouchInput(event, point.x, point.y, point.lastEventTime * INT64_C(1000000), point.kodiPointerNumber, point.size); +} + +void CSeatInputProcessor::UpdateTouchPoint(const TouchPoint& point) +{ + CGenericTouchInputHandler::GetInstance().UpdateTouchPointer(point.kodiPointerNumber, point.x, point.y, point.lastEventTime * INT64_C(1000000), point.size); } diff --git a/xbmc/windowing/wayland/SeatInputProcessor.h b/xbmc/windowing/wayland/SeatInputProcessor.h index 87a59e5a7ee19..7c3d86f2c9c18 100644 --- a/xbmc/windowing/wayland/SeatInputProcessor.h +++ b/xbmc/windowing/wayland/SeatInputProcessor.h @@ -19,10 +19,12 @@ */ #pragma once +#include #include #include +#include "input/touch/ITouchInputHandler.h" #include "threads/Timer.h" #include "windowing/XBMC_events.h" #include "windowing/XkbcommonKeymap.h" @@ -136,6 +138,24 @@ class CSeatInputProcessor void ConvertAndSendKey(std::uint32_t scancode, bool pressed); XBMC_Event SendKey(unsigned char scancode, XBMCKey key, std::uint16_t unicodeCodepoint, bool pressed); + + struct TouchPoint + { + std::uint32_t lastEventTime; + /// Pointer number passed to \ref ITouchInputHandler + std::int32_t kodiPointerNumber; + /** + * Last coordinates - needed for TouchInputUp events where Wayland does not + * send new coordinates but Kodi needs them anyway + */ + float x, y, size; + TouchPoint(std::uint32_t initialEventTime, std::int32_t kodiPointerNumber, float x, float y, float size) + : lastEventTime(initialEventTime), kodiPointerNumber(kodiPointerNumber), x(x), y(y), size(size) + {} + }; + + void SendTouchPointEvent(TouchInput event, TouchPoint const& point); + void UpdateTouchPoint(TouchPoint const& point); std::uint32_t m_globalName; wayland::seat_t m_seat; @@ -170,6 +190,9 @@ class CSeatInputProcessor }; CKeyRepeatCallback m_keyRepeatCallback; CTimer m_keyRepeatTimer; + + /// Map of wl_touch point id to data + std::map m_touchPoints; }; } diff --git a/xbmc/windowing/wayland/WinSystemWayland.cpp b/xbmc/windowing/wayland/WinSystemWayland.cpp index a40ec470dc709..fcb2f966538ad 100644 --- a/xbmc/windowing/wayland/WinSystemWayland.cpp +++ b/xbmc/windowing/wayland/WinSystemWayland.cpp @@ -33,8 +33,9 @@ #include "guilib/GraphicContext.h" #include "guilib/LocalizeStrings.h" #include "input/InputManager.h" +#include "input/touch/generic/GenericTouchActionHandler.h" +#include "input/touch/generic/GenericTouchInputHandler.h" #include "linux/PlatformConstants.h" -#include "../linux/OSScreenSaverFreedesktop.h" #include "OSScreenSaverIdleInhibitUnstableV1.h" #include "ServiceBroker.h" #include "settings/DisplaySettings.h" @@ -45,6 +46,7 @@ #include "utils/log.h" #include "utils/MathUtils.h" #include "utils/StringUtils.h" +#include "windowing/linux/OSScreenSaverFreedesktop.h" #include "WinEventsWayland.h" using namespace KODI::WINDOWING; @@ -124,6 +126,8 @@ bool CWinSystemWayland::InitWindowSystem() // pointer is by default not on this window, will be immediately rectified // by the enter() events if it is CServiceBroker::GetInputManager().SetMouseActive(false); + // Always use the generic touch action handler + CGenericTouchInputHandler::GetInstance().RegisterHandler(&CGenericTouchActionHandler::GetInstance()); return CWinSystemBase::InitWindowSystem(); } @@ -146,6 +150,9 @@ bool CWinSystemWayland::DestroyWindowSystem() m_surfaceOutputs.clear(); m_connection.reset(); + + CGenericTouchInputHandler::GetInstance().UnregisterHandler(); + return CWinSystemBase::DestroyWindowSystem(); } From f395fc5641413994a669cfd28d396ae46e03f965 Mon Sep 17 00:00:00 2001 From: Philipp Kerling Date: Thu, 29 Jun 2017 15:39:17 +0200 Subject: [PATCH 2/7] Make dpi in ITouchInputHandler atomic so it can be modified from other threads without problems --- xbmc/input/touch/ITouchInputHandler.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xbmc/input/touch/ITouchInputHandler.h b/xbmc/input/touch/ITouchInputHandler.h index e02bd1ff2acc6..52ce186479e89 100644 --- a/xbmc/input/touch/ITouchInputHandler.h +++ b/xbmc/input/touch/ITouchInputHandler.h @@ -19,6 +19,7 @@ * */ +#include #include #include "input/touch/ITouchInputHandling.h" @@ -101,5 +102,5 @@ class ITouchInputHandler : public ITouchInputHandling /*! * \brief DPI value of the touch screen */ - float m_dpi; + std::atomic m_dpi; }; From 16e6bb08dd5cf2e3fb8f5fc314f061d79b6339e6 Mon Sep 17 00:00:00 2001 From: Philipp Kerling Date: Thu, 29 Jun 2017 15:40:02 +0200 Subject: [PATCH 3/7] Set screen DPI on touch handler for wayland --- xbmc/windowing/wayland/Output.cpp | 17 +++++++++++++++++ xbmc/windowing/wayland/Output.h | 2 ++ xbmc/windowing/wayland/WinSystemWayland.cpp | 19 ++++++++++++++++++- xbmc/windowing/wayland/WinSystemWayland.h | 1 + 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/xbmc/windowing/wayland/Output.cpp b/xbmc/windowing/wayland/Output.cpp index f0d58c55a9a26..76a9f60f1b30c 100644 --- a/xbmc/windowing/wayland/Output.cpp +++ b/xbmc/windowing/wayland/Output.cpp @@ -21,6 +21,7 @@ #include "Output.h" #include +#include #include using namespace KODI::WINDOWING::WAYLAND; @@ -115,3 +116,19 @@ float COutput::GetPixelRatioForMode(const Mode& mode) const ); } } + +float COutput::GetDpiForMode(const Mode& mode) const +{ + constexpr float INCH_MM_RATIO{25.4f}; + + float diagonalPixels = std::sqrt(mode.width * mode.width + mode.height * mode.height); + // physicalWidth/physicalHeight is in millimeters + float diagonalInches = std::sqrt(m_physicalWidth * m_physicalWidth + m_physicalHeight * m_physicalHeight) / INCH_MM_RATIO; + + return diagonalPixels / diagonalInches; +} + +float COutput::GetCurrentDpi() const +{ + return GetDpiForMode(GetCurrentMode()); +} diff --git a/xbmc/windowing/wayland/Output.h b/xbmc/windowing/wayland/Output.h index aaaba3f17a741..a642f18800e87 100644 --- a/xbmc/windowing/wayland/Output.h +++ b/xbmc/windowing/wayland/Output.h @@ -125,6 +125,8 @@ class COutput Mode const& GetPreferredMode() const; float GetPixelRatioForMode(Mode const& mode) const; + float GetDpiForMode(Mode const& mode) const; + float GetCurrentDpi() const; private: COutput(COutput const& other) = delete; diff --git a/xbmc/windowing/wayland/WinSystemWayland.cpp b/xbmc/windowing/wayland/WinSystemWayland.cpp index fcb2f966538ad..497bffd258aee 100644 --- a/xbmc/windowing/wayland/WinSystemWayland.cpp +++ b/xbmc/windowing/wayland/WinSystemWayland.cpp @@ -22,6 +22,7 @@ #include #include +#include #if defined(HAVE_LIBVA) #include @@ -165,9 +166,10 @@ bool CWinSystemWayland::CreateNewWindow(const std::string& name, { if (auto output = FindOutputByWaylandOutput(wloutput)) { - CLog::Log(LOGDEBUG, "Entering output \"%s\" with scale %d", UserFriendlyOutputName(output).c_str(), output->GetScale()); + CLog::Log(LOGDEBUG, "Entering output \"%s\" with scale %d and %.3f dpi", UserFriendlyOutputName(output).c_str(), output->GetScale(), output->GetCurrentDpi()); m_surfaceOutputs.emplace(output); UpdateBufferScale(); + UpdateTouchDpi(); } else { @@ -181,6 +183,7 @@ bool CWinSystemWayland::CreateNewWindow(const std::string& name, CLog::Log(LOGDEBUG, "Leaving output \"%s\" with scale %d", UserFriendlyOutputName(output).c_str(), output->GetScale()); m_surfaceOutputs.erase(output); UpdateBufferScale(); + UpdateTouchDpi(); } else { @@ -881,6 +884,20 @@ void CWinSystemWayland::ApplyBufferScale(std::int32_t scale) } } +void CWinSystemWayland::UpdateTouchDpi() +{ + // If we have multiple outputs with wildly different DPI, this is really just + // guesswork to get a halfway reasonable value. min/max would probably also be OK. + float dpiSum = std::accumulate(m_surfaceOutputs.cbegin(), m_surfaceOutputs.cend(), 0.0f, + [](float acc, std::shared_ptr const& output) + { + return acc + output->GetCurrentDpi(); + }); + float dpi = dpiSum / m_surfaceOutputs.size(); + CLog::LogF(LOGDEBUG, "Computed average dpi of %.3f for touch handler", dpi); + CGenericTouchInputHandler::GetInstance().SetScreenDPI(dpi); +} + #if defined(HAVE_LIBVA) void* CWinSystemWayland::GetVaDisplay() { diff --git a/xbmc/windowing/wayland/WinSystemWayland.h b/xbmc/windowing/wayland/WinSystemWayland.h index fa5f1c7823130..e4028960c19cd 100644 --- a/xbmc/windowing/wayland/WinSystemWayland.h +++ b/xbmc/windowing/wayland/WinSystemWayland.h @@ -109,6 +109,7 @@ class CWinSystemWayland : public CWinSystemBase, public IInputHandler, public IC void OnOutputDone(std::uint32_t name); void UpdateBufferScale(); void ApplyBufferScale(std::int32_t scale); + void UpdateTouchDpi(); void AckConfigure(std::uint32_t serial); From 4f27057b3b678b29e6295405f650f87157b121ec Mon Sep 17 00:00:00 2001 From: Philipp Kerling Date: Fri, 14 Jul 2017 10:22:32 +0200 Subject: [PATCH 4/7] Refactor wayland input processing SeatInputProcessor has become too big --- xbmc/windowing/wayland/CMakeLists.txt | 6 + .../wayland/InputProcessorKeyboard.cpp | 172 +++++++ .../wayland/InputProcessorKeyboard.h | 83 ++++ .../wayland/InputProcessorPointer.cpp | 138 ++++++ .../windowing/wayland/InputProcessorPointer.h | 72 +++ .../windowing/wayland/InputProcessorTouch.cpp | 116 +++++ xbmc/windowing/wayland/InputProcessorTouch.h | 78 ++++ xbmc/windowing/wayland/SeatInputProcessor.cpp | 423 +++--------------- xbmc/windowing/wayland/SeatInputProcessor.h | 93 ++-- xbmc/windowing/wayland/WinSystemWayland.cpp | 2 +- 10 files changed, 765 insertions(+), 418 deletions(-) create mode 100644 xbmc/windowing/wayland/InputProcessorKeyboard.cpp create mode 100644 xbmc/windowing/wayland/InputProcessorKeyboard.h create mode 100644 xbmc/windowing/wayland/InputProcessorPointer.cpp create mode 100644 xbmc/windowing/wayland/InputProcessorPointer.h create mode 100644 xbmc/windowing/wayland/InputProcessorTouch.cpp create mode 100644 xbmc/windowing/wayland/InputProcessorTouch.h diff --git a/xbmc/windowing/wayland/CMakeLists.txt b/xbmc/windowing/wayland/CMakeLists.txt index 3a9791e9a0ed6..9e6c191eb5c4a 100644 --- a/xbmc/windowing/wayland/CMakeLists.txt +++ b/xbmc/windowing/wayland/CMakeLists.txt @@ -6,6 +6,9 @@ set_source_files_properties(${WAYLAND_EXTRA_PROTOCOL_GENERATED_DIR}/wayland-extr set(SOURCES Connection.cpp Output.cpp GLContextEGL.cpp + InputProcessorKeyboard.h + InputProcessorPointer.h + InputProcessorTouch.h OSScreenSaverIdleInhibitUnstableV1.cpp SeatInputProcessor.cpp ShellSurface.cpp @@ -19,6 +22,9 @@ set(SOURCES Connection.cpp set(HEADERS Connection.h Output.h GLContextEGL.h + InputProcessorKeyboard.cpp + InputProcessorPointer.cpp + InputProcessorTouch.cpp OSScreenSaverIdleInhibitUnstableV1.h SeatInputProcessor.h ShellSurface.h diff --git a/xbmc/windowing/wayland/InputProcessorKeyboard.cpp b/xbmc/windowing/wayland/InputProcessorKeyboard.cpp new file mode 100644 index 0000000000000..ba6cc42eb3d29 --- /dev/null +++ b/xbmc/windowing/wayland/InputProcessorKeyboard.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2017 Team XBMC + * http://xbmc.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, 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 XBMC; see the file COPYING. If not, see + * . + * + */ + +#include "InputProcessorKeyboard.h" + +#include + +#include +#include + +#include "utils/log.h" +#include "utils/ScopeGuard.h" +#include "windowing/XkbcommonKeymap.h" + +using namespace KODI::WINDOWING::WAYLAND; + +namespace +{ +// Offset between keyboard codes of Wayland (effectively evdev) and xkb_keycode_t +constexpr int WL_KEYBOARD_XKB_CODE_OFFSET = 8; +} + +CInputProcessorKeyboard::CInputProcessorKeyboard(wayland::keyboard_t const& keyboard, IInputHandlerKeyboard& handler) +: m_keyboard{keyboard}, m_handler{handler}, m_keyRepeatTimer{std::bind(&CInputProcessorKeyboard::KeyRepeatTimeout, this)} +{ + m_keyboard.on_enter() = [this](std::uint32_t serial, wayland::surface_t surface, wayland::array_t keys) + { + m_handler.OnKeyboardEnter(); + }; + m_keyboard.on_leave() = [this](std::uint32_t serial, wayland::surface_t surface) + { + m_handler.OnKeyboardLeave(); + }; + m_keyboard.on_repeat_info() = [this](std::int32_t rate, std::int32_t delay) + { + CLog::Log(LOGDEBUG, "Key repeat rate: %d cps, delay %d ms", rate, delay); + // rate is in characters per second, so convert to msec interval + m_keyRepeatInterval = (rate != 0) ? static_cast (1000.0f / rate) : 0; + m_keyRepeatDelay = delay; + }; + m_keyboard.on_keymap() = [this](wayland::keyboard_keymap_format format, int fd, std::uint32_t size) + { + KODI::UTILS::CScopeGuard fdGuard(close, fd); + + if (format != wayland::keyboard_keymap_format::xkb_v1) + { + CLog::Log(LOGWARNING, "Wayland compositor sent keymap in format %u, but we only understand xkbv1 - keyboard input will not work", format); + return; + } + + m_keyRepeatTimer.Stop(); + + try + { + if (!m_xkbContext) + { + // Lazily initialize XkbcommonContext + m_xkbContext.reset(new CXkbcommonContext); + } + + m_keymap.reset(m_xkbContext->KeymapFromSharedMemory(fd, size)); + } + catch(std::exception& e) + { + CLog::Log(LOGERROR, "Could not parse keymap from compositor: %s - continuing without keymap", e.what()); + } + }; + m_keyboard.on_key() = [this](std::uint32_t serial, std::uint32_t time, std::uint32_t key, wayland::keyboard_key_state state) + { + if (!m_keymap) + { + CLog::Log(LOGWARNING, "Key event for code %u without valid keymap, ignoring", key); + return; + } + + ConvertAndSendKey(key, state == wayland::keyboard_key_state::pressed); + }; + m_keyboard.on_modifiers() = [this](std::uint32_t serial, std::uint32_t modsDepressed, std::uint32_t modsLatched, std::uint32_t modsLocked, std::uint32_t group) + { + if (!m_keymap) + { + CLog::Log(LOGWARNING, "Modifier event without valid keymap, ignoring"); + return; + } + + m_keyRepeatTimer.Stop(); + m_keymap->UpdateMask(modsDepressed, modsLatched, modsLocked, group); + }; +} + +void CInputProcessorKeyboard::ConvertAndSendKey(std::uint32_t scancode, bool pressed) +{ + std::uint32_t xkbCode = scancode + WL_KEYBOARD_XKB_CODE_OFFSET; + XBMCKey xbmcKey = m_keymap->XBMCKeyForKeycode(xkbCode); + std::uint32_t utf32 = m_keymap->UnicodeCodepointForKeycode(xkbCode); + + if (utf32 > std::numeric_limits::max()) + { + // Kodi event system only supports UTF16, so ignore the codepoint if + // it does not fit + utf32 = 0; + } + if (scancode > std::numeric_limits::max()) + { + // Kodi scancodes are limited to unsigned char, pretend the scancode is unknown + // on overflow + scancode = 0; + } + + XBMC_Event event = SendKey(scancode, xbmcKey, static_cast (utf32), pressed); + + if (pressed && m_keymap->ShouldKeycodeRepeat(xkbCode) && m_keyRepeatInterval > 0) + { + // Can't modify keyToRepeat until we're sure the thread isn't accessing it + m_keyRepeatTimer.Stop(true); + // Update/Set key + m_keyToRepeat = event; + // Start timer with initial delay + m_keyRepeatTimer.Start(m_keyRepeatDelay, false); + } + else + { + m_keyRepeatTimer.Stop(); + } +} + +XBMC_Event CInputProcessorKeyboard::SendKey(unsigned char scancode, XBMCKey key, std::uint16_t unicodeCodepoint, bool pressed) +{ + assert(m_keymap); + + XBMC_Event event; + event.type = static_cast (pressed ? XBMC_KEYDOWN : XBMC_KEYUP); + event.key.keysym = + { + .scancode = scancode, + .sym = key, + .mod = m_keymap->ActiveXBMCModifiers(), + .unicode = unicodeCodepoint + }; + m_handler.OnKeyboardEvent(event); + // Return created event for convenience (key repeat) + return event; +} + +void CInputProcessorKeyboard::KeyRepeatTimeout() +{ + // Reset ourselves + m_keyRepeatTimer.RestartAsync(m_keyRepeatInterval); + // Simulate repeat: Key up and down + XBMC_Event event = m_keyToRepeat; + event.type = XBMC_KEYUP; + m_handler.OnKeyboardEvent(event); + event.type = XBMC_KEYDOWN; + m_handler.OnKeyboardEvent(event); +} diff --git a/xbmc/windowing/wayland/InputProcessorKeyboard.h b/xbmc/windowing/wayland/InputProcessorKeyboard.h new file mode 100644 index 0000000000000..98f92bc519265 --- /dev/null +++ b/xbmc/windowing/wayland/InputProcessorKeyboard.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2017 Team XBMC + * http://xbmc.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, 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 XBMC; see the file COPYING. If not, see + * . + * + */ +#pragma once + +#include +#include +#include +#include + +#include + +#include "input/XBMC_keysym.h" +#include "threads/Timer.h" +#include "windowing/XBMC_events.h" + +namespace KODI +{ +namespace WINDOWING +{ + +class CXkbcommonContext; +class CXkbcommonKeymap; + +namespace WAYLAND +{ + +class IInputHandlerKeyboard +{ +public: + virtual void OnKeyboardEnter() {} + virtual void OnKeyboardLeave() {} + virtual void OnKeyboardEvent(XBMC_Event& event) = 0; + virtual ~IInputHandlerKeyboard() = default; +}; + +class CInputProcessorKeyboard +{ +public: + CInputProcessorKeyboard(wayland::keyboard_t const& keyboard, IInputHandlerKeyboard& handler); + +private: + CInputProcessorKeyboard(CInputProcessorKeyboard const& other) = delete; + CInputProcessorKeyboard& operator=(CInputProcessorKeyboard const& other) = delete; + + void ConvertAndSendKey(std::uint32_t scancode, bool pressed); + XBMC_Event SendKey(unsigned char scancode, XBMCKey key, std::uint16_t unicodeCodepoint, bool pressed); + void KeyRepeatTimeout(); + + wayland::keyboard_t m_keyboard; + IInputHandlerKeyboard& m_handler; + + std::unique_ptr m_xkbContext; + std::unique_ptr m_keymap; + // Default values are used if compositor does not send any + std::atomic m_keyRepeatDelay{1000}; + std::atomic m_keyRepeatInterval{50}; + // Save complete XBMC_Event so no keymap lookups which might not be thread-safe + // are needed in the repeat callback + XBMC_Event m_keyToRepeat; + + CTimer m_keyRepeatTimer; +}; + +} +} +} \ No newline at end of file diff --git a/xbmc/windowing/wayland/InputProcessorPointer.cpp b/xbmc/windowing/wayland/InputProcessorPointer.cpp new file mode 100644 index 0000000000000..e28cfa5c877f8 --- /dev/null +++ b/xbmc/windowing/wayland/InputProcessorPointer.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2017 Team XBMC + * http://xbmc.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, 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 XBMC; see the file COPYING. If not, see + * . + * + */ + +#include "InputProcessorPointer.h" + +#include + +#include + +#include "input/MouseStat.h" + +using namespace KODI::WINDOWING::WAYLAND; + +namespace +{ + +int WaylandToXbmcButton(std::uint32_t button) +{ + // Wayland button is evdev code + switch (button) + { + case BTN_LEFT: + return XBMC_BUTTON_LEFT; + case BTN_MIDDLE: + return XBMC_BUTTON_MIDDLE; + case BTN_RIGHT: + return XBMC_BUTTON_RIGHT; + default: + return -1; + } +} + +} + +CInputProcessorPointer::CInputProcessorPointer(wayland::pointer_t const& pointer, IInputHandlerPointer& handler) +: m_pointer{pointer}, m_handler{handler} +{ + m_pointer.on_enter() = [this](std::uint32_t serial, wayland::surface_t surface, double surfaceX, double surfaceY) + { + m_handler.OnPointerEnter(m_pointer, serial); + SetMousePosFromSurface(surfaceX, surfaceY); + SendMouseMotion(); + }; + m_pointer.on_leave() = [this](std::uint32_t serial, wayland::surface_t surface) + { + m_handler.OnPointerLeave(); + }; + m_pointer.on_motion() = [this](std::uint32_t time, double surfaceX, double surfaceY) + { + SetMousePosFromSurface(surfaceX, surfaceY); + SendMouseMotion(); + }; + m_pointer.on_button() = [this](std::uint32_t serial, std::uint32_t time, std::uint32_t button, wayland::pointer_button_state state) + { + int xbmcButton = WaylandToXbmcButton(button); + if (xbmcButton < 0) + { + // Button is unmapped + return; + } + + bool pressed = (state == wayland::pointer_button_state::pressed); + SendMouseButton(xbmcButton, pressed); + }; + m_pointer.on_axis() = [this](std::uint32_t serial, wayland::pointer_axis axis, std::int32_t value) + { + // For axis events we only care about the vector direction + // and not the scalar magnitude. Every axis event callback + // generates one scroll button event for XBMC + + // Negative is up + unsigned char xbmcButton = (wl_fixed_to_double(value) < 0.0) ? XBMC_BUTTON_WHEELUP : XBMC_BUTTON_WHEELDOWN; + // Simulate a single click of the wheel-equivalent "button" + SendMouseButton(xbmcButton, true); + SendMouseButton(xbmcButton, false); + }; + + // Wayland groups pointer events, but right now there is no benefit in + // treating them in groups. The main use case for doing so seems to be + // multi-axis (i.e. diagnoal) scrolling, but we do not support this anyway. + /*m_pointer.on_frame() = [this]() + { + + };*/ +} + +std::uint16_t CInputProcessorPointer::ConvertMouseCoordinate(double coord) +{ + return static_cast (std::round(coord * m_coordinateScale)); +} + +void CInputProcessorPointer::SetMousePosFromSurface(double x, double y) +{ + m_pointerX = ConvertMouseCoordinate(x); + m_pointerY = ConvertMouseCoordinate(y); +} + +void CInputProcessorPointer::SendMouseMotion() +{ + XBMC_Event event; + event.type = XBMC_MOUSEMOTION; + event.motion = + { + .x = m_pointerX, + .y = m_pointerY + }; + m_handler.OnPointerEvent(event); +} + +void CInputProcessorPointer::SendMouseButton(unsigned char button, bool pressed) +{ + XBMC_Event event; + event.type = static_cast (pressed ? XBMC_MOUSEBUTTONDOWN : XBMC_MOUSEBUTTONUP); + event.button = + { + .button = button, + .x = m_pointerX, + .y = m_pointerY + }; + m_handler.OnPointerEvent(event); +} \ No newline at end of file diff --git a/xbmc/windowing/wayland/InputProcessorPointer.h b/xbmc/windowing/wayland/InputProcessorPointer.h new file mode 100644 index 0000000000000..600dec70da68b --- /dev/null +++ b/xbmc/windowing/wayland/InputProcessorPointer.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2017 Team XBMC + * http://xbmc.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, 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 XBMC; see the file COPYING. If not, see + * . + * + */ +#pragma once + +#include +#include + +#include + +#include "input/XBMC_keysym.h" +#include "windowing/XBMC_events.h" + +namespace KODI +{ +namespace WINDOWING +{ +namespace WAYLAND +{ + +class IInputHandlerPointer +{ +public: + virtual void OnPointerEnter(wayland::pointer_t& pointer, std::uint32_t serial) {}; + virtual void OnPointerLeave() {}; + virtual void OnPointerEvent(XBMC_Event& event) = 0; + virtual ~IInputHandlerPointer() = default; +}; + +class CInputProcessorPointer +{ +public: + CInputProcessorPointer(wayland::pointer_t const& pointer, IInputHandlerPointer& handler); + void SetCoordinateScale(std::int32_t scale) { m_coordinateScale = scale; } + +private: + CInputProcessorPointer(CInputProcessorPointer const& other) = delete; + CInputProcessorPointer& operator=(CInputProcessorPointer const& other) = delete; + + std::uint16_t ConvertMouseCoordinate(double coord); + void SetMousePosFromSurface(double x, double y); + void SendMouseMotion(); + void SendMouseButton(unsigned char button, bool pressed); + + wayland::pointer_t m_pointer; + IInputHandlerPointer& m_handler; + + // Pointer position in *scaled* coordinates + std::uint16_t m_pointerX{}; + std::uint16_t m_pointerY{}; + std::int32_t m_coordinateScale{1}; +}; + +} +} +} \ No newline at end of file diff --git a/xbmc/windowing/wayland/InputProcessorTouch.cpp b/xbmc/windowing/wayland/InputProcessorTouch.cpp new file mode 100644 index 0000000000000..414999a9a7c1b --- /dev/null +++ b/xbmc/windowing/wayland/InputProcessorTouch.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2017 Team XBMC + * http://xbmc.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, 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 XBMC; see the file COPYING. If not, see + * . + * + */ + +#include "InputProcessorTouch.h" + +#include "input/touch/generic/GenericTouchInputHandler.h" + +using namespace KODI::WINDOWING::WAYLAND; + +CInputProcessorTouch::CInputProcessorTouch(wayland::touch_t const& touch) +: m_touch{touch} +{ + m_touch.on_down() = [this](std::uint32_t serial, std::uint32_t time, wayland::surface_t surface, std::int32_t id, double x, double y) + { + // Find free Kodi pointer number + int kodiPointer = -1; + // Not optimal, but irrelevant for the small number of iterations + for (int testPointer = 0; testPointer < TOUCH_MAX_POINTERS; testPointer++) + { + if (std::all_of(m_touchPoints.cbegin(), m_touchPoints.cend(), + [=](decltype(m_touchPoints)::value_type const& pair) + { + return (pair.second.kodiPointerNumber != testPointer); + })) + { + kodiPointer = testPointer; + break; + } + } + + if (kodiPointer != -1) + { + auto it = m_touchPoints.emplace(std::piecewise_construct, std::forward_as_tuple(id), std::forward_as_tuple(time, kodiPointer, x * m_coordinateScale, y * m_coordinateScale, 0.0f)).first; + SendTouchPointEvent(TouchInputDown, it->second); + } + }; + m_touch.on_up() = [this](std::uint32_t serial, std::uint32_t time, std::int32_t id) + { + auto it = m_touchPoints.find(id); + if (it != m_touchPoints.end()) + { + auto& point = it->second; + point.lastEventTime = time; + SendTouchPointEvent(TouchInputUp, point); + m_touchPoints.erase(it); + } + }; + m_touch.on_motion() = [this](std::uint32_t time, std::int32_t id, double x, double y) + { + auto it = m_touchPoints.find(id); + if (it != m_touchPoints.end()) + { + auto& point = it->second; + point.x = x * m_coordinateScale; + point.y = y * m_coordinateScale; + point.lastEventTime = time; + SendTouchPointEvent(TouchInputMove, point); + } + }; + m_touch.on_cancel() = [this]() + { + // TouchInputAbort aborts for all pointers, so it does not matter which is specified + if (!m_touchPoints.empty()) + { + SendTouchPointEvent(TouchInputAbort, m_touchPoints.begin()->second); + } + m_touchPoints.clear(); + }; + m_touch.on_shape() = [this](std::int32_t id, double major, double minor) + { + auto it = m_touchPoints.find(id); + if (it != m_touchPoints.end()) + { + auto& point = it->second; + // Kodi only supports size without shape, so use average of both axes + point.size = ((major + minor) / 2.0) * m_coordinateScale; + UpdateTouchPoint(point); + } + }; +} + +void CInputProcessorTouch::SendTouchPointEvent(TouchInput event, const TouchPoint& point) +{ + if (event == TouchInputMove) + { + for (auto const& point : m_touchPoints) + { + // Contrary to the docs, this must be called before HandleTouchInput or the + // position will not be updated and gesture detection will not work + UpdateTouchPoint(point.second); + } + } + CGenericTouchInputHandler::GetInstance().HandleTouchInput(event, point.x, point.y, point.lastEventTime * INT64_C(1000000), point.kodiPointerNumber, point.size); +} + +void CInputProcessorTouch::UpdateTouchPoint(const TouchPoint& point) +{ + CGenericTouchInputHandler::GetInstance().UpdateTouchPointer(point.kodiPointerNumber, point.x, point.y, point.lastEventTime * INT64_C(1000000), point.size); +} diff --git a/xbmc/windowing/wayland/InputProcessorTouch.h b/xbmc/windowing/wayland/InputProcessorTouch.h new file mode 100644 index 0000000000000..0558f4b6ab4a6 --- /dev/null +++ b/xbmc/windowing/wayland/InputProcessorTouch.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2017 Team XBMC + * http://xbmc.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, 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 XBMC; see the file COPYING. If not, see + * . + * + */ +#pragma once + +#include +#include + +#include + +#include "input/touch/ITouchInputHandler.h" + +namespace KODI +{ +namespace WINDOWING +{ +namespace WAYLAND +{ + +/** + * Touch input processor + * + * Events go directly to \ref CGenericTouchInputHandler, so no callbacks here + */ +class CInputProcessorTouch +{ +public: + CInputProcessorTouch(wayland::touch_t const& touch); + void SetCoordinateScale(std::int32_t scale) { m_coordinateScale = scale; } + +private: + CInputProcessorTouch(CInputProcessorTouch const& other) = delete; + CInputProcessorTouch& operator=(CInputProcessorTouch const& other) = delete; + + struct TouchPoint + { + std::uint32_t lastEventTime; + /// Pointer number passed to \ref ITouchInputHandler + std::int32_t kodiPointerNumber; + /** + * Last coordinates - needed for TouchInputUp events where Wayland does not + * send new coordinates but Kodi needs them anyway + */ + float x, y, size; + TouchPoint(std::uint32_t initialEventTime, std::int32_t kodiPointerNumber, float x, float y, float size) + : lastEventTime(initialEventTime), kodiPointerNumber(kodiPointerNumber), x(x), y(y), size(size) + {} + }; + + void SendTouchPointEvent(TouchInput event, TouchPoint const& point); + void UpdateTouchPoint(TouchPoint const& point); + + wayland::touch_t m_touch; + std::int32_t m_coordinateScale{1}; + + /// Map of wl_touch point id to data + std::map m_touchPoints; +}; + +} +} +} \ No newline at end of file diff --git a/xbmc/windowing/wayland/SeatInputProcessor.cpp b/xbmc/windowing/wayland/SeatInputProcessor.cpp index 17c2bad1a65f2..8161ba809bb97 100644 --- a/xbmc/windowing/wayland/SeatInputProcessor.cpp +++ b/xbmc/windowing/wayland/SeatInputProcessor.cpp @@ -18,21 +18,12 @@ * */ -#include - -#include -#include -#include - -#include -#include - -#include "input/MouseStat.h" -#include "input/touch/generic/GenericTouchInputHandler.h" #include "SeatInputProcessor.h" + #include "utils/log.h" using namespace KODI::WINDOWING::WAYLAND; +using namespace std::placeholders; namespace { @@ -41,32 +32,33 @@ namespace * Handle change of availability of a wl_seat input capability * * This checks whether the capability is currently available with the wl_seat - * and whether it was bound to an instance. If there is a mismatch between - * these two, the instance is destroyed if a capability was removed or created + * and whether it was bound to a processor. If there is a mismatch between + * these two, the processor is destroyed if a capability was removed or created * if a capability was added. * * \param handler CSeatInputProcessor instance * \param caps new capabilities * \param cap capability to check for * \param capName human-readable name of the capability for log messages - * \param instance reference to the Wayland protocol instance that holds the - * protocol corresponding to the capability + * \param processor reference to a smart pointer that holds the + * processor corresponding to the capability * \param instanceProvider function that functions as factory for the Wayland * protocol instance if the capability has been added * \param onNewCapability function that is called after setting the new capability * instance when it was added */ -template +template void HandleCapabilityChange(CSeatInputProcessor* handler, wayland::seat_capability caps, wayland::seat_capability cap, - std::string const & capName, T& instance, - std::function const & instanceProvider, - std::function const & onNewCapability = std::function()) + std::string const & capName, + ProcessorPtrT& processor, + InstanceProviderT instanceProvider, + OnNewCapabilityT onNewCapability) { bool hasCapability = caps & cap; - if (instance.proxy_has_object() != hasCapability) + if ((!!processor) != hasCapability) { // Capability changed @@ -74,44 +66,22 @@ void HandleCapabilityChange(CSeatInputProcessor* handler, { // The capability was added CLog::Log(LOGDEBUG, "Wayland seat %s gained capability %s", handler->GetName().c_str(), capName.c_str()); - instance = instanceProvider(); - onNewCapability(); + onNewCapability(instanceProvider()); } else { // The capability was removed CLog::Log(LOGDEBUG, "Wayland seat %s lost capability %s", handler->GetName().c_str(), capName.c_str()); - instance.proxy_release(); + processor.reset(); } } }; -int WaylandToXbmcButton(std::uint32_t button) -{ - // Wayland button is evdev code - switch (button) - { - case BTN_LEFT: - return XBMC_BUTTON_LEFT; - case BTN_MIDDLE: - return XBMC_BUTTON_MIDDLE; - case BTN_RIGHT: - return XBMC_BUTTON_RIGHT; - default: - return -1; - } } -// Offset between keyboard codes of Wayland (effectively evdev) and xkb_keycode_t -constexpr int WL_KEYBOARD_XKB_CODE_OFFSET = 8; - -} - -CSeatInputProcessor::CSeatInputProcessor(std::uint32_t globalName, const wayland::seat_t& seat, IInputHandler* handler) -: m_globalName(globalName), m_seat(seat), m_handler(handler), m_keyRepeatCallback(this), m_keyRepeatTimer(&m_keyRepeatCallback) +CSeatInputProcessor::CSeatInputProcessor(std::uint32_t globalName, const wayland::seat_t& seat, IInputHandler& handler) +: m_globalName(globalName), m_seat(seat), m_handler(handler) { - assert(m_handler); - m_seat.on_name() = [this](std::string name) { m_name = name; @@ -119,345 +89,98 @@ CSeatInputProcessor::CSeatInputProcessor(std::uint32_t globalName, const wayland m_seat.on_capabilities() = std::bind(&CSeatInputProcessor::HandleOnCapabilities, this, std::placeholders::_1); } +CSeatInputProcessor::~CSeatInputProcessor() = default; + void CSeatInputProcessor::HandleOnCapabilities(wayland::seat_capability caps) { - HandleCapabilityChange(this, - caps, - wayland::seat_capability::pointer, - "pointer", - m_pointer, - static_cast> (std::bind(&wayland::seat_t::get_pointer, &m_seat)), - std::bind(&CSeatInputProcessor::HandlePointerCapability, this)); - HandleCapabilityChange(this, - caps, - wayland::seat_capability::keyboard, - "keyboard", - m_keyboard, - static_cast> (std::bind(&wayland::seat_t::get_keyboard, &m_seat)), - std::bind(&CSeatInputProcessor::HandleKeyboardCapability, this)); - HandleCapabilityChange(this, - caps, - wayland::seat_capability::touch, - "touch", - m_touch, - static_cast> (std::bind(&wayland::seat_t::get_touch, &m_seat)), - std::bind(&CSeatInputProcessor::HandleTouchCapability, this)); + HandleCapabilityChange + (this, + caps, + wayland::seat_capability::pointer, + "pointer", + m_pointer, + std::bind(&wayland::seat_t::get_pointer, &m_seat), + std::bind(&CSeatInputProcessor::HandlePointerCapability, this, _1)); + HandleCapabilityChange + (this, + caps, + wayland::seat_capability::keyboard, + "keyboard", + m_keyboard, + std::bind(&wayland::seat_t::get_keyboard, &m_seat), + std::bind(&CSeatInputProcessor::HandleKeyboardCapability, this, _1)); + HandleCapabilityChange + (this, + caps, + wayland::seat_capability::touch, + "touch", + m_touch, + std::bind(&wayland::seat_t::get_touch, &m_seat), + std::bind(&CSeatInputProcessor::HandleTouchCapability, this, _1)); } -std::uint16_t CSeatInputProcessor::ConvertMouseCoordinate(double coord) +void CSeatInputProcessor::HandlePointerCapability(wayland::pointer_t const& pointer) { - return static_cast (std::round(coord * m_coordinateScale)); + m_pointer.reset(new CInputProcessorPointer(pointer, static_cast (*this))); + UpdateCoordinateScale(); } -void CSeatInputProcessor::SetMousePosFromSurface(double x, double y) +void CSeatInputProcessor::OnPointerEnter(wayland::pointer_t& pointer, std::uint32_t serial) { - m_pointerX = ConvertMouseCoordinate(x); - m_pointerY = ConvertMouseCoordinate(y); + m_handler.OnSetCursor(pointer, serial); + m_handler.OnEnter(m_globalName, InputType::POINTER); } -void CSeatInputProcessor::HandlePointerCapability() +void CSeatInputProcessor::OnPointerLeave() { - m_pointer.on_enter() = [this](std::uint32_t serial, wayland::surface_t surface, double surfaceX, double surfaceY) - { - m_handler->OnSetCursor(m_pointer, serial); - m_handler->OnEnter(m_globalName, InputType::POINTER); - SetMousePosFromSurface(surfaceX, surfaceY); - SendMouseMotion(); - }; - m_pointer.on_leave() = [this](std::uint32_t serial, wayland::surface_t surface) - { - m_handler->OnLeave(m_globalName, InputType::POINTER); - }; - m_pointer.on_motion() = [this](std::uint32_t time, double surfaceX, double surfaceY) - { - SetMousePosFromSurface(surfaceX, surfaceY); - SendMouseMotion(); - }; - m_pointer.on_button() = [this](std::uint32_t serial, std::uint32_t time, std::uint32_t button, wayland::pointer_button_state state) - { - int xbmcButton = WaylandToXbmcButton(button); - if (xbmcButton < 0) - { - // Button is unmapped - return; - } - - bool pressed = (state == wayland::pointer_button_state::pressed); - SendMouseButton(xbmcButton, pressed); - }; - m_pointer.on_axis() = [this](std::uint32_t serial, wayland::pointer_axis axis, std::int32_t value) - { - // For axis events we only care about the vector direction - // and not the scalar magnitude. Every axis event callback - // generates one scroll button event for XBMC - - // Negative is up - unsigned char xbmcButton = (wl_fixed_to_double(value) < 0.0) ? XBMC_BUTTON_WHEELUP : XBMC_BUTTON_WHEELDOWN; - // Simulate a single click of the wheel-equivalent "button" - SendMouseButton(xbmcButton, true); - SendMouseButton(xbmcButton, false); - }; - - // Wayland groups pointer events, but right now there is no benefit in - // treating them in groups. The main use case for doing so seems to be - // multi-axis (i.e. diagnoal) scrolling, but we do not support this anyway. - /*m_pointer.on_frame() = [this]() - { - - };*/ + m_handler.OnLeave(m_globalName, InputType::POINTER); } -void CSeatInputProcessor::SendMouseMotion() +void CSeatInputProcessor::OnPointerEvent(XBMC_Event& event) { - XBMC_Event event; - event.type = XBMC_MOUSEMOTION; - event.motion = - { - .x = m_pointerX, - .y = m_pointerY - }; - m_handler->OnEvent(m_globalName, InputType::POINTER, event); + m_handler.OnEvent(m_globalName, InputType::POINTER, event); } -void CSeatInputProcessor::SendMouseButton(unsigned char button, bool pressed) +void CSeatInputProcessor::HandleKeyboardCapability(wayland::keyboard_t const& keyboard) { - XBMC_Event event; - event.type = static_cast (pressed ? XBMC_MOUSEBUTTONDOWN : XBMC_MOUSEBUTTONUP); - event.button = - { - .button = button, - .x = m_pointerX, - .y = m_pointerY - }; - m_handler->OnEvent(m_globalName, InputType::POINTER, event); + m_keyboard.reset(new CInputProcessorKeyboard(keyboard, static_cast (*this))); } -void CSeatInputProcessor::HandleKeyboardCapability() +void CSeatInputProcessor::OnKeyboardEnter() { - m_keyboard.on_enter() = [this](std::uint32_t serial, wayland::surface_t surface, wayland::array_t keys) - { - m_handler->OnEnter(m_globalName, InputType::KEYBOARD); - }; - m_keyboard.on_leave() = [this](std::uint32_t serial, wayland::surface_t surface) - { - m_handler->OnLeave(m_globalName, InputType::KEYBOARD); - }; - m_keyboard.on_repeat_info() = [this](std::int32_t rate, std::int32_t delay) - { - CLog::Log(LOGDEBUG, "Seat %s key repeat rate: %d cps, delay %d ms", m_name.c_str(), rate, delay); - // rate is in characters per second, so convert to msec interval - m_keyRepeatInterval = (rate != 0) ? static_cast (1000.0f / rate) : 0; - m_keyRepeatDelay = delay; - }; - m_keyboard.on_keymap() = [this](wayland::keyboard_keymap_format format, int fd, std::uint32_t size) - { - if (format != wayland::keyboard_keymap_format::xkb_v1) - { - CLog::Log(LOGWARNING, "Wayland compositor sent keymap in format %u, but we only understand xkbv1 - keyboard input will not work", format); - // File descriptor should always be closed - close(fd); - return; - } - - m_keyRepeatTimer.Stop(); - - try - { - if (!m_xkbContext) - { - // Lazily initialize XkbcommonContext - m_xkbContext.reset(new CXkbcommonContext); - } - - m_keymap.reset(m_xkbContext->KeymapFromSharedMemory(fd, size)); - } - catch(std::exception& e) - { - CLog::Log(LOGERROR, "Could not parse keymap from compositor: %s - continuing without keymap", e.what()); - } - - close(fd); - }; - m_keyboard.on_key() = [this](std::uint32_t serial, std::uint32_t time, std::uint32_t key, wayland::keyboard_key_state state) - { - if (!m_keymap) - { - CLog::Log(LOGWARNING, "Key event for code %u without valid keymap, ignoring", key); - return; - } - - ConvertAndSendKey(key, state == wayland::keyboard_key_state::pressed); - }; - m_keyboard.on_modifiers() = [this](std::uint32_t serial, std::uint32_t modsDepressed, std::uint32_t modsLatched, std::uint32_t modsLocked, std::uint32_t group) - { - if (!m_keymap) - { - CLog::Log(LOGWARNING, "Modifier event without valid keymap, ignoring"); - return; - } - - m_keyRepeatTimer.Stop(); - m_keymap->UpdateMask(modsDepressed, modsLatched, modsLocked, group); - }; + m_handler.OnEnter(m_globalName, InputType::KEYBOARD); } -void CSeatInputProcessor::ConvertAndSendKey(std::uint32_t scancode, bool pressed) +void CSeatInputProcessor::OnKeyboardLeave() { - std::uint32_t xkbCode = scancode + WL_KEYBOARD_XKB_CODE_OFFSET; - XBMCKey xbmcKey = m_keymap->XBMCKeyForKeycode(xkbCode); - std::uint32_t utf32 = m_keymap->UnicodeCodepointForKeycode(xkbCode); - - if (utf32 > std::numeric_limits::max()) - { - // Kodi event system only supports UTF16, so ignore the codepoint if - // it does not fit - utf32 = 0; - } - if (scancode > std::numeric_limits::max()) - { - // Kodi scancodes are limited to unsigned char, pretend the scancode is unknown - // on overflow - scancode = 0; - } - - XBMC_Event event = SendKey(scancode, xbmcKey, static_cast (utf32), pressed); - - if (pressed && m_keymap->ShouldKeycodeRepeat(xkbCode) && m_keyRepeatInterval > 0) - { - // Can't modify keyToRepeat until we're sure the thread isn't accessing it - m_keyRepeatTimer.Stop(true); - // Update/Set key - m_keyToRepeat = event; - // Start timer with initial delay - m_keyRepeatTimer.Start(m_keyRepeatDelay, false); - } - else - { - m_keyRepeatTimer.Stop(); - } + m_handler.OnLeave(m_globalName, InputType::KEYBOARD); } -XBMC_Event CSeatInputProcessor::SendKey(unsigned char scancode, XBMCKey key, std::uint16_t unicodeCodepoint, bool pressed) +void CSeatInputProcessor::OnKeyboardEvent(XBMC_Event& event) { - assert(m_keymap); - - XBMC_Event event; - event.type = static_cast (pressed ? XBMC_KEYDOWN : XBMC_KEYUP); - event.key.keysym = - { - .scancode = scancode, - .sym = key, - .mod = m_keymap->ActiveXBMCModifiers(), - .unicode = unicodeCodepoint - }; - m_handler->OnEvent(m_globalName, InputType::KEYBOARD, event); - // Return created event for convenience (key repeat) - return event; + m_handler.OnEvent(m_globalName, InputType::KEYBOARD, event); } -CSeatInputProcessor::CKeyRepeatCallback::CKeyRepeatCallback(CSeatInputProcessor* processor) -: m_processor(processor) +void CSeatInputProcessor::HandleTouchCapability(wayland::touch_t const& touch) { + m_touch.reset(new CInputProcessorTouch(touch)); + UpdateCoordinateScale(); } -void CSeatInputProcessor::CKeyRepeatCallback::OnTimeout() +void CSeatInputProcessor::SetCoordinateScale(std::int32_t scale) { - // Reset ourselves - m_processor->m_keyRepeatTimer.RestartAsync(m_processor->m_keyRepeatInterval); - // Simulate repeat: Key up and down - XBMC_Event event = m_processor->m_keyToRepeat; - event.type = XBMC_KEYUP; - m_processor->m_handler->OnEvent(m_processor->m_globalName, InputType::KEYBOARD, event); - event.type = XBMC_KEYDOWN; - m_processor->m_handler->OnEvent(m_processor->m_globalName, InputType::KEYBOARD, event); + m_coordinateScale = scale; + UpdateCoordinateScale(); } -void CSeatInputProcessor::HandleTouchCapability() +void CSeatInputProcessor::UpdateCoordinateScale() { - m_touch.on_down() = [this](std::uint32_t serial, std::uint32_t time, wayland::surface_t surface, std::int32_t id, double x, double y) - { - // Find free Kodi pointer number - int kodiPointer = -1; - // Not optimal, but irrelevant for the small number of iterations - for (int testPointer = 0; testPointer < TOUCH_MAX_POINTERS; testPointer++) - { - if (std::all_of(m_touchPoints.cbegin(), m_touchPoints.cend(), - [=](decltype(m_touchPoints)::value_type const& pair) - { - return (pair.second.kodiPointerNumber != testPointer); - })) - { - kodiPointer = testPointer; - break; - } - } - - if (kodiPointer != -1) - { - auto it = m_touchPoints.emplace(std::piecewise_construct, std::forward_as_tuple(id), std::forward_as_tuple(time, kodiPointer, x * m_coordinateScale, y * m_coordinateScale, 0.0f)).first; - SendTouchPointEvent(TouchInputDown, it->second); - } - }; - m_touch.on_up() = [this](std::uint32_t serial, std::uint32_t time, std::int32_t id) + if (m_pointer) { - auto it = m_touchPoints.find(id); - if (it != m_touchPoints.end()) - { - auto& point = it->second; - point.lastEventTime = time; - SendTouchPointEvent(TouchInputUp, point); - m_touchPoints.erase(it); - } - }; - m_touch.on_motion() = [this](std::uint32_t time, std::int32_t id, double x, double y) - { - auto it = m_touchPoints.find(id); - if (it != m_touchPoints.end()) - { - auto& point = it->second; - point.x = x * m_coordinateScale; - point.y = y * m_coordinateScale; - point.lastEventTime = time; - SendTouchPointEvent(TouchInputMove, point); - } - }; - m_touch.on_cancel() = [this]() - { - // TouchInputAbort aborts for all pointers, so it does not matter which is specified - if (!m_touchPoints.empty()) - { - SendTouchPointEvent(TouchInputAbort, m_touchPoints.begin()->second); - } - m_touchPoints.clear(); - }; - m_touch.on_shape() = [this](std::int32_t id, double major, double minor) - { - auto it = m_touchPoints.find(id); - if (it != m_touchPoints.end()) - { - auto& point = it->second; - // Kodi only supports size without shape, so use average of both axes - point.size = ((major + minor) / 2.0) * m_coordinateScale; - UpdateTouchPoint(point); - } - }; -} - -void CSeatInputProcessor::SendTouchPointEvent(TouchInput event, const TouchPoint& point) -{ - if (event == TouchInputMove) + m_pointer->SetCoordinateScale(m_coordinateScale); + } + if (m_touch) { - for (auto const& point : m_touchPoints) - { - // Contrary to the docs, this must be called before HandleTouchInput or the - // position will not be updated and gesture detection will not work - UpdateTouchPoint(point.second); - } + m_touch->SetCoordinateScale(m_coordinateScale); } - CGenericTouchInputHandler::GetInstance().HandleTouchInput(event, point.x, point.y, point.lastEventTime * INT64_C(1000000), point.kodiPointerNumber, point.size); -} - -void CSeatInputProcessor::UpdateTouchPoint(const TouchPoint& point) -{ - CGenericTouchInputHandler::GetInstance().UpdateTouchPointer(point.kodiPointerNumber, point.x, point.y, point.lastEventTime * INT64_C(1000000), point.size); -} +} \ No newline at end of file diff --git a/xbmc/windowing/wayland/SeatInputProcessor.h b/xbmc/windowing/wayland/SeatInputProcessor.h index 7c3d86f2c9c18..2ace5a190329b 100644 --- a/xbmc/windowing/wayland/SeatInputProcessor.h +++ b/xbmc/windowing/wayland/SeatInputProcessor.h @@ -25,6 +25,9 @@ #include #include "input/touch/ITouchInputHandler.h" +#include "InputProcessorPointer.h" +#include "InputProcessorKeyboard.h" +#include "InputProcessorTouch.h" #include "threads/Timer.h" #include "windowing/XBMC_events.h" #include "windowing/XkbcommonKeymap.h" @@ -87,7 +90,7 @@ class IInputHandler /** * Handle all wl_seat-related events and process them into Kodi events */ -class CSeatInputProcessor +class CSeatInputProcessor : IInputHandlerPointer, IInputHandlerKeyboard { public: /** @@ -96,7 +99,8 @@ class CSeatInputProcessor * \param seat bound seat_t instance * \param handler handler that receives events from this seat, must not be null */ - CSeatInputProcessor(std::uint32_t globalName, wayland::seat_t const & seat, IInputHandler* handler); + CSeatInputProcessor(std::uint32_t globalName, wayland::seat_t const & seat, IInputHandler& handler); + ~CSeatInputProcessor(); std::uint32_t GetGlobalName() const { return m_globalName; @@ -107,92 +111,47 @@ class CSeatInputProcessor } bool HasPointerCapability() const { - return m_pointer; + return !!m_pointer; } bool HasKeyboardCapability() const { - return m_keyboard; + return !!m_keyboard; } bool HasTouchCapability() const { - return m_touch; - } - void SetCoordinateScale(std::int32_t scale) - { - m_coordinateScale = scale; + return !!m_touch; } + void SetCoordinateScale(std::int32_t scale); private: CSeatInputProcessor(CSeatInputProcessor const& other) = delete; CSeatInputProcessor& operator=(CSeatInputProcessor const& other) = delete; void HandleOnCapabilities(wayland::seat_capability caps); - void HandlePointerCapability(); - void HandleKeyboardCapability(); - void HandleTouchCapability(); + void HandlePointerCapability(wayland::pointer_t const& pointer); + void HandleKeyboardCapability(wayland::keyboard_t const& keyboard); + void HandleTouchCapability(wayland::touch_t const& touch); - std::uint16_t ConvertMouseCoordinate(double coord); - void SetMousePosFromSurface(double x, double y); - void SendMouseMotion(); - void SendMouseButton(unsigned char button, bool pressed); - - void ConvertAndSendKey(std::uint32_t scancode, bool pressed); - XBMC_Event SendKey(unsigned char scancode, XBMCKey key, std::uint16_t unicodeCodepoint, bool pressed); + void OnKeyboardEnter() override; + void OnKeyboardLeave() override; + void OnKeyboardEvent(XBMC_Event& event) override; - struct TouchPoint - { - std::uint32_t lastEventTime; - /// Pointer number passed to \ref ITouchInputHandler - std::int32_t kodiPointerNumber; - /** - * Last coordinates - needed for TouchInputUp events where Wayland does not - * send new coordinates but Kodi needs them anyway - */ - float x, y, size; - TouchPoint(std::uint32_t initialEventTime, std::int32_t kodiPointerNumber, float x, float y, float size) - : lastEventTime(initialEventTime), kodiPointerNumber(kodiPointerNumber), x(x), y(y), size(size) - {} - }; + void OnPointerEnter(wayland::pointer_t& pointer, std::uint32_t serial) override; + void OnPointerLeave() override; + void OnPointerEvent(XBMC_Event& event) override; - void SendTouchPointEvent(TouchInput event, TouchPoint const& point); - void UpdateTouchPoint(TouchPoint const& point); + void UpdateCoordinateScale(); std::uint32_t m_globalName; wayland::seat_t m_seat; - std::string m_name = ""; + std::string m_name{""}; + std::int32_t m_coordinateScale{1}; - IInputHandler* m_handler = nullptr; - - wayland::pointer_t m_pointer; - wayland::keyboard_t m_keyboard; - wayland::touch_t m_touch; + IInputHandler& m_handler; - std::int32_t m_coordinateScale = 1; - // Pointer position in *scaled* coordinates - std::uint16_t m_pointerX = 0; - std::uint16_t m_pointerY = 0; - - std::unique_ptr m_xkbContext; - std::unique_ptr m_keymap; - // Default values are used if compositor does not send any - std::atomic m_keyRepeatDelay = {1000}; - std::atomic m_keyRepeatInterval = {50}; - // Save complete XBMC_Event so no keymap lookups which might not be thread-safe - // are needed in the repeat callback - XBMC_Event m_keyToRepeat; - - class CKeyRepeatCallback : public ITimerCallback - { - CSeatInputProcessor* m_processor; - public: - CKeyRepeatCallback(CSeatInputProcessor* processor); - void OnTimeout() override; - }; - CKeyRepeatCallback m_keyRepeatCallback; - CTimer m_keyRepeatTimer; - - /// Map of wl_touch point id to data - std::map m_touchPoints; + std::unique_ptr m_pointer; + std::unique_ptr m_keyboard; + std::unique_ptr m_touch; }; } diff --git a/xbmc/windowing/wayland/WinSystemWayland.cpp b/xbmc/windowing/wayland/WinSystemWayland.cpp index 497bffd258aee..b6b31260c8956 100644 --- a/xbmc/windowing/wayland/WinSystemWayland.cpp +++ b/xbmc/windowing/wayland/WinSystemWayland.cpp @@ -739,7 +739,7 @@ void CWinSystemWayland::Unregister(IDispResource* resource) void CWinSystemWayland::OnSeatAdded(std::uint32_t name, wayland::seat_t& seat) { CSingleLock lock(m_seatProcessorsMutex); - auto newSeatEmplace = m_seatProcessors.emplace(std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple(name, seat, this)); + auto newSeatEmplace = m_seatProcessors.emplace(std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple(name, seat, *this)); newSeatEmplace.first->second.SetCoordinateScale(m_scale); } From 19a2815b5a96a8a923c8b2eedbc7421a278920c5 Mon Sep 17 00:00:00 2001 From: Philipp Kerling Date: Fri, 14 Jul 2017 10:25:36 +0200 Subject: [PATCH 5/7] Rename SeatInputProcessor -> Seat so the seat can also handle this unrelated to input --- xbmc/windowing/wayland/CMakeLists.txt | 4 +- .../{SeatInputProcessor.cpp => Seat.cpp} | 42 +++++++++---------- .../wayland/{SeatInputProcessor.h => Seat.h} | 10 ++--- xbmc/windowing/wayland/WinSystemWayland.h | 4 +- 4 files changed, 30 insertions(+), 30 deletions(-) rename xbmc/windowing/wayland/{SeatInputProcessor.cpp => Seat.cpp} (75%) rename xbmc/windowing/wayland/{SeatInputProcessor.h => Seat.h} (92%) diff --git a/xbmc/windowing/wayland/CMakeLists.txt b/xbmc/windowing/wayland/CMakeLists.txt index 9e6c191eb5c4a..4e10373666c88 100644 --- a/xbmc/windowing/wayland/CMakeLists.txt +++ b/xbmc/windowing/wayland/CMakeLists.txt @@ -10,7 +10,7 @@ set(SOURCES Connection.cpp InputProcessorPointer.h InputProcessorTouch.h OSScreenSaverIdleInhibitUnstableV1.cpp - SeatInputProcessor.cpp + Seat.cpp ShellSurface.cpp ShellSurfaceWlShell.cpp ShellSurfaceXdgShellUnstableV6.cpp @@ -26,7 +26,7 @@ set(HEADERS Connection.h InputProcessorPointer.cpp InputProcessorTouch.cpp OSScreenSaverIdleInhibitUnstableV1.h - SeatInputProcessor.h + Seat.h ShellSurface.h ShellSurfaceWlShell.h ShellSurfaceXdgShellUnstableV6.h diff --git a/xbmc/windowing/wayland/SeatInputProcessor.cpp b/xbmc/windowing/wayland/Seat.cpp similarity index 75% rename from xbmc/windowing/wayland/SeatInputProcessor.cpp rename to xbmc/windowing/wayland/Seat.cpp index 8161ba809bb97..5f89f6db1c247 100644 --- a/xbmc/windowing/wayland/SeatInputProcessor.cpp +++ b/xbmc/windowing/wayland/Seat.cpp @@ -18,7 +18,7 @@ * */ -#include "SeatInputProcessor.h" +#include "Seat.h" #include "utils/log.h" @@ -36,7 +36,7 @@ namespace * these two, the processor is destroyed if a capability was removed or created * if a capability was added. * - * \param handler CSeatInputProcessor instance + * \param handler CSeat instance * \param caps new capabilities * \param cap capability to check for * \param capName human-readable name of the capability for log messages @@ -48,7 +48,7 @@ namespace * instance when it was added */ template -void HandleCapabilityChange(CSeatInputProcessor* handler, +void HandleCapabilityChange(CSeat* handler, wayland::seat_capability caps, wayland::seat_capability cap, std::string const & capName, @@ -79,19 +79,19 @@ void HandleCapabilityChange(CSeatInputProcessor* handler, } -CSeatInputProcessor::CSeatInputProcessor(std::uint32_t globalName, const wayland::seat_t& seat, IInputHandler& handler) +CSeat::CSeat(std::uint32_t globalName, const wayland::seat_t& seat, IInputHandler& handler) : m_globalName(globalName), m_seat(seat), m_handler(handler) { m_seat.on_name() = [this](std::string name) { m_name = name; }; - m_seat.on_capabilities() = std::bind(&CSeatInputProcessor::HandleOnCapabilities, this, std::placeholders::_1); + m_seat.on_capabilities() = std::bind(&CSeat::HandleOnCapabilities, this, std::placeholders::_1); } -CSeatInputProcessor::~CSeatInputProcessor() = default; +CSeat::~CSeat() = default; -void CSeatInputProcessor::HandleOnCapabilities(wayland::seat_capability caps) +void CSeat::HandleOnCapabilities(wayland::seat_capability caps) { HandleCapabilityChange (this, @@ -100,7 +100,7 @@ void CSeatInputProcessor::HandleOnCapabilities(wayland::seat_capability caps) "pointer", m_pointer, std::bind(&wayland::seat_t::get_pointer, &m_seat), - std::bind(&CSeatInputProcessor::HandlePointerCapability, this, _1)); + std::bind(&CSeat::HandlePointerCapability, this, _1)); HandleCapabilityChange (this, caps, @@ -108,7 +108,7 @@ void CSeatInputProcessor::HandleOnCapabilities(wayland::seat_capability caps) "keyboard", m_keyboard, std::bind(&wayland::seat_t::get_keyboard, &m_seat), - std::bind(&CSeatInputProcessor::HandleKeyboardCapability, this, _1)); + std::bind(&CSeat::HandleKeyboardCapability, this, _1)); HandleCapabilityChange (this, caps, @@ -116,64 +116,64 @@ void CSeatInputProcessor::HandleOnCapabilities(wayland::seat_capability caps) "touch", m_touch, std::bind(&wayland::seat_t::get_touch, &m_seat), - std::bind(&CSeatInputProcessor::HandleTouchCapability, this, _1)); + std::bind(&CSeat::HandleTouchCapability, this, _1)); } -void CSeatInputProcessor::HandlePointerCapability(wayland::pointer_t const& pointer) +void CSeat::HandlePointerCapability(wayland::pointer_t const& pointer) { m_pointer.reset(new CInputProcessorPointer(pointer, static_cast (*this))); UpdateCoordinateScale(); } -void CSeatInputProcessor::OnPointerEnter(wayland::pointer_t& pointer, std::uint32_t serial) +void CSeat::OnPointerEnter(wayland::pointer_t& pointer, std::uint32_t serial) { m_handler.OnSetCursor(pointer, serial); m_handler.OnEnter(m_globalName, InputType::POINTER); } -void CSeatInputProcessor::OnPointerLeave() +void CSeat::OnPointerLeave() { m_handler.OnLeave(m_globalName, InputType::POINTER); } -void CSeatInputProcessor::OnPointerEvent(XBMC_Event& event) +void CSeat::OnPointerEvent(XBMC_Event& event) { m_handler.OnEvent(m_globalName, InputType::POINTER, event); } -void CSeatInputProcessor::HandleKeyboardCapability(wayland::keyboard_t const& keyboard) +void CSeat::HandleKeyboardCapability(wayland::keyboard_t const& keyboard) { m_keyboard.reset(new CInputProcessorKeyboard(keyboard, static_cast (*this))); } -void CSeatInputProcessor::OnKeyboardEnter() +void CSeat::OnKeyboardEnter() { m_handler.OnEnter(m_globalName, InputType::KEYBOARD); } -void CSeatInputProcessor::OnKeyboardLeave() +void CSeat::OnKeyboardLeave() { m_handler.OnLeave(m_globalName, InputType::KEYBOARD); } -void CSeatInputProcessor::OnKeyboardEvent(XBMC_Event& event) +void CSeat::OnKeyboardEvent(XBMC_Event& event) { m_handler.OnEvent(m_globalName, InputType::KEYBOARD, event); } -void CSeatInputProcessor::HandleTouchCapability(wayland::touch_t const& touch) +void CSeat::HandleTouchCapability(wayland::touch_t const& touch) { m_touch.reset(new CInputProcessorTouch(touch)); UpdateCoordinateScale(); } -void CSeatInputProcessor::SetCoordinateScale(std::int32_t scale) +void CSeat::SetCoordinateScale(std::int32_t scale) { m_coordinateScale = scale; UpdateCoordinateScale(); } -void CSeatInputProcessor::UpdateCoordinateScale() +void CSeat::UpdateCoordinateScale() { if (m_pointer) { diff --git a/xbmc/windowing/wayland/SeatInputProcessor.h b/xbmc/windowing/wayland/Seat.h similarity index 92% rename from xbmc/windowing/wayland/SeatInputProcessor.h rename to xbmc/windowing/wayland/Seat.h index 2ace5a190329b..0fd04bf896710 100644 --- a/xbmc/windowing/wayland/SeatInputProcessor.h +++ b/xbmc/windowing/wayland/Seat.h @@ -90,7 +90,7 @@ class IInputHandler /** * Handle all wl_seat-related events and process them into Kodi events */ -class CSeatInputProcessor : IInputHandlerPointer, IInputHandlerKeyboard +class CSeat : IInputHandlerPointer, IInputHandlerKeyboard { public: /** @@ -99,8 +99,8 @@ class CSeatInputProcessor : IInputHandlerPointer, IInputHandlerKeyboard * \param seat bound seat_t instance * \param handler handler that receives events from this seat, must not be null */ - CSeatInputProcessor(std::uint32_t globalName, wayland::seat_t const & seat, IInputHandler& handler); - ~CSeatInputProcessor(); + CSeat(std::uint32_t globalName, wayland::seat_t const & seat, IInputHandler& handler); + ~CSeat(); std::uint32_t GetGlobalName() const { return m_globalName; @@ -124,8 +124,8 @@ class CSeatInputProcessor : IInputHandlerPointer, IInputHandlerKeyboard void SetCoordinateScale(std::int32_t scale); private: - CSeatInputProcessor(CSeatInputProcessor const& other) = delete; - CSeatInputProcessor& operator=(CSeatInputProcessor const& other) = delete; + CSeat(CSeat const& other) = delete; + CSeat& operator=(CSeat const& other) = delete; void HandleOnCapabilities(wayland::seat_capability caps); void HandlePointerCapability(wayland::pointer_t const& pointer); diff --git a/xbmc/windowing/wayland/WinSystemWayland.h b/xbmc/windowing/wayland/WinSystemWayland.h index e4028960c19cd..37aa81cf49a8a 100644 --- a/xbmc/windowing/wayland/WinSystemWayland.h +++ b/xbmc/windowing/wayland/WinSystemWayland.h @@ -27,7 +27,7 @@ #include "Connection.h" #include "Output.h" -#include "SeatInputProcessor.h" +#include "Seat.h" #include "ShellSurface.h" #include "threads/CriticalSection.h" #include "windowing/WinSystem.h" @@ -117,7 +117,7 @@ class CWinSystemWayland : public CWinSystemBase, public IInputHandler, public IC wayland::surface_t m_surface; std::unique_ptr m_shellSurface; - std::map m_seatProcessors; + std::map m_seatProcessors; CCriticalSection m_seatProcessorsMutex; // m_outputsInPreparation did not receive their done event yet std::map> m_outputs, m_outputsInPreparation; From d49c641eb8296d8de383b576fd85b3e9bdf4ebb2 Mon Sep 17 00:00:00 2001 From: Philipp Kerling Date: Fri, 14 Jul 2017 10:27:37 +0200 Subject: [PATCH 6/7] Stop key repeat when leaving keyboard focus --- xbmc/windowing/wayland/InputProcessorKeyboard.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/xbmc/windowing/wayland/InputProcessorKeyboard.cpp b/xbmc/windowing/wayland/InputProcessorKeyboard.cpp index ba6cc42eb3d29..288186051c839 100644 --- a/xbmc/windowing/wayland/InputProcessorKeyboard.cpp +++ b/xbmc/windowing/wayland/InputProcessorKeyboard.cpp @@ -46,6 +46,7 @@ CInputProcessorKeyboard::CInputProcessorKeyboard(wayland::keyboard_t const& keyb }; m_keyboard.on_leave() = [this](std::uint32_t serial, wayland::surface_t surface) { + m_keyRepeatTimer.Stop(); m_handler.OnKeyboardLeave(); }; m_keyboard.on_repeat_info() = [this](std::int32_t rate, std::int32_t delay) From 8a560c76139530af948cdf04ad1c8543701a6a2a Mon Sep 17 00:00:00 2001 From: Philipp Kerling Date: Fri, 14 Jul 2017 14:44:56 +0200 Subject: [PATCH 7/7] Abort touches when touch capability is lost --- .../windowing/wayland/InputProcessorTouch.cpp | 22 ++++++++++++++----- xbmc/windowing/wayland/InputProcessorTouch.h | 2 ++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/xbmc/windowing/wayland/InputProcessorTouch.cpp b/xbmc/windowing/wayland/InputProcessorTouch.cpp index 414999a9a7c1b..936f23e01ebea 100644 --- a/xbmc/windowing/wayland/InputProcessorTouch.cpp +++ b/xbmc/windowing/wayland/InputProcessorTouch.cpp @@ -76,12 +76,7 @@ CInputProcessorTouch::CInputProcessorTouch(wayland::touch_t const& touch) }; m_touch.on_cancel() = [this]() { - // TouchInputAbort aborts for all pointers, so it does not matter which is specified - if (!m_touchPoints.empty()) - { - SendTouchPointEvent(TouchInputAbort, m_touchPoints.begin()->second); - } - m_touchPoints.clear(); + AbortTouches(); }; m_touch.on_shape() = [this](std::int32_t id, double major, double minor) { @@ -96,6 +91,21 @@ CInputProcessorTouch::CInputProcessorTouch(wayland::touch_t const& touch) }; } +CInputProcessorTouch::~CInputProcessorTouch() +{ + AbortTouches(); +} + +void CInputProcessorTouch::AbortTouches() +{ + // TouchInputAbort aborts for all pointers, so it does not matter which is specified + if (!m_touchPoints.empty()) + { + SendTouchPointEvent(TouchInputAbort, m_touchPoints.begin()->second); + } + m_touchPoints.clear(); +} + void CInputProcessorTouch::SendTouchPointEvent(TouchInput event, const TouchPoint& point) { if (event == TouchInputMove) diff --git a/xbmc/windowing/wayland/InputProcessorTouch.h b/xbmc/windowing/wayland/InputProcessorTouch.h index 0558f4b6ab4a6..dba4b3be2d7af 100644 --- a/xbmc/windowing/wayland/InputProcessorTouch.h +++ b/xbmc/windowing/wayland/InputProcessorTouch.h @@ -42,6 +42,7 @@ class CInputProcessorTouch { public: CInputProcessorTouch(wayland::touch_t const& touch); + ~CInputProcessorTouch(); void SetCoordinateScale(std::int32_t scale) { m_coordinateScale = scale; } private: @@ -65,6 +66,7 @@ class CInputProcessorTouch void SendTouchPointEvent(TouchInput event, TouchPoint const& point); void UpdateTouchPoint(TouchPoint const& point); + void AbortTouches(); wayland::touch_t m_touch; std::int32_t m_coordinateScale{1};