FreeRDP
Loading...
Searching...
No Matches
wlf_input.c
1
21#include <stdlib.h>
22#include <float.h>
23
24#include <linux/input.h>
25
26#include <winpr/assert.h>
27#include <winpr/cast.h>
28
29#include <freerdp/config.h>
30#include <freerdp/locale/keyboard.h>
31#include <uwac/uwac.h>
32
33#include "wlfreerdp.h"
34#include "wlf_input.h"
35
36static BOOL scale_signed_coordinates(rdpContext* context, int32_t* x, int32_t* y,
37 BOOL fromLocalToRDP)
38{
39 BOOL rc = 0;
40 UINT32 ux = 0;
41 UINT32 uy = 0;
42 WINPR_ASSERT(context);
43 WINPR_ASSERT(x);
44 WINPR_ASSERT(y);
45 WINPR_ASSERT(*x >= 0);
46 WINPR_ASSERT(*y >= 0);
47
48 ux = (UINT32)*x;
49 uy = (UINT32)*y;
50 rc = wlf_scale_coordinates(context, &ux, &uy, fromLocalToRDP);
51 WINPR_ASSERT(ux < INT32_MAX);
52 WINPR_ASSERT(uy < INT32_MAX);
53 *x = (int32_t)ux;
54 *y = (int32_t)uy;
55 return rc;
56}
57
58BOOL wlf_handle_pointer_enter(freerdp* instance, const UwacPointerEnterLeaveEvent* ev)
59{
60 uint32_t x = 0;
61 uint32_t y = 0;
62 rdpClientContext* cctx = NULL;
63
64 if (!instance || !ev)
65 return FALSE;
66
67 x = ev->x;
68 y = ev->y;
69
70 if (!wlf_scale_coordinates(instance->context, &x, &y, TRUE))
71 return FALSE;
72
73 cctx = (rdpClientContext*)instance->context;
74 return freerdp_client_send_button_event(cctx, FALSE, PTR_FLAGS_MOVE,
75 WINPR_ASSERTING_INT_CAST(int, x),
76 WINPR_ASSERTING_INT_CAST(int, y));
77}
78
79BOOL wlf_handle_pointer_motion(freerdp* instance, const UwacPointerMotionEvent* ev)
80{
81 rdpClientContext* cctx = NULL;
82
83 if (!instance || !ev)
84 return FALSE;
85
86 cctx = (rdpClientContext*)instance->context;
87 WINPR_ASSERT(cctx);
88
89 uint32_t x = ev->x;
90 uint32_t y = ev->y;
91
92 if (!wlf_scale_coordinates(instance->context, &x, &y, TRUE))
93 return FALSE;
94
95 return freerdp_client_send_button_event(cctx, FALSE, PTR_FLAGS_MOVE,
96 WINPR_ASSERTING_INT_CAST(int32_t, x),
97 WINPR_ASSERTING_INT_CAST(int32_t, y));
98}
99
100BOOL wlf_handle_pointer_buttons(freerdp* instance, const UwacPointerButtonEvent* ev)
101{
102 rdpClientContext* cctx = NULL;
103 UINT16 flags = 0;
104 UINT16 xflags = 0;
105
106 if (!instance || !ev)
107 return FALSE;
108
109 cctx = (rdpClientContext*)instance->context;
110 WINPR_ASSERT(cctx);
111
112 uint32_t x = ev->x;
113 uint32_t y = ev->y;
114
115 if (!wlf_scale_coordinates(instance->context, &x, &y, TRUE))
116 return FALSE;
117
118 if (ev->state == WL_POINTER_BUTTON_STATE_PRESSED)
119 {
120 flags |= PTR_FLAGS_DOWN;
121 xflags |= PTR_XFLAGS_DOWN;
122 }
123
124 switch (ev->button)
125 {
126 case BTN_LEFT:
127 flags |= PTR_FLAGS_BUTTON1;
128 break;
129
130 case BTN_RIGHT:
131 flags |= PTR_FLAGS_BUTTON2;
132 break;
133
134 case BTN_MIDDLE:
135 flags |= PTR_FLAGS_BUTTON3;
136 break;
137
138 case BTN_SIDE:
139 xflags |= PTR_XFLAGS_BUTTON1;
140 break;
141
142 case BTN_EXTRA:
143 xflags |= PTR_XFLAGS_BUTTON2;
144 break;
145
146 default:
147 return TRUE;
148 }
149
150 const INT32 cx = WINPR_ASSERTING_INT_CAST(int32_t, x);
151 const INT32 cy = WINPR_ASSERTING_INT_CAST(int32_t, y);
152
153 if ((flags & ~PTR_FLAGS_DOWN) != 0)
154 return freerdp_client_send_button_event(cctx, FALSE, flags, cx, cy);
155
156 if ((xflags & ~PTR_XFLAGS_DOWN) != 0)
157 return freerdp_client_send_extended_button_event(cctx, FALSE, xflags, cx, cy);
158
159 return FALSE;
160}
161
162BOOL wlf_handle_pointer_axis(freerdp* instance, const UwacPointerAxisEvent* ev)
163{
164 wlfContext* context = NULL;
165 if (!instance || !instance->context || !ev)
166 return FALSE;
167
168 context = (wlfContext*)instance->context;
169 return ArrayList_Append(context->events, ev);
170}
171
172BOOL wlf_handle_pointer_axis_discrete(freerdp* instance, const UwacPointerAxisEvent* ev)
173{
174 wlfContext* context = NULL;
175 if (!instance || !instance->context || !ev)
176 return FALSE;
177
178 context = (wlfContext*)instance->context;
179 return ArrayList_Append(context->events, ev);
180}
181
182static BOOL wlf_handle_wheel(freerdp* instance, uint32_t x, uint32_t y, uint32_t axis,
183 int32_t value)
184{
185 rdpClientContext* cctx = NULL;
186 UINT16 flags = 0;
187 int32_t direction = 0;
188 uint32_t avalue = (uint32_t)abs(value);
189
190 WINPR_ASSERT(instance);
191
192 cctx = (rdpClientContext*)instance->context;
193 WINPR_ASSERT(cctx);
194
195 if (!wlf_scale_coordinates(instance->context, &x, &y, TRUE))
196 return FALSE;
197
198 direction = value;
199 switch (axis)
200 {
201 case WL_POINTER_AXIS_VERTICAL_SCROLL:
202 flags |= PTR_FLAGS_WHEEL;
203 if (direction > 0)
204 flags |= PTR_FLAGS_WHEEL_NEGATIVE;
205 break;
206
207 case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
208 flags |= PTR_FLAGS_HWHEEL;
209 if (direction < 0)
210 flags |= PTR_FLAGS_WHEEL_NEGATIVE;
211 break;
212
213 default:
214 return FALSE;
215 }
216
217 /* Wheel rotation steps:
218 *
219 * positive: 0 ... 0xFF -> slow ... fast
220 * negative: 0 ... 0xFF -> fast ... slow
221 */
222
223 while (avalue > 0)
224 {
225 const UINT16 cval = (avalue > 0xFF) ? 0xFF : (UINT16)avalue;
226 UINT16 cflags = flags | cval;
227 /* Convert negative values to 9bit twos complement */
228 if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
229 cflags = (flags & 0xFF00) | (0x100 - cval);
230 if (!freerdp_client_send_wheel_event(cctx, cflags))
231 return FALSE;
232
233 avalue -= cval;
234 }
235 return TRUE;
236}
237
238BOOL wlf_handle_pointer_frame(freerdp* instance, const UwacPointerFrameEvent* ev)
239{
240 BOOL success = TRUE;
241 BOOL handle = FALSE;
242 wlfContext* context = NULL;
243 enum wl_pointer_axis_source source = WL_POINTER_AXIS_SOURCE_CONTINUOUS;
244
245 if (!instance || !ev || !instance->context)
246 return FALSE;
247
248 context = (wlfContext*)instance->context;
249
250 for (size_t x = 0; x < ArrayList_Count(context->events); x++)
251 {
252 UwacEvent* cev = ArrayList_GetItem(context->events, x);
253 if (!cev)
254 continue;
255 if (cev->type == UWAC_EVENT_POINTER_SOURCE)
256 {
257 handle = TRUE;
258 source = cev->mouse_source.axis_source;
259 }
260 }
261
262 /* We need source events to determine how to interpret the data */
263 if (handle)
264 {
265 for (size_t x = 0; x < ArrayList_Count(context->events); x++)
266 {
267 UwacEvent* cev = ArrayList_GetItem(context->events, x);
268 if (!cev)
269 continue;
270
271 switch (source)
272 {
273 /* If we have a mouse wheel, just use discrete data */
274 case WL_POINTER_AXIS_SOURCE_WHEEL:
275#if defined(WL_POINTER_AXIS_SOURCE_WHEEL_TILT_SINCE_VERSION)
276 case WL_POINTER_AXIS_SOURCE_WHEEL_TILT:
277#endif
278 if (cev->type == UWAC_EVENT_POINTER_AXIS_DISCRETE)
279 {
280 /* Get the number of steps, multiply by default step width of 120 */
281 int32_t val = cev->mouse_axis.value * 0x78;
282 /* No wheel event received, success! */
283 if (!wlf_handle_wheel(instance, cev->mouse_axis.x, cev->mouse_axis.y,
284 cev->mouse_axis.axis, val))
285 success = FALSE;
286 }
287 break;
288 /* If we have a touch pad we get actual data, scale */
289 case WL_POINTER_AXIS_SOURCE_FINGER:
290 case WL_POINTER_AXIS_SOURCE_CONTINUOUS:
291 if (cev->type == UWAC_EVENT_POINTER_AXIS)
292 {
293 double dval = wl_fixed_to_double(cev->mouse_axis.value);
294 int32_t val = (int32_t)(dval * 0x78 / 10.0);
295 if (!wlf_handle_wheel(instance, cev->mouse_axis.x, cev->mouse_axis.y,
296 cev->mouse_axis.axis, val))
297 success = FALSE;
298 }
299 break;
300 default:
301 break;
302 }
303 }
304 }
305 ArrayList_Clear(context->events);
306 return success;
307}
308
309BOOL wlf_handle_pointer_source(freerdp* instance, const UwacPointerSourceEvent* ev)
310{
311 wlfContext* context = NULL;
312 if (!instance || !instance->context || !ev)
313 return FALSE;
314
315 context = (wlfContext*)instance->context;
316 return ArrayList_Append(context->events, ev);
317}
318
319BOOL wlf_handle_key(freerdp* instance, const UwacKeyEvent* ev)
320{
321 if (!instance || !ev)
322 return FALSE;
323
324 WINPR_ASSERT(instance->context);
325 wlfContext* ctx = (wlfContext*)instance->context;
326 if (freerdp_settings_get_bool(instance->context->settings, FreeRDP_GrabKeyboard) &&
327 ev->raw_key == KEY_RIGHTCTRL)
328 wlf_handle_ungrab_key(instance, ev);
329
330 rdpInput* input = instance->context->input;
331
332 const DWORD vc = GetVirtualKeyCodeFromKeycode(ev->raw_key, WINPR_KEYCODE_TYPE_EVDEV);
333 const DWORD sc = GetVirtualScanCodeFromVirtualKeyCode(vc, WINPR_KBD_TYPE_IBM_ENHANCED);
334 const DWORD rdp_scancode = freerdp_keyboard_remap_key(ctx->remap_table, sc);
335
336 if (rdp_scancode == RDP_SCANCODE_UNKNOWN)
337 return TRUE;
338
339 return freerdp_input_send_keyboard_event_ex(input, ev->pressed, ev->repeated, rdp_scancode);
340}
341
342BOOL wlf_handle_ungrab_key(freerdp* instance, const UwacKeyEvent* ev)
343{
344 wlfContext* context = NULL;
345 if (!instance || !instance->context || !ev)
346 return FALSE;
347
348 context = (wlfContext*)instance->context;
349
350 return UwacSeatInhibitShortcuts(context->seat, false) == UWAC_SUCCESS;
351}
352
353BOOL wlf_keyboard_enter(freerdp* instance, const UwacKeyboardEnterLeaveEvent* ev)
354{
355 if (!instance || !ev)
356 return FALSE;
357
358 ((wlfContext*)instance->context)->focusing = TRUE;
359 return TRUE;
360}
361
362BOOL wlf_keyboard_modifiers(freerdp* instance, const UwacKeyboardModifiersEvent* ev)
363{
364 rdpInput* input = NULL;
365 UINT16 syncFlags = 0;
366 wlfContext* wlf = NULL;
367
368 if (!instance || !ev)
369 return FALSE;
370
371 wlf = (wlfContext*)instance->context;
372 WINPR_ASSERT(wlf);
373
374 input = instance->context->input;
375 WINPR_ASSERT(input);
376
377 syncFlags = 0;
378
379 if (ev->modifiers & UWAC_MOD_CAPS_MASK)
380 syncFlags |= KBD_SYNC_CAPS_LOCK;
381 if (ev->modifiers & UWAC_MOD_NUM_MASK)
382 syncFlags |= KBD_SYNC_NUM_LOCK;
383
384 if (!wlf->focusing)
385 return TRUE;
386
387 ((wlfContext*)instance->context)->focusing = FALSE;
388
389 return freerdp_input_send_focus_in_event(input, syncFlags) &&
390 freerdp_client_send_button_event(&wlf->common, FALSE, PTR_FLAGS_MOVE, 0, 0);
391}
392
393BOOL wlf_handle_touch_up(freerdp* instance, const UwacTouchUp* ev)
394{
395 int32_t x = 0;
396 int32_t y = 0;
397
398 WINPR_ASSERT(instance);
399 WINPR_ASSERT(ev);
400
401 wlfContext* wlf = (wlfContext*)instance->context;
402 WINPR_ASSERT(wlf);
403
404 x = ev->x;
405 y = ev->y;
406
407 if (!scale_signed_coordinates(instance->context, &x, &y, TRUE))
408 return FALSE;
409
410 return freerdp_client_handle_touch(&wlf->common, FREERDP_TOUCH_UP, ev->id, 0, x, y);
411}
412
413BOOL wlf_handle_touch_down(freerdp* instance, const UwacTouchDown* ev)
414{
415 int32_t x = 0;
416 int32_t y = 0;
417
418 WINPR_ASSERT(instance);
419 WINPR_ASSERT(ev);
420
421 wlfContext* wlf = (wlfContext*)instance->context;
422 WINPR_ASSERT(wlf);
423
424 x = ev->x;
425 y = ev->y;
426
427 if (!scale_signed_coordinates(instance->context, &x, &y, TRUE))
428 return FALSE;
429
430 return freerdp_client_handle_touch(&wlf->common, FREERDP_TOUCH_DOWN, ev->id, 0, x, y);
431}
432
433BOOL wlf_handle_touch_motion(freerdp* instance, const UwacTouchMotion* ev)
434{
435 int32_t x = 0;
436 int32_t y = 0;
437
438 WINPR_ASSERT(instance);
439 WINPR_ASSERT(ev);
440
441 wlfContext* wlf = (wlfContext*)instance->context;
442 WINPR_ASSERT(wlf);
443
444 x = ev->x;
445 y = ev->y;
446
447 if (!scale_signed_coordinates(instance->context, &x, &y, TRUE))
448 return FALSE;
449
450 return freerdp_client_handle_touch(&wlf->common, FREERDP_TOUCH_MOTION, 0,
451 WINPR_ASSERTING_INT_CAST(uint32_t, ev->id), x, y);
452}
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.