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