FreeRDP
Loading...
Searching...
No Matches
SDL2/sdl_touch.cpp
1
20#include <freerdp/config.h>
21
22#include "sdl_touch.hpp"
23#include "sdl_freerdp.hpp"
24
25#include <winpr/wtypes.h>
26#include <winpr/assert.h>
27
28#include <freerdp/freerdp.h>
29#include <freerdp/gdi/gdi.h>
30
31#include <SDL.h>
32
33BOOL sdl_scale_coordinates(SdlContext* sdl, Uint32 windowId, INT32* px, INT32* py,
34 BOOL fromLocalToRDP, BOOL applyOffset)
35{
36 rdpGdi* gdi = nullptr;
37 double sx = 1.0;
38 double sy = 1.0;
39
40 if (!sdl || !px || !py || !sdl->context()->gdi)
41 return FALSE;
42
43 WINPR_ASSERT(sdl->context()->gdi);
44 WINPR_ASSERT(sdl->context()->settings);
45
46 gdi = sdl->context()->gdi;
47
48 // TODO: Make this multimonitor ready!
49 // TODO: Need to find the primary monitor, get the scale
50 // TODO: Need to find the destination monitor, get the scale
51 // TODO: All intermediate monitors, get the scale
52
53 int offset_x = 0;
54 int offset_y = 0;
55 for (const auto& it : sdl->windows)
56 {
57 auto& window = it.second;
58 const auto id = window.id();
59 if (id != windowId)
60 {
61 continue;
62 }
63
64 auto size = window.rect();
65
66 sx = size.w / static_cast<double>(gdi->width);
67 sy = size.h / static_cast<double>(gdi->height);
68 offset_x = window.offsetX();
69 offset_y = window.offsetY();
70 break;
71 }
72
73 if (freerdp_settings_get_bool(sdl->context()->settings, FreeRDP_SmartSizing))
74 {
75 if (!fromLocalToRDP)
76 {
77 *px = static_cast<INT32>(*px * sx);
78 *py = static_cast<INT32>(*py * sy);
79 }
80 else
81 {
82 *px = static_cast<INT32>(*px / sx);
83 *py = static_cast<INT32>(*py / sy);
84 }
85 }
86 else if (applyOffset)
87 {
88 *px -= offset_x;
89 *py -= offset_y;
90 }
91
92 return TRUE;
93}
94
95static BOOL sdl_get_touch_scaled(SdlContext* sdl, const SDL_TouchFingerEvent* ev, INT32* px,
96 INT32* py, BOOL local)
97{
98 Uint32 windowID = 0;
99
100 WINPR_ASSERT(sdl);
101 WINPR_ASSERT(ev);
102 WINPR_ASSERT(px);
103 WINPR_ASSERT(py);
104
105#if SDL_VERSION_ATLEAST(2, 0, 12)
106 SDL_Window* window = SDL_GetWindowFromID(ev->windowID);
107#else
108 SDL_Window* window = SDL_GetMouseFocus();
109#endif
110
111 if (!window)
112 return FALSE;
113
114 windowID = SDL_GetWindowID(window);
115 SDL_Surface* surface = SDL_GetWindowSurface(window);
116 if (!surface)
117 return FALSE;
118
119 // TODO: Add the offset of the surface in the global coordinates
120 *px = static_cast<INT32>(ev->x * static_cast<float>(surface->w));
121 *py = static_cast<INT32>(ev->y * static_cast<float>(surface->h));
122 return sdl_scale_coordinates(sdl, windowID, px, py, local, TRUE);
123}
124
125static BOOL send_mouse_wheel(SdlContext* sdl, UINT16 flags, INT32 avalue)
126{
127 WINPR_ASSERT(sdl);
128 if (avalue < 0)
129 {
130 flags |= PTR_FLAGS_WHEEL_NEGATIVE;
131 avalue = -avalue;
132 }
133
134 while (avalue > 0)
135 {
136 const UINT16 cval = (avalue > 0xFF) ? 0xFF : static_cast<UINT16>(avalue);
137 UINT16 cflags = flags | cval;
138 /* Convert negative values to 9bit twos complement */
139 if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
140 cflags = (flags & 0xFF00) | (0x100 - cval);
141 if (!freerdp_client_send_wheel_event(sdl->common(), cflags))
142 return FALSE;
143
144 avalue -= cval;
145 }
146 return TRUE;
147}
148
149static UINT32 sdl_scale_pressure(const float pressure)
150{
151 const float val = pressure * 0x400; /* [MS-RDPEI] 2.2.3.3.1.1 RDPINPUT_TOUCH_CONTACT */
152 if (val < 0.0f)
153 return 0;
154 if (val > 0x400)
155 return 0x400;
156 return static_cast<UINT32>(val);
157}
158
159BOOL sdl_handle_touch_up(SdlContext* sdl, const SDL_TouchFingerEvent* ev)
160{
161 WINPR_ASSERT(sdl);
162 WINPR_ASSERT(ev);
163
164 INT32 x = 0;
165 INT32 y = 0;
166 if (!sdl_get_touch_scaled(sdl, ev, &x, &y, TRUE))
167 return FALSE;
168 return freerdp_client_handle_touch(sdl->common(), FREERDP_TOUCH_UP | FREERDP_TOUCH_HAS_PRESSURE,
169 static_cast<INT32>(ev->fingerId),
170 sdl_scale_pressure(ev->pressure), x, y);
171}
172
173BOOL sdl_handle_touch_down(SdlContext* sdl, const SDL_TouchFingerEvent* ev)
174{
175 WINPR_ASSERT(sdl);
176 WINPR_ASSERT(ev);
177
178 INT32 x = 0;
179 INT32 y = 0;
180 if (!sdl_get_touch_scaled(sdl, ev, &x, &y, TRUE))
181 return FALSE;
182 return freerdp_client_handle_touch(
183 sdl->common(), FREERDP_TOUCH_DOWN | FREERDP_TOUCH_HAS_PRESSURE,
184 static_cast<INT32>(ev->fingerId), sdl_scale_pressure(ev->pressure), x, y);
185}
186
187BOOL sdl_handle_touch_motion(SdlContext* sdl, const SDL_TouchFingerEvent* ev)
188{
189 WINPR_ASSERT(sdl);
190 WINPR_ASSERT(ev);
191
192 INT32 x = 0;
193 INT32 y = 0;
194 if (!sdl_get_touch_scaled(sdl, ev, &x, &y, TRUE))
195 return FALSE;
196 return freerdp_client_handle_touch(
197 sdl->common(), FREERDP_TOUCH_MOTION | FREERDP_TOUCH_HAS_PRESSURE,
198 static_cast<INT32>(ev->fingerId), sdl_scale_pressure(ev->pressure), x, y);
199}
200
201BOOL sdl_handle_mouse_motion(SdlContext* sdl, const SDL_MouseMotionEvent* ev)
202{
203 WINPR_ASSERT(sdl);
204 WINPR_ASSERT(ev);
205
206 sdl->input.mouse_focus(ev->windowID);
207 const BOOL relative = freerdp_client_use_relative_mouse_events(sdl->common());
208 INT32 x = relative ? ev->xrel : ev->x;
209 INT32 y = relative ? ev->yrel : ev->y;
210 sdl_scale_coordinates(sdl, ev->windowID, &x, &y, TRUE, TRUE);
211 return freerdp_client_send_button_event(sdl->common(), relative, PTR_FLAGS_MOVE, x, y);
212}
213
214BOOL sdl_handle_mouse_wheel(SdlContext* sdl, const SDL_MouseWheelEvent* ev)
215{
216 WINPR_ASSERT(sdl);
217 WINPR_ASSERT(ev);
218
219 const BOOL flipped = (ev->direction == SDL_MOUSEWHEEL_FLIPPED);
220 const INT32 x = ev->x * (flipped ? -1 : 1) * 0x78;
221 const INT32 y = ev->y * (flipped ? -1 : 1) * 0x78;
222 UINT16 flags = 0;
223
224 if (y != 0)
225 {
226 flags |= PTR_FLAGS_WHEEL;
227 send_mouse_wheel(sdl, flags, y);
228 }
229
230 if (x != 0)
231 {
232 flags |= PTR_FLAGS_HWHEEL;
233 send_mouse_wheel(sdl, flags, x);
234 }
235 return TRUE;
236}
237
238BOOL sdl_handle_mouse_button(SdlContext* sdl, const SDL_MouseButtonEvent* ev)
239{
240 UINT16 flags = 0;
241 UINT16 xflags = 0;
242
243 WINPR_ASSERT(sdl);
244 WINPR_ASSERT(ev);
245
246 if (ev->state == SDL_PRESSED)
247 {
248 flags |= PTR_FLAGS_DOWN;
249 xflags |= PTR_XFLAGS_DOWN;
250 }
251
252 switch (ev->button)
253 {
254 case 1:
255 flags |= PTR_FLAGS_BUTTON1;
256 break;
257 case 2:
258 flags |= PTR_FLAGS_BUTTON3;
259 break;
260 case 3:
261 flags |= PTR_FLAGS_BUTTON2;
262 break;
263 case 4:
264 xflags |= PTR_XFLAGS_BUTTON1;
265 break;
266 case 5:
267 xflags |= PTR_XFLAGS_BUTTON2;
268 break;
269 default:
270 break;
271 }
272
273 const BOOL relative = freerdp_client_use_relative_mouse_events(sdl->common());
274 INT32 x = relative ? 0 : ev->x;
275 INT32 y = relative ? 0 : ev->y;
276 sdl_scale_coordinates(sdl, ev->windowID, &x, &y, TRUE, TRUE);
277 if ((flags & (~PTR_FLAGS_DOWN)) != 0)
278 return freerdp_client_send_button_event(sdl->common(), relative, flags, x, y);
279 else if ((xflags & (~PTR_XFLAGS_DOWN)) != 0)
280 return freerdp_client_send_extended_button_event(sdl->common(), relative, xflags, x, y);
281 else
282 return FALSE;
283}
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.