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