1 /*
2  *  Copyright (C) 2016-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 "MouseInputHandling.h"
10 
11 #include "input/InputTranslator.h"
12 #include "input/joysticks/interfaces/IButtonMap.h"
13 #include "input/mouse/interfaces/IMouseInputHandler.h"
14 
15 using namespace KODI;
16 using namespace MOUSE;
17 
CMouseInputHandling(IMouseInputHandler * handler,JOYSTICK::IButtonMap * buttonMap)18 CMouseInputHandling::CMouseInputHandling(IMouseInputHandler* handler,
19                                          JOYSTICK::IButtonMap* buttonMap)
20   : m_handler(handler), m_buttonMap(buttonMap)
21 {
22 }
23 
OnPosition(int x,int y)24 bool CMouseInputHandling::OnPosition(int x, int y)
25 {
26   using namespace JOYSTICK;
27 
28   if (!m_bHasPosition)
29   {
30     m_bHasPosition = true;
31     m_x = x;
32     m_y = y;
33     return true;
34   }
35 
36   int dx = x - m_x;
37   int dy = y - m_y;
38 
39   bool bHandled = false;
40 
41   // Get direction of motion
42   POINTER_DIRECTION dir = GetPointerDirection(dx, dy);
43 
44   CDriverPrimitive source(dir);
45   if (source.IsValid())
46   {
47     // Get pointer in direction of motion
48     PointerName pointerName;
49     if (m_buttonMap->GetFeature(source, pointerName))
50     {
51       // Get orthogonal direction of motion
52       POINTER_DIRECTION dirCCW = GetOrthogonalDirectionCCW(dir);
53 
54       // Get mapped directions of motion for rotation and reflection
55       CDriverPrimitive target;
56       CDriverPrimitive targetCCW;
57 
58       if (m_buttonMap->GetRelativePointer(pointerName, dir, target))
59         m_buttonMap->GetRelativePointer(pointerName, dirCCW, targetCCW);
60 
61       if (target.IsValid())
62       {
63         // Invert y to right-handed cartesian system
64         dy *= -1;
65 
66         // Perform rotation
67         int rotation[2][2] = {{1, 0}, {0, 1}};
68 
69         GetRotation(dir, target.PointerDirection(), rotation);
70 
71         dx = rotation[0][0] * dx + rotation[0][1] * dy;
72         dy = rotation[1][0] * dx + rotation[1][1] * dy;
73 
74         if (targetCCW.IsValid())
75         {
76           // Perform reflection
77           int reflection[2][2] = {{1, 0}, {0, 1}};
78 
79           GetReflectionCCW(target.PointerDirection(), targetCCW.PointerDirection(), reflection);
80 
81           dx = reflection[0][0] * dx + reflection[0][1] * dy;
82           dy = reflection[1][0] * dx + reflection[1][1] * dy;
83         }
84 
85         // Invert y back to left-handed coordinate system
86         dy *= -1;
87       }
88 
89       bHandled = m_handler->OnMotion(pointerName, dx, dy);
90     }
91   }
92   else
93   {
94     // Don't fall through - might disrupt the game
95     bHandled = true;
96   }
97 
98   m_x = x;
99   m_y = y;
100 
101   return bHandled;
102 }
103 
OnButtonPress(BUTTON_ID button)104 bool CMouseInputHandling::OnButtonPress(BUTTON_ID button)
105 {
106   bool bHandled = false;
107 
108   JOYSTICK::CDriverPrimitive source(button);
109 
110   ButtonName buttonName;
111   if (m_buttonMap->GetFeature(source, buttonName))
112     bHandled = m_handler->OnButtonPress(buttonName);
113 
114   return bHandled;
115 }
116 
OnButtonRelease(BUTTON_ID button)117 void CMouseInputHandling::OnButtonRelease(BUTTON_ID button)
118 {
119   JOYSTICK::CDriverPrimitive source(button);
120 
121   ButtonName buttonName;
122   if (m_buttonMap->GetFeature(source, buttonName))
123     m_handler->OnButtonRelease(buttonName);
124 }
125 
GetPointerDirection(int x,int y)126 POINTER_DIRECTION CMouseInputHandling::GetPointerDirection(int x, int y)
127 {
128   using namespace INPUT;
129 
130   return CInputTranslator::VectorToCardinalDirection(static_cast<float>(x), static_cast<float>(-y));
131 }
132 
GetOrthogonalDirectionCCW(POINTER_DIRECTION direction)133 POINTER_DIRECTION CMouseInputHandling::GetOrthogonalDirectionCCW(POINTER_DIRECTION direction)
134 {
135   switch (direction)
136   {
137     case POINTER_DIRECTION::RIGHT:
138       return POINTER_DIRECTION::UP;
139     case POINTER_DIRECTION::UP:
140       return POINTER_DIRECTION::LEFT;
141     case POINTER_DIRECTION::LEFT:
142       return POINTER_DIRECTION::DOWN;
143     case POINTER_DIRECTION::DOWN:
144       return POINTER_DIRECTION::RIGHT;
145     default:
146       break;
147   }
148 
149   return POINTER_DIRECTION::NONE;
150 }
151 
GetRotation(POINTER_DIRECTION source,POINTER_DIRECTION target,int (& rotation)[2][2])152 void CMouseInputHandling::GetRotation(POINTER_DIRECTION source,
153                                       POINTER_DIRECTION target,
154                                       int (&rotation)[2][2])
155 {
156   switch (source)
157   {
158     case POINTER_DIRECTION::RIGHT:
159     {
160       switch (target)
161       {
162         case POINTER_DIRECTION::UP:
163           GetRotation(90, rotation);
164           break;
165         case POINTER_DIRECTION::LEFT:
166           GetRotation(180, rotation);
167           break;
168         case POINTER_DIRECTION::DOWN:
169           GetRotation(270, rotation);
170           break;
171         default:
172           break;
173       }
174       break;
175     }
176     case POINTER_DIRECTION::UP:
177     {
178       switch (target)
179       {
180         case POINTER_DIRECTION::LEFT:
181           GetRotation(90, rotation);
182           break;
183         case POINTER_DIRECTION::DOWN:
184           GetRotation(180, rotation);
185           break;
186         case POINTER_DIRECTION::RIGHT:
187           GetRotation(270, rotation);
188           break;
189         default:
190           break;
191       }
192       break;
193     }
194     case POINTER_DIRECTION::LEFT:
195     {
196       switch (target)
197       {
198         case POINTER_DIRECTION::DOWN:
199           GetRotation(90, rotation);
200           break;
201         case POINTER_DIRECTION::RIGHT:
202           GetRotation(180, rotation);
203           break;
204         case POINTER_DIRECTION::UP:
205           GetRotation(270, rotation);
206           break;
207         default:
208           break;
209       }
210       break;
211     }
212     case POINTER_DIRECTION::DOWN:
213     {
214       switch (target)
215       {
216         case POINTER_DIRECTION::RIGHT:
217           GetRotation(90, rotation);
218           break;
219         case POINTER_DIRECTION::UP:
220           GetRotation(180, rotation);
221           break;
222         case POINTER_DIRECTION::LEFT:
223           GetRotation(270, rotation);
224           break;
225         default:
226           break;
227       }
228       break;
229     }
230     default:
231       break;
232   }
233 }
234 
GetRotation(int deg,int (& rotation)[2][2])235 void CMouseInputHandling::GetRotation(int deg, int (&rotation)[2][2])
236 {
237   switch (deg)
238   {
239     case 90:
240     {
241       rotation[0][0] = 0;
242       rotation[0][1] = -1;
243       rotation[1][0] = 1;
244       rotation[1][1] = 0;
245       break;
246     }
247     case 180:
248     {
249       rotation[0][0] = -1;
250       rotation[0][1] = 0;
251       rotation[1][0] = 0;
252       rotation[1][1] = -1;
253       break;
254     }
255     case 270:
256     {
257       rotation[0][0] = 0;
258       rotation[0][1] = 1;
259       rotation[1][0] = -1;
260       rotation[1][1] = 0;
261       break;
262     }
263     default:
264       break;
265   }
266 }
267 
GetReflectionCCW(POINTER_DIRECTION source,POINTER_DIRECTION target,int (& rotation)[2][2])268 void CMouseInputHandling::GetReflectionCCW(POINTER_DIRECTION source,
269                                            POINTER_DIRECTION target,
270                                            int (&rotation)[2][2])
271 {
272   switch (source)
273   {
274     case POINTER_DIRECTION::RIGHT:
275     {
276       switch (target)
277       {
278         case POINTER_DIRECTION::DOWN:
279           GetReflection(0, rotation);
280           break;
281         default:
282           break;
283       }
284       break;
285     }
286     case POINTER_DIRECTION::UP:
287     {
288       switch (target)
289       {
290         case POINTER_DIRECTION::RIGHT:
291           GetReflection(90, rotation);
292           break;
293         default:
294           break;
295       }
296       break;
297     }
298     case POINTER_DIRECTION::LEFT:
299     {
300       switch (target)
301       {
302         case POINTER_DIRECTION::UP:
303           GetReflection(180, rotation);
304           break;
305         default:
306           break;
307       }
308       break;
309     }
310     case POINTER_DIRECTION::DOWN:
311     {
312       switch (target)
313       {
314         case POINTER_DIRECTION::LEFT:
315           GetReflection(270, rotation);
316           break;
317         default:
318           break;
319       }
320       break;
321     }
322     default:
323       break;
324   }
325 }
326 
GetReflection(int deg,int (& reflection)[2][2])327 void CMouseInputHandling::GetReflection(int deg, int (&reflection)[2][2])
328 {
329   switch (deg)
330   {
331     case 0:
332     case 180:
333     {
334       reflection[0][0] = 1;
335       reflection[0][1] = 0;
336       reflection[1][0] = 0;
337       reflection[1][1] = -1;
338       break;
339     }
340     case 90:
341     case 270:
342     {
343       reflection[0][0] = -1;
344       reflection[0][1] = 0;
345       reflection[1][0] = 0;
346       reflection[1][1] = 1;
347       break;
348     }
349     default:
350       break;
351   }
352 }
353