1 /*
2  *  Copyright (C) 2017-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #include "InputProcessorPointer.h"
10 
11 #include "input/mouse/MouseStat.h"
12 
13 #include <cmath>
14 
15 #include <linux/input-event-codes.h>
16 
17 using namespace KODI::WINDOWING::WAYLAND;
18 
19 namespace
20 {
21 
WaylandToXbmcButton(std::uint32_t button)22 int WaylandToXbmcButton(std::uint32_t button)
23 {
24   // Wayland button is evdev code
25   switch (button)
26   {
27     case BTN_LEFT:
28       return XBMC_BUTTON_LEFT;
29     case BTN_MIDDLE:
30       return XBMC_BUTTON_MIDDLE;
31     case BTN_RIGHT:
32       return XBMC_BUTTON_RIGHT;
33     default:
34       return -1;
35   }
36 }
37 
38 }
39 
CInputProcessorPointer(wayland::surface_t const & surface,IInputHandlerPointer & handler)40 CInputProcessorPointer::CInputProcessorPointer(wayland::surface_t const& surface, IInputHandlerPointer& handler)
41 : m_surface{surface}, m_handler{handler}
42 {
43 }
44 
OnPointerEnter(CSeat * seat,std::uint32_t serial,const wayland::surface_t & surface,double surfaceX,double surfaceY)45 void CInputProcessorPointer::OnPointerEnter(CSeat* seat,
46                                             std::uint32_t serial,
47                                             const wayland::surface_t& surface,
48                                             double surfaceX,
49                                             double surfaceY)
50 {
51   if (surface == m_surface)
52   {
53     m_pointerOnSurface = true;
54     m_handler.OnPointerEnter(seat->GetGlobalName(), serial);
55     SetMousePosFromSurface({surfaceX, surfaceY});
56     SendMouseMotion();
57   }
58 }
59 
OnPointerLeave(CSeat * seat,std::uint32_t serial,const wayland::surface_t & surface)60 void CInputProcessorPointer::OnPointerLeave(CSeat* seat,
61                                             std::uint32_t serial,
62                                             const wayland::surface_t& surface)
63 {
64   if (m_pointerOnSurface)
65   {
66     m_handler.OnPointerLeave();
67     m_pointerOnSurface = false;
68   }
69 }
70 
OnPointerMotion(CSeat * seat,std::uint32_t time,double surfaceX,double surfaceY)71 void CInputProcessorPointer::OnPointerMotion(CSeat* seat, std::uint32_t time, double surfaceX, double surfaceY)
72 {
73   if (m_pointerOnSurface)
74   {
75     SetMousePosFromSurface({surfaceX, surfaceY});
76     SendMouseMotion();
77   }
78 }
79 
OnPointerButton(CSeat * seat,std::uint32_t serial,std::uint32_t time,std::uint32_t button,wayland::pointer_button_state state)80 void CInputProcessorPointer::OnPointerButton(CSeat* seat, std::uint32_t serial, std::uint32_t time, std::uint32_t button, wayland::pointer_button_state state)
81 {
82   if (m_pointerOnSurface)
83   {
84     int xbmcButton = WaylandToXbmcButton(button);
85     if (xbmcButton < 0)
86     {
87       // Button is unmapped
88       return;
89     }
90 
91     bool pressed = (state == wayland::pointer_button_state::pressed);
92     SendMouseButton(xbmcButton, pressed);
93   }
94 }
95 
OnPointerAxis(CSeat * seat,std::uint32_t time,wayland::pointer_axis axis,double value)96 void CInputProcessorPointer::OnPointerAxis(CSeat* seat, std::uint32_t time, wayland::pointer_axis axis, double value)
97 {
98   if (m_pointerOnSurface)
99   {
100     // For axis events we only care about the vector direction
101     // and not the scalar magnitude. Every axis event callback
102     // generates one scroll button event for XBMC
103 
104     // Negative is up
105     auto xbmcButton = static_cast<unsigned char> ((value < 0.0) ? XBMC_BUTTON_WHEELUP : XBMC_BUTTON_WHEELDOWN);
106     // Simulate a single click of the wheel-equivalent "button"
107     SendMouseButton(xbmcButton, true);
108     SendMouseButton(xbmcButton, false);
109   }
110 }
111 
ConvertMouseCoordinate(double coord) const112 std::uint16_t CInputProcessorPointer::ConvertMouseCoordinate(double coord) const
113 {
114   return static_cast<std::uint16_t> (std::round(coord * m_coordinateScale));
115 }
116 
SetMousePosFromSurface(CPointGen<double> position)117 void CInputProcessorPointer::SetMousePosFromSurface(CPointGen<double> position)
118 {
119   m_pointerPosition = {ConvertMouseCoordinate(position.x), ConvertMouseCoordinate(position.y)};
120 }
121 
SendMouseMotion()122 void CInputProcessorPointer::SendMouseMotion()
123 {
124   XBMC_Event event{XBMC_MOUSEMOTION};
125   event.motion = {m_pointerPosition.x, m_pointerPosition.y};
126   m_handler.OnPointerEvent(event);
127 }
128 
SendMouseButton(unsigned char button,bool pressed)129 void CInputProcessorPointer::SendMouseButton(unsigned char button, bool pressed)
130 {
131   XBMC_Event event{static_cast<unsigned char> (pressed ? XBMC_MOUSEBUTTONDOWN : XBMC_MOUSEBUTTONUP)};
132   event.button = {button, m_pointerPosition.x, m_pointerPosition.y};
133   m_handler.OnPointerEvent(event);
134 }
135