Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Touch support #38

Merged
merged 7 commits into from
Jul 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion xbmc/input/touch/ITouchInputHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
*
*/

#include <atomic>
#include <stdint.h>

#include "input/touch/ITouchInputHandling.h"
Expand Down Expand Up @@ -101,5 +102,5 @@ class ITouchInputHandler : public ITouchInputHandling
/*!
* \brief DPI value of the touch screen
*/
float m_dpi;
std::atomic<float> m_dpi;
};
10 changes: 8 additions & 2 deletions xbmc/windowing/wayland/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ 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
Seat.cpp
ShellSurface.cpp
ShellSurfaceWlShell.cpp
ShellSurfaceXdgShellUnstableV6.cpp
Expand All @@ -19,8 +22,11 @@ set(SOURCES Connection.cpp
set(HEADERS Connection.h
Output.h
GLContextEGL.h
InputProcessorKeyboard.cpp
InputProcessorPointer.cpp
InputProcessorTouch.cpp
OSScreenSaverIdleInhibitUnstableV1.h
SeatInputProcessor.h
Seat.h
ShellSurface.h
ShellSurfaceWlShell.h
ShellSurfaceXdgShellUnstableV6.h
Expand Down
173 changes: 173 additions & 0 deletions xbmc/windowing/wayland/InputProcessorKeyboard.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/*
* 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
* <http://www.gnu.org/licenses/>.
*
*/

#include "InputProcessorKeyboard.h"

#include <unistd.h>

#include <cassert>
#include <limits>

#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_keyRepeatTimer.Stop();
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<int> (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<int, -1, decltype(close)> 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<std::uint16_t>::max())
{
// Kodi event system only supports UTF16, so ignore the codepoint if
// it does not fit
utf32 = 0;
}
if (scancode > std::numeric_limits<unsigned char>::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<std::uint16_t> (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<unsigned char> (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);
}
83 changes: 83 additions & 0 deletions xbmc/windowing/wayland/InputProcessorKeyboard.h
Original file line number Diff line number Diff line change
@@ -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
* <http://www.gnu.org/licenses/>.
*
*/
#pragma once

#include <atomic>
#include <cstdint>
#include <functional>
#include <memory>

#include <wayland-client-protocol.hpp>

#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<CXkbcommonContext> m_xkbContext;
std::unique_ptr<CXkbcommonKeymap> m_keymap;
// Default values are used if compositor does not send any
std::atomic<int> m_keyRepeatDelay{1000};
std::atomic<int> 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;
};

}
}
}
Loading