FreeRDP
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 
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 #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 
125 static 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 
149 static 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 
159 BOOL 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 
173 BOOL 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 
187 BOOL 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 
201 BOOL 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 
214 BOOL 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 
238 BOOL 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.