FreeRDP
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 
33 BOOL 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 
95 static 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 
121 static 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 
145 static 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 
155 BOOL 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 
169 BOOL 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 
183 BOOL 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 
197 BOOL 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 = freerdp_client_use_relative_mouse_events(sdl->common());
204  auto x = static_cast<INT32>(relative ? ev->xrel : ev->x);
205  auto y = static_cast<INT32>(relative ? ev->yrel : ev->y);
206  sdl_scale_coordinates(sdl, ev->windowID, &x, &y, TRUE, TRUE);
207  return freerdp_client_send_button_event(sdl->common(), relative, PTR_FLAGS_MOVE, x, y);
208 }
209 
210 BOOL sdl_handle_mouse_wheel(SdlContext* sdl, const SDL_MouseWheelEvent* ev)
211 {
212  WINPR_ASSERT(sdl);
213  WINPR_ASSERT(ev);
214 
215  const BOOL flipped = (ev->direction == SDL_MOUSEWHEEL_FLIPPED);
216  const auto x = static_cast<INT32>(ev->x * (flipped ? -1 : 1) * 0x78);
217  const auto y = static_cast<INT32>(ev->y * (flipped ? -1 : 1) * 0x78);
218  UINT16 flags = 0;
219 
220  if (y != 0)
221  {
222  flags |= PTR_FLAGS_WHEEL;
223  send_mouse_wheel(sdl, flags, y);
224  }
225 
226  if (x != 0)
227  {
228  flags |= PTR_FLAGS_HWHEEL;
229  send_mouse_wheel(sdl, flags, x);
230  }
231  return TRUE;
232 }
233 
234 BOOL sdl_handle_mouse_button(SdlContext* sdl, const SDL_MouseButtonEvent* ev)
235 {
236  UINT16 flags = 0;
237  UINT16 xflags = 0;
238 
239  WINPR_ASSERT(sdl);
240  WINPR_ASSERT(ev);
241 
242  if (ev->type == SDL_EVENT_MOUSE_BUTTON_DOWN)
243  {
244  flags |= PTR_FLAGS_DOWN;
245  xflags |= PTR_XFLAGS_DOWN;
246  }
247 
248  switch (ev->button)
249  {
250  case 1:
251  flags |= PTR_FLAGS_BUTTON1;
252  break;
253  case 2:
254  flags |= PTR_FLAGS_BUTTON3;
255  break;
256  case 3:
257  flags |= PTR_FLAGS_BUTTON2;
258  break;
259  case 4:
260  xflags |= PTR_XFLAGS_BUTTON1;
261  break;
262  case 5:
263  xflags |= PTR_XFLAGS_BUTTON2;
264  break;
265  default:
266  break;
267  }
268 
269  const BOOL relative = freerdp_client_use_relative_mouse_events(sdl->common());
270  auto x = static_cast<INT32>(relative ? 0 : ev->x);
271  auto y = static_cast<INT32>(relative ? 0 : ev->y);
272  sdl_scale_coordinates(sdl, ev->windowID, &x, &y, TRUE, TRUE);
273  if ((flags & (~PTR_FLAGS_DOWN)) != 0)
274  return freerdp_client_send_button_event(sdl->common(), relative, flags, x, y);
275  else if ((xflags & (~PTR_XFLAGS_DOWN)) != 0)
276  return freerdp_client_send_extended_button_event(sdl->common(), relative, xflags, x, y);
277  else
278  return FALSE;
279 }
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.