FreeRDP
Loading...
Searching...
No Matches
SDL3/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 <SDL3/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 SDL_Window* window = SDL_GetWindowFromID(ev->windowID);
106
107 if (!window)
108 return FALSE;
109
110 windowID = SDL_GetWindowID(window);
111 SDL_Surface* surface = SDL_GetWindowSurface(window);
112 if (!surface)
113 return FALSE;
114
115 // TODO: Add the offset of the surface in the global coordinates
116 *px = static_cast<INT32>(ev->x * static_cast<float>(surface->w));
117 *py = static_cast<INT32>(ev->y * static_cast<float>(surface->h));
118 return sdl_scale_coordinates(sdl, windowID, px, py, local, TRUE);
119}
120
121static BOOL send_mouse_wheel(SdlContext* sdl, UINT16 flags, INT32 avalue)
122{
123 WINPR_ASSERT(sdl);
124 if (avalue < 0)
125 {
126 flags |= PTR_FLAGS_WHEEL_NEGATIVE;
127 avalue = -avalue;
128 }
129
130 while (avalue > 0)
131 {
132 const UINT16 cval = (avalue > 0xFF) ? 0xFF : static_cast<UINT16>(avalue);
133 UINT16 cflags = flags | cval;
134 /* Convert negative values to 9bit twos complement */
135 if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
136 cflags = (flags & 0xFF00) | (0x100 - cval);
137 if (!freerdp_client_send_wheel_event(sdl->common(), cflags))
138 return FALSE;
139
140 avalue -= cval;
141 }
142 return TRUE;
143}
144
145static UINT32 sdl_scale_pressure(const float pressure)
146{
147 const float val = pressure * 0x400; /* [MS-RDPEI] 2.2.3.3.1.1 RDPINPUT_TOUCH_CONTACT */
148 if (val < 0.0f)
149 return 0;
150 if (val > 0x400)
151 return 0x400;
152 return static_cast<UINT32>(val);
153}
154
155BOOL sdl_handle_touch_up(SdlContext* sdl, const SDL_TouchFingerEvent* ev)
156{
157 WINPR_ASSERT(sdl);
158 WINPR_ASSERT(ev);
159
160 INT32 x = 0;
161 INT32 y = 0;
162 if (!sdl_get_touch_scaled(sdl, ev, &x, &y, TRUE))
163 return FALSE;
164 return freerdp_client_handle_touch(sdl->common(), FREERDP_TOUCH_UP | FREERDP_TOUCH_HAS_PRESSURE,
165 static_cast<INT32>(ev->fingerID),
166 sdl_scale_pressure(ev->pressure), x, y);
167}
168
169BOOL sdl_handle_touch_down(SdlContext* sdl, const SDL_TouchFingerEvent* ev)
170{
171 WINPR_ASSERT(sdl);
172 WINPR_ASSERT(ev);
173
174 INT32 x = 0;
175 INT32 y = 0;
176 if (!sdl_get_touch_scaled(sdl, ev, &x, &y, TRUE))
177 return FALSE;
178 return freerdp_client_handle_touch(
179 sdl->common(), FREERDP_TOUCH_DOWN | FREERDP_TOUCH_HAS_PRESSURE,
180 static_cast<INT32>(ev->fingerID), sdl_scale_pressure(ev->pressure), x, y);
181}
182
183BOOL sdl_handle_touch_motion(SdlContext* sdl, const SDL_TouchFingerEvent* ev)
184{
185 WINPR_ASSERT(sdl);
186 WINPR_ASSERT(ev);
187
188 INT32 x = 0;
189 INT32 y = 0;
190 if (!sdl_get_touch_scaled(sdl, ev, &x, &y, TRUE))
191 return FALSE;
192 return freerdp_client_handle_touch(
193 sdl->common(), FREERDP_TOUCH_MOTION | FREERDP_TOUCH_HAS_PRESSURE,
194 static_cast<INT32>(ev->fingerID), sdl_scale_pressure(ev->pressure), x, y);
195}
196
197BOOL sdl_handle_mouse_motion(SdlContext* sdl, const SDL_MouseMotionEvent* ev)
198{
199 WINPR_ASSERT(sdl);
200 WINPR_ASSERT(ev);
201
202 sdl->input.mouse_focus(ev->windowID);
203 const BOOL relative =
204 freerdp_client_use_relative_mouse_events(sdl->common()) && !sdl->hasCursor();
205 auto x = static_cast<INT32>(relative ? ev->xrel : ev->x);
206 auto y = static_cast<INT32>(relative ? ev->yrel : ev->y);
207 sdl_scale_coordinates(sdl, ev->windowID, &x, &y, TRUE, TRUE);
208 return freerdp_client_send_button_event(sdl->common(), relative, PTR_FLAGS_MOVE, x, y);
209}
210
211BOOL sdl_handle_mouse_wheel(SdlContext* sdl, const SDL_MouseWheelEvent* ev)
212{
213 WINPR_ASSERT(sdl);
214 WINPR_ASSERT(ev);
215
216 const BOOL flipped = (ev->direction == SDL_MOUSEWHEEL_FLIPPED);
217 const auto x = static_cast<INT32>(ev->x * (flipped ? -1.0f : 1.0f) * 120.0f);
218 const auto y = static_cast<INT32>(ev->y * (flipped ? -1.0f : 1.0f) * 120.0f);
219 UINT16 flags = 0;
220
221 if (y != 0)
222 {
223 flags |= PTR_FLAGS_WHEEL;
224 send_mouse_wheel(sdl, flags, y);
225 }
226
227 if (x != 0)
228 {
229 flags |= PTR_FLAGS_HWHEEL;
230 send_mouse_wheel(sdl, flags, x);
231 }
232 return TRUE;
233}
234
235BOOL sdl_handle_mouse_button(SdlContext* sdl, const SDL_MouseButtonEvent* ev)
236{
237 UINT16 flags = 0;
238 UINT16 xflags = 0;
239
240 WINPR_ASSERT(sdl);
241 WINPR_ASSERT(ev);
242
243 if (ev->type == SDL_EVENT_MOUSE_BUTTON_DOWN)
244 {
245 flags |= PTR_FLAGS_DOWN;
246 xflags |= PTR_XFLAGS_DOWN;
247 }
248
249 switch (ev->button)
250 {
251 case 1:
252 flags |= PTR_FLAGS_BUTTON1;
253 break;
254 case 2:
255 flags |= PTR_FLAGS_BUTTON3;
256 break;
257 case 3:
258 flags |= PTR_FLAGS_BUTTON2;
259 break;
260 case 4:
261 xflags |= PTR_XFLAGS_BUTTON1;
262 break;
263 case 5:
264 xflags |= PTR_XFLAGS_BUTTON2;
265 break;
266 default:
267 break;
268 }
269
270 const BOOL relative =
271 freerdp_client_use_relative_mouse_events(sdl->common()) && !sdl->hasCursor();
272 auto x = static_cast<INT32>(relative ? 0 : ev->x);
273 auto y = static_cast<INT32>(relative ? 0 : ev->y);
274 sdl_scale_coordinates(sdl, ev->windowID, &x, &y, TRUE, TRUE);
275 if ((flags & (~PTR_FLAGS_DOWN)) != 0)
276 return freerdp_client_send_button_event(sdl->common(), relative, flags, x, y);
277 else if ((xflags & (~PTR_XFLAGS_DOWN)) != 0)
278 return freerdp_client_send_extended_button_event(sdl->common(), relative, xflags, x, y);
279 else
280 return FALSE;
281}
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.