Skip to content

Commit

Permalink
Merge pull request #38 from pkerling/issue/9-wl_touch
Browse files Browse the repository at this point in the history
Touch support
  • Loading branch information
pkerling authored Jul 15, 2017
2 parents 023eba2 + 8a560c7 commit 1374f0e
Show file tree
Hide file tree
Showing 15 changed files with 949 additions and 434 deletions.
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

0 comments on commit 1374f0e

Please sign in to comment.