summaryrefslogtreecommitdiffstats
path: root/xbmc/windowing/wayland/InputProcessorTouch.cpp
blob: a664e32ef6afe2fc0faf257567fec7f05b66c5d2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
 *  Copyright (C) 2017-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 "InputProcessorTouch.h"

#include "input/touch/generic/GenericTouchInputHandler.h"

using namespace KODI::WINDOWING::WAYLAND;

CInputProcessorTouch::CInputProcessorTouch(wayland::surface_t const& surface)
: m_surface{surface}
{
}

void CInputProcessorTouch::OnTouchDown(CSeat* seat,
                                       std::uint32_t serial,
                                       std::uint32_t time,
                                       const wayland::surface_t& surface,
                                       std::int32_t id,
                                       double x,
                                       double y)
{
  if (surface != m_surface)
  {
    return;
  }

  // Find free Kodi pointer number
  int kodiPointer{-1};
  // Not optimal, but irrelevant for the small number of iterations
  for (int testPointer{0}; testPointer < CGenericTouchInputHandler::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);
  }
}

void CInputProcessorTouch::OnTouchUp(CSeat* seat, 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);
  }
}

void CInputProcessorTouch::OnTouchMotion(CSeat* seat, 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);
  }
}

void CInputProcessorTouch::OnTouchCancel(CSeat* seat)
{
  AbortTouches();
}

void CInputProcessorTouch::OnTouchShape(CSeat* seat, 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);
  }
}

CInputProcessorTouch::~CInputProcessorTouch() noexcept
{
  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)
  {
    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);
}