/src/FreeRDP/libfreerdp/core/input.c
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * FreeRDP: A Remote Desktop Protocol Implementation |
3 | | * Input PDUs |
4 | | * |
5 | | * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com> |
6 | | * |
7 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | | * you may not use this file except in compliance with the License. |
9 | | * You may obtain a copy of the License at |
10 | | * |
11 | | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | | * |
13 | | * Unless required by applicable law or agreed to in writing, software |
14 | | * distributed under the License is distributed on an "AS IS" BASIS, |
15 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | | * See the License for the specific language governing permissions and |
17 | | * limitations under the License. |
18 | | */ |
19 | | |
20 | | #include <time.h> |
21 | | #include <freerdp/config.h> |
22 | | |
23 | | #include <winpr/crt.h> |
24 | | #include <winpr/assert.h> |
25 | | |
26 | | #include <freerdp/input.h> |
27 | | #include <freerdp/log.h> |
28 | | |
29 | | #include "message.h" |
30 | | |
31 | | #include "input.h" |
32 | | |
33 | | #define TAG FREERDP_TAG("core") |
34 | | |
35 | | /* Input Events */ |
36 | 0 | #define INPUT_EVENT_SYNC 0x0000 |
37 | 0 | #define INPUT_EVENT_SCANCODE 0x0004 |
38 | 0 | #define INPUT_EVENT_UNICODE 0x0005 |
39 | 0 | #define INPUT_EVENT_MOUSE 0x8001 |
40 | 0 | #define INPUT_EVENT_MOUSEX 0x8002 |
41 | 0 | #define INPUT_EVENT_MOUSEREL 0x8004 |
42 | | |
43 | | #define RDP_CLIENT_INPUT_PDU_HEADER_LENGTH 4 |
44 | | |
45 | | static void rdp_write_client_input_pdu_header(wStream* s, UINT16 number) |
46 | 0 | { |
47 | 0 | WINPR_ASSERT(s); |
48 | 0 | WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 4); |
49 | 0 | Stream_Write_UINT16(s, number); /* numberEvents (2 bytes) */ |
50 | 0 | Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */ |
51 | 0 | } |
52 | | |
53 | | static void rdp_write_input_event_header(wStream* s, UINT32 time, UINT16 type) |
54 | 0 | { |
55 | 0 | WINPR_ASSERT(s); |
56 | 0 | WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 6); |
57 | 0 | Stream_Write_UINT32(s, time); /* eventTime (4 bytes) */ |
58 | 0 | Stream_Write_UINT16(s, type); /* messageType (2 bytes) */ |
59 | 0 | } |
60 | | |
61 | | static wStream* rdp_client_input_pdu_init(rdpRdp* rdp, UINT16 type) |
62 | 0 | { |
63 | 0 | wStream* s = NULL; |
64 | 0 | s = rdp_data_pdu_init(rdp); |
65 | |
|
66 | 0 | if (!s) |
67 | 0 | return NULL; |
68 | | |
69 | 0 | rdp_write_client_input_pdu_header(s, 1); |
70 | 0 | rdp_write_input_event_header(s, 0, type); |
71 | 0 | return s; |
72 | 0 | } |
73 | | |
74 | | static BOOL rdp_send_client_input_pdu(rdpRdp* rdp, wStream* s) |
75 | 0 | { |
76 | 0 | return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_INPUT, rdp->mcs->userId); |
77 | 0 | } |
78 | | |
79 | | static void input_write_synchronize_event(wStream* s, UINT32 flags) |
80 | 0 | { |
81 | 0 | WINPR_ASSERT(s); |
82 | 0 | WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 6); |
83 | 0 | Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */ |
84 | 0 | Stream_Write_UINT32(s, flags); /* toggleFlags (4 bytes) */ |
85 | 0 | } |
86 | | |
87 | | static BOOL input_ensure_client_running(rdpInput* input) |
88 | 0 | { |
89 | 0 | WINPR_ASSERT(input); |
90 | 0 | if (freerdp_shall_disconnect_context(input->context)) |
91 | 0 | { |
92 | 0 | WLog_WARN(TAG, "[APPLICATION BUG] input functions called after the session terminated"); |
93 | 0 | return FALSE; |
94 | 0 | } |
95 | 0 | return TRUE; |
96 | 0 | } |
97 | | |
98 | | static BOOL input_send_synchronize_event(rdpInput* input, UINT32 flags) |
99 | 0 | { |
100 | 0 | wStream* s = NULL; |
101 | 0 | rdpRdp* rdp = NULL; |
102 | |
|
103 | 0 | if (!input || !input->context) |
104 | 0 | return FALSE; |
105 | | |
106 | 0 | rdp = input->context->rdp; |
107 | |
|
108 | 0 | if (!input_ensure_client_running(input)) |
109 | 0 | return FALSE; |
110 | | |
111 | 0 | s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_SYNC); |
112 | |
|
113 | 0 | if (!s) |
114 | 0 | return FALSE; |
115 | | |
116 | 0 | input_write_synchronize_event(s, flags); |
117 | 0 | return rdp_send_client_input_pdu(rdp, s); |
118 | 0 | } |
119 | | |
120 | | static void input_write_keyboard_event(wStream* s, UINT16 flags, UINT16 code) |
121 | 0 | { |
122 | 0 | WINPR_ASSERT(s); |
123 | 0 | WINPR_ASSERT(code <= UINT8_MAX); |
124 | | |
125 | 0 | Stream_Write_UINT16(s, flags); /* keyboardFlags (2 bytes) */ |
126 | 0 | Stream_Write_UINT16(s, code); /* keyCode (2 bytes) */ |
127 | 0 | Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */ |
128 | 0 | } |
129 | | |
130 | | static BOOL input_send_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code) |
131 | 0 | { |
132 | 0 | wStream* s = NULL; |
133 | 0 | rdpRdp* rdp = NULL; |
134 | |
|
135 | 0 | if (!input || !input->context) |
136 | 0 | return FALSE; |
137 | | |
138 | 0 | rdp = input->context->rdp; |
139 | |
|
140 | 0 | if (!input_ensure_client_running(input)) |
141 | 0 | return FALSE; |
142 | | |
143 | 0 | s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_SCANCODE); |
144 | |
|
145 | 0 | if (!s) |
146 | 0 | return FALSE; |
147 | | |
148 | 0 | input_write_keyboard_event(s, flags, code); |
149 | 0 | return rdp_send_client_input_pdu(rdp, s); |
150 | 0 | } |
151 | | |
152 | | static void input_write_unicode_keyboard_event(wStream* s, UINT16 flags, UINT16 code) |
153 | 0 | { |
154 | 0 | Stream_Write_UINT16(s, flags); /* keyboardFlags (2 bytes) */ |
155 | 0 | Stream_Write_UINT16(s, code); /* unicodeCode (2 bytes) */ |
156 | 0 | Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */ |
157 | 0 | } |
158 | | |
159 | | static BOOL input_send_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) |
160 | 0 | { |
161 | 0 | wStream* s = NULL; |
162 | 0 | rdpRdp* rdp = NULL; |
163 | |
|
164 | 0 | if (!input || !input->context) |
165 | 0 | return FALSE; |
166 | | |
167 | 0 | if (!input_ensure_client_running(input)) |
168 | 0 | return FALSE; |
169 | | |
170 | 0 | if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_UnicodeInput)) |
171 | 0 | { |
172 | 0 | WLog_WARN(TAG, "Unicode input not supported by server."); |
173 | 0 | return FALSE; |
174 | 0 | } |
175 | | |
176 | 0 | rdp = input->context->rdp; |
177 | 0 | s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_UNICODE); |
178 | |
|
179 | 0 | if (!s) |
180 | 0 | return FALSE; |
181 | | |
182 | 0 | input_write_unicode_keyboard_event(s, flags, code); |
183 | 0 | return rdp_send_client_input_pdu(rdp, s); |
184 | 0 | } |
185 | | |
186 | | static void input_write_mouse_event(wStream* s, UINT16 flags, UINT16 x, UINT16 y) |
187 | 0 | { |
188 | 0 | Stream_Write_UINT16(s, flags); /* pointerFlags (2 bytes) */ |
189 | 0 | Stream_Write_UINT16(s, x); /* xPos (2 bytes) */ |
190 | 0 | Stream_Write_UINT16(s, y); /* yPos (2 bytes) */ |
191 | 0 | } |
192 | | |
193 | | static BOOL input_send_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) |
194 | 0 | { |
195 | 0 | wStream* s = NULL; |
196 | 0 | rdpRdp* rdp = NULL; |
197 | |
|
198 | 0 | if (!input || !input->context || !input->context->settings) |
199 | 0 | return FALSE; |
200 | | |
201 | 0 | rdp = input->context->rdp; |
202 | |
|
203 | 0 | if (!input_ensure_client_running(input)) |
204 | 0 | return FALSE; |
205 | | |
206 | 0 | if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_HasHorizontalWheel)) |
207 | 0 | { |
208 | 0 | if (flags & PTR_FLAGS_HWHEEL) |
209 | 0 | { |
210 | 0 | WLog_WARN(TAG, |
211 | 0 | "skip mouse event %" PRIu16 "x%" PRIu16 " flags=0x%04" PRIX16 |
212 | 0 | ", no horizontal mouse wheel supported", |
213 | 0 | x, y, flags); |
214 | 0 | return TRUE; |
215 | 0 | } |
216 | 0 | } |
217 | | |
218 | 0 | s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_MOUSE); |
219 | |
|
220 | 0 | if (!s) |
221 | 0 | return FALSE; |
222 | | |
223 | 0 | input_write_mouse_event(s, flags, x, y); |
224 | 0 | return rdp_send_client_input_pdu(rdp, s); |
225 | 0 | } |
226 | | |
227 | | static BOOL input_send_relmouse_event(rdpInput* input, UINT16 flags, INT16 xDelta, INT16 yDelta) |
228 | 0 | { |
229 | 0 | wStream* s = NULL; |
230 | 0 | rdpRdp* rdp = NULL; |
231 | |
|
232 | 0 | if (!input || !input->context || !input->context->settings) |
233 | 0 | return FALSE; |
234 | | |
235 | 0 | rdp = input->context->rdp; |
236 | |
|
237 | 0 | if (!input_ensure_client_running(input)) |
238 | 0 | return FALSE; |
239 | | |
240 | 0 | if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_HasRelativeMouseEvent)) |
241 | 0 | { |
242 | 0 | WLog_ERR(TAG, "Sending relative mouse event, but no support for that"); |
243 | 0 | return FALSE; |
244 | 0 | } |
245 | | |
246 | 0 | s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_MOUSEREL); |
247 | |
|
248 | 0 | if (!s) |
249 | 0 | return FALSE; |
250 | | |
251 | 0 | Stream_Write_UINT16(s, flags); /* pointerFlags (2 bytes) */ |
252 | 0 | Stream_Write_INT16(s, xDelta); /* xDelta (2 bytes) */ |
253 | 0 | Stream_Write_INT16(s, yDelta); /* yDelta (2 bytes) */ |
254 | |
|
255 | 0 | return rdp_send_client_input_pdu(rdp, s); |
256 | 0 | } |
257 | | |
258 | | static void input_write_extended_mouse_event(wStream* s, UINT16 flags, UINT16 x, UINT16 y) |
259 | 0 | { |
260 | 0 | Stream_Write_UINT16(s, flags); /* pointerFlags (2 bytes) */ |
261 | 0 | Stream_Write_UINT16(s, x); /* xPos (2 bytes) */ |
262 | 0 | Stream_Write_UINT16(s, y); /* yPos (2 bytes) */ |
263 | 0 | } |
264 | | |
265 | | static BOOL input_send_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) |
266 | 0 | { |
267 | 0 | wStream* s = NULL; |
268 | 0 | rdpRdp* rdp = NULL; |
269 | |
|
270 | 0 | WINPR_ASSERT(input); |
271 | 0 | WINPR_ASSERT(input->context); |
272 | 0 | WINPR_ASSERT(input->context->settings); |
273 | | |
274 | 0 | rdp = input->context->rdp; |
275 | 0 | WINPR_ASSERT(rdp); |
276 | | |
277 | 0 | if (!input_ensure_client_running(input)) |
278 | 0 | return FALSE; |
279 | | |
280 | 0 | if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_HasExtendedMouseEvent)) |
281 | 0 | { |
282 | 0 | WLog_WARN(TAG, |
283 | 0 | "skip extended mouse event %" PRIu16 "x%" PRIu16 " flags=0x%04" PRIX16 |
284 | 0 | ", no extended mouse events supported", |
285 | 0 | x, y, flags); |
286 | 0 | return TRUE; |
287 | 0 | } |
288 | | |
289 | 0 | s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_MOUSEX); |
290 | |
|
291 | 0 | if (!s) |
292 | 0 | return FALSE; |
293 | | |
294 | 0 | input_write_extended_mouse_event(s, flags, x, y); |
295 | 0 | return rdp_send_client_input_pdu(rdp, s); |
296 | 0 | } |
297 | | |
298 | | static BOOL input_send_focus_in_event(rdpInput* input, UINT16 toggleStates) |
299 | 0 | { |
300 | | /* send a tab up like mstsc.exe */ |
301 | 0 | if (!input_send_keyboard_event(input, KBD_FLAGS_RELEASE, 0x0f)) |
302 | 0 | return FALSE; |
303 | | |
304 | | /* send the toggle key states */ |
305 | 0 | if (!input_send_synchronize_event(input, (toggleStates & 0x1F))) |
306 | 0 | return FALSE; |
307 | | |
308 | | /* send another tab up like mstsc.exe */ |
309 | 0 | return input_send_keyboard_event(input, KBD_FLAGS_RELEASE, 0x0f); |
310 | 0 | } |
311 | | |
312 | | static BOOL input_send_keyboard_pause_event(rdpInput* input) |
313 | 0 | { |
314 | | /* In ancient days, pause-down without control sent E1 1D 45 E1 9D C5, |
315 | | * and pause-up sent nothing. However, reverse engineering mstsc shows |
316 | | * it sending the following sequence: |
317 | | */ |
318 | | |
319 | | /* Control down (0x1D) */ |
320 | 0 | if (!input_send_keyboard_event(input, KBD_FLAGS_EXTENDED1, |
321 | 0 | RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL))) |
322 | 0 | return FALSE; |
323 | | |
324 | | /* Numlock down (0x45) */ |
325 | 0 | if (!input_send_keyboard_event(input, 0, RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK))) |
326 | 0 | return FALSE; |
327 | | |
328 | | /* Control up (0x1D) */ |
329 | 0 | if (!input_send_keyboard_event(input, KBD_FLAGS_RELEASE | KBD_FLAGS_EXTENDED1, |
330 | 0 | RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL))) |
331 | 0 | return FALSE; |
332 | | |
333 | | /* Numlock up (0x45) */ |
334 | 0 | return input_send_keyboard_event(input, KBD_FLAGS_RELEASE, |
335 | 0 | RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK)); |
336 | 0 | } |
337 | | |
338 | | static BOOL input_send_fastpath_synchronize_event(rdpInput* input, UINT32 flags) |
339 | 0 | { |
340 | 0 | wStream* s = NULL; |
341 | 0 | rdpRdp* rdp = NULL; |
342 | |
|
343 | 0 | WINPR_ASSERT(input); |
344 | 0 | WINPR_ASSERT(input->context); |
345 | | |
346 | 0 | rdp = input->context->rdp; |
347 | 0 | WINPR_ASSERT(rdp); |
348 | | |
349 | 0 | if (!input_ensure_client_running(input)) |
350 | 0 | return FALSE; |
351 | | |
352 | | /* The FastPath Synchronization eventFlags has identical values as SlowPath */ |
353 | 0 | s = fastpath_input_pdu_init(rdp->fastpath, (BYTE)flags, FASTPATH_INPUT_EVENT_SYNC); |
354 | |
|
355 | 0 | if (!s) |
356 | 0 | return FALSE; |
357 | | |
358 | 0 | return fastpath_send_input_pdu(rdp->fastpath, s); |
359 | 0 | } |
360 | | |
361 | | static BOOL input_send_fastpath_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code) |
362 | 0 | { |
363 | 0 | wStream* s = NULL; |
364 | 0 | BYTE eventFlags = 0; |
365 | 0 | rdpRdp* rdp = NULL; |
366 | |
|
367 | 0 | WINPR_ASSERT(input); |
368 | 0 | WINPR_ASSERT(input->context); |
369 | | |
370 | 0 | rdp = input->context->rdp; |
371 | 0 | WINPR_ASSERT(rdp); |
372 | | |
373 | 0 | if (!input_ensure_client_running(input)) |
374 | 0 | return FALSE; |
375 | | |
376 | 0 | eventFlags |= (flags & KBD_FLAGS_RELEASE) ? FASTPATH_INPUT_KBDFLAGS_RELEASE : 0; |
377 | 0 | eventFlags |= (flags & KBD_FLAGS_EXTENDED) ? FASTPATH_INPUT_KBDFLAGS_EXTENDED : 0; |
378 | 0 | eventFlags |= (flags & KBD_FLAGS_EXTENDED1) ? FASTPATH_INPUT_KBDFLAGS_PREFIX_E1 : 0; |
379 | 0 | s = fastpath_input_pdu_init(rdp->fastpath, eventFlags, FASTPATH_INPUT_EVENT_SCANCODE); |
380 | |
|
381 | 0 | if (!s) |
382 | 0 | return FALSE; |
383 | | |
384 | 0 | WINPR_ASSERT(code <= UINT8_MAX); |
385 | 0 | Stream_Write_UINT8(s, (UINT8)code); /* keyCode (1 byte) */ |
386 | 0 | return fastpath_send_input_pdu(rdp->fastpath, s); |
387 | 0 | } |
388 | | |
389 | | static BOOL input_send_fastpath_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) |
390 | 0 | { |
391 | 0 | wStream* s = NULL; |
392 | 0 | BYTE eventFlags = 0; |
393 | 0 | rdpRdp* rdp = NULL; |
394 | |
|
395 | 0 | WINPR_ASSERT(input); |
396 | 0 | WINPR_ASSERT(input->context); |
397 | 0 | WINPR_ASSERT(input->context->settings); |
398 | | |
399 | 0 | rdp = input->context->rdp; |
400 | 0 | WINPR_ASSERT(rdp); |
401 | | |
402 | 0 | if (!input_ensure_client_running(input)) |
403 | 0 | return FALSE; |
404 | | |
405 | 0 | if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_UnicodeInput)) |
406 | 0 | { |
407 | 0 | WLog_WARN(TAG, "Unicode input not supported by server."); |
408 | 0 | return FALSE; |
409 | 0 | } |
410 | | |
411 | 0 | eventFlags |= (flags & KBD_FLAGS_RELEASE) ? FASTPATH_INPUT_KBDFLAGS_RELEASE : 0; |
412 | 0 | s = fastpath_input_pdu_init(rdp->fastpath, eventFlags, FASTPATH_INPUT_EVENT_UNICODE); |
413 | |
|
414 | 0 | if (!s) |
415 | 0 | return FALSE; |
416 | | |
417 | 0 | Stream_Write_UINT16(s, code); /* unicodeCode (2 bytes) */ |
418 | 0 | return fastpath_send_input_pdu(rdp->fastpath, s); |
419 | 0 | } |
420 | | |
421 | | static BOOL input_send_fastpath_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) |
422 | 0 | { |
423 | 0 | wStream* s = NULL; |
424 | 0 | rdpRdp* rdp = NULL; |
425 | |
|
426 | 0 | WINPR_ASSERT(input); |
427 | 0 | WINPR_ASSERT(input->context); |
428 | 0 | WINPR_ASSERT(input->context->settings); |
429 | | |
430 | 0 | rdp = input->context->rdp; |
431 | 0 | WINPR_ASSERT(rdp); |
432 | | |
433 | 0 | if (!input_ensure_client_running(input)) |
434 | 0 | return FALSE; |
435 | | |
436 | 0 | if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_HasHorizontalWheel)) |
437 | 0 | { |
438 | 0 | if (flags & PTR_FLAGS_HWHEEL) |
439 | 0 | { |
440 | 0 | WLog_WARN(TAG, |
441 | 0 | "skip mouse event %" PRIu16 "x%" PRIu16 " flags=0x%04" PRIX16 |
442 | 0 | ", no horizontal mouse wheel supported", |
443 | 0 | x, y, flags); |
444 | 0 | return TRUE; |
445 | 0 | } |
446 | 0 | } |
447 | | |
448 | 0 | s = fastpath_input_pdu_init(rdp->fastpath, 0, FASTPATH_INPUT_EVENT_MOUSE); |
449 | |
|
450 | 0 | if (!s) |
451 | 0 | return FALSE; |
452 | | |
453 | 0 | input_write_mouse_event(s, flags, x, y); |
454 | 0 | return fastpath_send_input_pdu(rdp->fastpath, s); |
455 | 0 | } |
456 | | |
457 | | static BOOL input_send_fastpath_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, |
458 | | UINT16 y) |
459 | 0 | { |
460 | 0 | wStream* s = NULL; |
461 | 0 | rdpRdp* rdp = NULL; |
462 | |
|
463 | 0 | WINPR_ASSERT(input); |
464 | 0 | WINPR_ASSERT(input->context); |
465 | | |
466 | 0 | rdp = input->context->rdp; |
467 | 0 | WINPR_ASSERT(rdp); |
468 | | |
469 | 0 | if (!input_ensure_client_running(input)) |
470 | 0 | return FALSE; |
471 | | |
472 | 0 | if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_HasExtendedMouseEvent)) |
473 | 0 | { |
474 | 0 | WLog_WARN(TAG, |
475 | 0 | "skip extended mouse event %" PRIu16 "x%" PRIu16 " flags=0x%04" PRIX16 |
476 | 0 | ", no extended mouse events supported", |
477 | 0 | x, y, flags); |
478 | 0 | return TRUE; |
479 | 0 | } |
480 | | |
481 | 0 | s = fastpath_input_pdu_init(rdp->fastpath, 0, FASTPATH_INPUT_EVENT_MOUSEX); |
482 | |
|
483 | 0 | if (!s) |
484 | 0 | return FALSE; |
485 | | |
486 | 0 | input_write_extended_mouse_event(s, flags, x, y); |
487 | 0 | return fastpath_send_input_pdu(rdp->fastpath, s); |
488 | 0 | } |
489 | | |
490 | | static BOOL input_send_fastpath_relmouse_event(rdpInput* input, UINT16 flags, INT16 xDelta, |
491 | | INT16 yDelta) |
492 | 0 | { |
493 | 0 | wStream* s = NULL; |
494 | 0 | rdpRdp* rdp = NULL; |
495 | |
|
496 | 0 | WINPR_ASSERT(input); |
497 | 0 | WINPR_ASSERT(input->context); |
498 | 0 | WINPR_ASSERT(input->context->settings); |
499 | | |
500 | 0 | rdp = input->context->rdp; |
501 | 0 | WINPR_ASSERT(rdp); |
502 | | |
503 | 0 | if (!input_ensure_client_running(input)) |
504 | 0 | return FALSE; |
505 | | |
506 | 0 | if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_HasRelativeMouseEvent)) |
507 | 0 | { |
508 | 0 | WLog_ERR(TAG, "Sending relative fastpath mouse event, but no support for that announced"); |
509 | 0 | return FALSE; |
510 | 0 | } |
511 | | |
512 | 0 | s = fastpath_input_pdu_init(rdp->fastpath, 0, TS_FP_RELPOINTER_EVENT); |
513 | |
|
514 | 0 | if (!s) |
515 | 0 | return FALSE; |
516 | | |
517 | 0 | Stream_Write_UINT16(s, flags); /* pointerFlags (2 bytes) */ |
518 | 0 | Stream_Write_INT16(s, xDelta); /* xDelta (2 bytes) */ |
519 | 0 | Stream_Write_INT16(s, yDelta); /* yDelta (2 bytes) */ |
520 | 0 | return fastpath_send_input_pdu(rdp->fastpath, s); |
521 | 0 | } |
522 | | |
523 | | static BOOL input_send_fastpath_qoe_event(rdpInput* input, UINT32 timestampMS) |
524 | 0 | { |
525 | 0 | WINPR_ASSERT(input); |
526 | 0 | WINPR_ASSERT(input->context); |
527 | 0 | WINPR_ASSERT(input->context->settings); |
528 | | |
529 | 0 | rdpRdp* rdp = input->context->rdp; |
530 | 0 | WINPR_ASSERT(rdp); |
531 | | |
532 | 0 | if (!input_ensure_client_running(input)) |
533 | 0 | return FALSE; |
534 | | |
535 | 0 | if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_HasQoeEvent)) |
536 | 0 | { |
537 | 0 | WLog_ERR(TAG, "Sending qoe event, but no support for that announced"); |
538 | 0 | return FALSE; |
539 | 0 | } |
540 | | |
541 | 0 | wStream* s = fastpath_input_pdu_init(rdp->fastpath, 0, TS_FP_QOETIMESTAMP_EVENT); |
542 | |
|
543 | 0 | if (!s) |
544 | 0 | return FALSE; |
545 | | |
546 | 0 | if (!Stream_EnsureRemainingCapacity(s, 4)) |
547 | 0 | { |
548 | 0 | Stream_Free(s, TRUE); |
549 | 0 | return FALSE; |
550 | 0 | } |
551 | | |
552 | 0 | Stream_Write_UINT32(s, timestampMS); |
553 | 0 | return fastpath_send_input_pdu(rdp->fastpath, s); |
554 | 0 | } |
555 | | |
556 | | static BOOL input_send_fastpath_focus_in_event(rdpInput* input, UINT16 toggleStates) |
557 | 0 | { |
558 | 0 | wStream* s = NULL; |
559 | 0 | BYTE eventFlags = 0; |
560 | 0 | rdpRdp* rdp = NULL; |
561 | |
|
562 | 0 | WINPR_ASSERT(input); |
563 | 0 | WINPR_ASSERT(input->context); |
564 | | |
565 | 0 | rdp = input->context->rdp; |
566 | 0 | WINPR_ASSERT(rdp); |
567 | | |
568 | 0 | if (!input_ensure_client_running(input)) |
569 | 0 | return FALSE; |
570 | | |
571 | 0 | s = fastpath_input_pdu_init_header(rdp->fastpath); |
572 | |
|
573 | 0 | if (!s) |
574 | 0 | return FALSE; |
575 | | |
576 | | /* send a tab up like mstsc.exe */ |
577 | 0 | eventFlags = FASTPATH_INPUT_KBDFLAGS_RELEASE | FASTPATH_INPUT_EVENT_SCANCODE << 5; |
578 | 0 | Stream_Write_UINT8(s, eventFlags); /* Key Release event (1 byte) */ |
579 | 0 | Stream_Write_UINT8(s, 0x0f); /* keyCode (1 byte) */ |
580 | | /* send the toggle key states */ |
581 | 0 | eventFlags = (toggleStates & 0x1F) | FASTPATH_INPUT_EVENT_SYNC << 5; |
582 | 0 | Stream_Write_UINT8(s, eventFlags); /* toggle state (1 byte) */ |
583 | | /* send another tab up like mstsc.exe */ |
584 | 0 | eventFlags = FASTPATH_INPUT_KBDFLAGS_RELEASE | FASTPATH_INPUT_EVENT_SCANCODE << 5; |
585 | 0 | Stream_Write_UINT8(s, eventFlags); /* Key Release event (1 byte) */ |
586 | 0 | Stream_Write_UINT8(s, 0x0f); /* keyCode (1 byte) */ |
587 | 0 | return fastpath_send_multiple_input_pdu(rdp->fastpath, s, 3); |
588 | 0 | } |
589 | | |
590 | | static BOOL input_send_fastpath_keyboard_pause_event(rdpInput* input) |
591 | 0 | { |
592 | | /* In ancient days, pause-down without control sent E1 1D 45 E1 9D C5, |
593 | | * and pause-up sent nothing. However, reverse engineering mstsc shows |
594 | | * it sending the following sequence: |
595 | | */ |
596 | 0 | wStream* s = NULL; |
597 | 0 | const BYTE keyDownEvent = FASTPATH_INPUT_EVENT_SCANCODE << 5; |
598 | 0 | const BYTE keyUpEvent = (FASTPATH_INPUT_EVENT_SCANCODE << 5) | FASTPATH_INPUT_KBDFLAGS_RELEASE; |
599 | 0 | rdpRdp* rdp = NULL; |
600 | |
|
601 | 0 | WINPR_ASSERT(input); |
602 | 0 | WINPR_ASSERT(input->context); |
603 | | |
604 | 0 | rdp = input->context->rdp; |
605 | 0 | WINPR_ASSERT(rdp); |
606 | | |
607 | 0 | if (!input_ensure_client_running(input)) |
608 | 0 | return FALSE; |
609 | | |
610 | 0 | s = fastpath_input_pdu_init_header(rdp->fastpath); |
611 | |
|
612 | 0 | if (!s) |
613 | 0 | return FALSE; |
614 | | |
615 | | /* Control down (0x1D) */ |
616 | 0 | Stream_Write_UINT8(s, keyDownEvent | FASTPATH_INPUT_KBDFLAGS_PREFIX_E1); |
617 | 0 | Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL)); |
618 | | /* Numlock down (0x45) */ |
619 | 0 | Stream_Write_UINT8(s, keyDownEvent); |
620 | 0 | Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK)); |
621 | | /* Control up (0x1D) */ |
622 | 0 | Stream_Write_UINT8(s, keyUpEvent | FASTPATH_INPUT_KBDFLAGS_PREFIX_E1); |
623 | 0 | Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL)); |
624 | | /* Numlock down (0x45) */ |
625 | 0 | Stream_Write_UINT8(s, keyUpEvent); |
626 | 0 | Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK)); |
627 | 0 | return fastpath_send_multiple_input_pdu(rdp->fastpath, s, 4); |
628 | 0 | } |
629 | | |
630 | | static BOOL input_recv_sync_event(rdpInput* input, wStream* s) |
631 | 0 | { |
632 | 0 | UINT32 toggleFlags = 0; |
633 | |
|
634 | 0 | WINPR_ASSERT(input); |
635 | 0 | WINPR_ASSERT(s); |
636 | | |
637 | 0 | if (!Stream_CheckAndLogRequiredLength(TAG, s, 6)) |
638 | 0 | return FALSE; |
639 | | |
640 | 0 | Stream_Seek(s, 2); /* pad2Octets (2 bytes) */ |
641 | 0 | Stream_Read_UINT32(s, toggleFlags); /* toggleFlags (4 bytes) */ |
642 | 0 | return IFCALLRESULT(TRUE, input->SynchronizeEvent, input, toggleFlags); |
643 | 0 | } |
644 | | |
645 | | static BOOL input_recv_keyboard_event(rdpInput* input, wStream* s) |
646 | 0 | { |
647 | 0 | UINT16 keyboardFlags = 0; |
648 | 0 | UINT16 keyCode = 0; |
649 | |
|
650 | 0 | WINPR_ASSERT(input); |
651 | 0 | WINPR_ASSERT(s); |
652 | | |
653 | 0 | if (!Stream_CheckAndLogRequiredLength(TAG, s, 6)) |
654 | 0 | return FALSE; |
655 | | |
656 | 0 | Stream_Read_UINT16(s, keyboardFlags); /* keyboardFlags (2 bytes) */ |
657 | 0 | Stream_Read_UINT16(s, keyCode); /* keyCode (2 bytes) */ |
658 | 0 | Stream_Seek(s, 2); /* pad2Octets (2 bytes) */ |
659 | |
|
660 | 0 | if (keyboardFlags & KBD_FLAGS_RELEASE) |
661 | 0 | keyboardFlags &= ~KBD_FLAGS_DOWN; |
662 | |
|
663 | 0 | if (keyCode & 0xFF00) |
664 | 0 | WLog_WARN(TAG, |
665 | 0 | "Problematic [MS-RDPBCGR] 2.2.8.1.1.3.1.1.1 Keyboard Event (TS_KEYBOARD_EVENT) " |
666 | 0 | "keyCode=0x%04" PRIx16 |
667 | 0 | ", high byte values should be sent in keyboardFlags field, ignoring.", |
668 | 0 | keyCode); |
669 | 0 | return IFCALLRESULT(TRUE, input->KeyboardEvent, input, keyboardFlags, keyCode & 0xFF); |
670 | 0 | } |
671 | | |
672 | | static BOOL input_recv_unicode_keyboard_event(rdpInput* input, wStream* s) |
673 | 0 | { |
674 | 0 | UINT16 keyboardFlags = 0; |
675 | 0 | UINT16 unicodeCode = 0; |
676 | |
|
677 | 0 | WINPR_ASSERT(input); |
678 | 0 | WINPR_ASSERT(s); |
679 | | |
680 | 0 | if (!Stream_CheckAndLogRequiredLength(TAG, s, 6)) |
681 | 0 | return FALSE; |
682 | | |
683 | 0 | Stream_Read_UINT16(s, keyboardFlags); /* keyboardFlags (2 bytes) */ |
684 | 0 | Stream_Read_UINT16(s, unicodeCode); /* unicodeCode (2 bytes) */ |
685 | 0 | Stream_Seek(s, 2); /* pad2Octets (2 bytes) */ |
686 | | |
687 | | /* "fix" keyboardFlags - see comment in input_recv_keyboard_event() */ |
688 | |
|
689 | 0 | if (keyboardFlags & KBD_FLAGS_RELEASE) |
690 | 0 | keyboardFlags &= ~KBD_FLAGS_DOWN; |
691 | |
|
692 | 0 | return IFCALLRESULT(TRUE, input->UnicodeKeyboardEvent, input, keyboardFlags, unicodeCode); |
693 | 0 | } |
694 | | |
695 | | static BOOL input_recv_mouse_event(rdpInput* input, wStream* s) |
696 | 0 | { |
697 | 0 | UINT16 pointerFlags = 0; |
698 | 0 | UINT16 xPos = 0; |
699 | 0 | UINT16 yPos = 0; |
700 | |
|
701 | 0 | WINPR_ASSERT(input); |
702 | 0 | WINPR_ASSERT(s); |
703 | | |
704 | 0 | if (!Stream_CheckAndLogRequiredLength(TAG, s, 6)) |
705 | 0 | return FALSE; |
706 | | |
707 | 0 | Stream_Read_UINT16(s, pointerFlags); /* pointerFlags (2 bytes) */ |
708 | 0 | Stream_Read_UINT16(s, xPos); /* xPos (2 bytes) */ |
709 | 0 | Stream_Read_UINT16(s, yPos); /* yPos (2 bytes) */ |
710 | 0 | return IFCALLRESULT(TRUE, input->MouseEvent, input, pointerFlags, xPos, yPos); |
711 | 0 | } |
712 | | |
713 | | static BOOL input_recv_relmouse_event(rdpInput* input, wStream* s) |
714 | 0 | { |
715 | 0 | UINT16 pointerFlags = 0; |
716 | 0 | INT16 xDelta = 0; |
717 | 0 | INT16 yDelta = 0; |
718 | |
|
719 | 0 | WINPR_ASSERT(input); |
720 | 0 | WINPR_ASSERT(s); |
721 | | |
722 | 0 | if (!Stream_CheckAndLogRequiredLength(TAG, s, 6)) |
723 | 0 | return FALSE; |
724 | | |
725 | 0 | Stream_Read_UINT16(s, pointerFlags); /* pointerFlags (2 bytes) */ |
726 | 0 | Stream_Read_INT16(s, xDelta); /* xPos (2 bytes) */ |
727 | 0 | Stream_Read_INT16(s, yDelta); /* yPos (2 bytes) */ |
728 | |
|
729 | 0 | if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_HasRelativeMouseEvent)) |
730 | 0 | { |
731 | 0 | WLog_ERR(TAG, |
732 | 0 | "Received relative mouse event(flags=0x%04" PRIx16 ", xPos=%" PRId16 |
733 | 0 | ", yPos=%" PRId16 "), but we did not announce support for that", |
734 | 0 | pointerFlags, xDelta, yDelta); |
735 | 0 | return FALSE; |
736 | 0 | } |
737 | | |
738 | 0 | return IFCALLRESULT(TRUE, input->RelMouseEvent, input, pointerFlags, xDelta, yDelta); |
739 | 0 | } |
740 | | |
741 | | static BOOL input_recv_extended_mouse_event(rdpInput* input, wStream* s) |
742 | 0 | { |
743 | 0 | UINT16 pointerFlags = 0; |
744 | 0 | UINT16 xPos = 0; |
745 | 0 | UINT16 yPos = 0; |
746 | |
|
747 | 0 | WINPR_ASSERT(input); |
748 | 0 | WINPR_ASSERT(s); |
749 | | |
750 | 0 | if (!Stream_CheckAndLogRequiredLength(TAG, s, 6)) |
751 | 0 | return FALSE; |
752 | | |
753 | 0 | Stream_Read_UINT16(s, pointerFlags); /* pointerFlags (2 bytes) */ |
754 | 0 | Stream_Read_UINT16(s, xPos); /* xPos (2 bytes) */ |
755 | 0 | Stream_Read_UINT16(s, yPos); /* yPos (2 bytes) */ |
756 | |
|
757 | 0 | if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_HasExtendedMouseEvent)) |
758 | 0 | { |
759 | 0 | WLog_ERR(TAG, |
760 | 0 | "Received extended mouse event(flags=0x%04" PRIx16 ", xPos=%" PRIu16 |
761 | 0 | ", yPos=%" PRIu16 "), but we did not announce support for that", |
762 | 0 | pointerFlags, xPos, yPos); |
763 | 0 | return FALSE; |
764 | 0 | } |
765 | | |
766 | 0 | return IFCALLRESULT(TRUE, input->ExtendedMouseEvent, input, pointerFlags, xPos, yPos); |
767 | 0 | } |
768 | | |
769 | | static BOOL input_recv_event(rdpInput* input, wStream* s) |
770 | 0 | { |
771 | 0 | UINT16 messageType = 0; |
772 | |
|
773 | 0 | WINPR_ASSERT(input); |
774 | 0 | WINPR_ASSERT(s); |
775 | | |
776 | 0 | if (!Stream_CheckAndLogRequiredLength(TAG, s, 6)) |
777 | 0 | return FALSE; |
778 | | |
779 | 0 | Stream_Seek(s, 4); /* eventTime (4 bytes), ignored by the server */ |
780 | 0 | Stream_Read_UINT16(s, messageType); /* messageType (2 bytes) */ |
781 | |
|
782 | 0 | switch (messageType) |
783 | 0 | { |
784 | 0 | case INPUT_EVENT_SYNC: |
785 | 0 | if (!input_recv_sync_event(input, s)) |
786 | 0 | return FALSE; |
787 | | |
788 | 0 | break; |
789 | | |
790 | 0 | case INPUT_EVENT_SCANCODE: |
791 | 0 | if (!input_recv_keyboard_event(input, s)) |
792 | 0 | return FALSE; |
793 | | |
794 | 0 | break; |
795 | | |
796 | 0 | case INPUT_EVENT_UNICODE: |
797 | 0 | if (!input_recv_unicode_keyboard_event(input, s)) |
798 | 0 | return FALSE; |
799 | | |
800 | 0 | break; |
801 | | |
802 | 0 | case INPUT_EVENT_MOUSE: |
803 | 0 | if (!input_recv_mouse_event(input, s)) |
804 | 0 | return FALSE; |
805 | | |
806 | 0 | break; |
807 | | |
808 | 0 | case INPUT_EVENT_MOUSEX: |
809 | 0 | if (!input_recv_extended_mouse_event(input, s)) |
810 | 0 | return FALSE; |
811 | | |
812 | 0 | break; |
813 | | |
814 | 0 | case INPUT_EVENT_MOUSEREL: |
815 | 0 | if (!input_recv_relmouse_event(input, s)) |
816 | 0 | return FALSE; |
817 | | |
818 | 0 | break; |
819 | | |
820 | 0 | default: |
821 | 0 | WLog_ERR(TAG, "Unknown messageType %" PRIu16 "", messageType); |
822 | | /* Each input event uses 6 bytes. */ |
823 | 0 | Stream_Seek(s, 6); |
824 | 0 | break; |
825 | 0 | } |
826 | | |
827 | 0 | return TRUE; |
828 | 0 | } |
829 | | |
830 | | BOOL input_recv(rdpInput* input, wStream* s) |
831 | 0 | { |
832 | 0 | UINT16 numberEvents = 0; |
833 | |
|
834 | 0 | WINPR_ASSERT(input); |
835 | 0 | WINPR_ASSERT(s); |
836 | | |
837 | 0 | if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) |
838 | 0 | return FALSE; |
839 | | |
840 | 0 | Stream_Read_UINT16(s, numberEvents); /* numberEvents (2 bytes) */ |
841 | 0 | Stream_Seek(s, 2); /* pad2Octets (2 bytes) */ |
842 | | |
843 | | /* Each input event uses 6 exactly bytes. */ |
844 | 0 | if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, numberEvents, 6ull)) |
845 | 0 | return FALSE; |
846 | | |
847 | 0 | for (UINT16 i = 0; i < numberEvents; i++) |
848 | 0 | { |
849 | 0 | if (!input_recv_event(input, s)) |
850 | 0 | return FALSE; |
851 | 0 | } |
852 | | |
853 | 0 | return TRUE; |
854 | 0 | } |
855 | | |
856 | | BOOL input_register_client_callbacks(rdpInput* input) |
857 | 0 | { |
858 | 0 | rdpSettings* settings = NULL; |
859 | |
|
860 | 0 | if (!input->context) |
861 | 0 | return FALSE; |
862 | | |
863 | 0 | settings = input->context->settings; |
864 | |
|
865 | 0 | if (!settings) |
866 | 0 | return FALSE; |
867 | | |
868 | 0 | if (freerdp_settings_get_bool(settings, FreeRDP_FastPathInput)) |
869 | 0 | { |
870 | 0 | input->SynchronizeEvent = input_send_fastpath_synchronize_event; |
871 | 0 | input->KeyboardEvent = input_send_fastpath_keyboard_event; |
872 | 0 | input->KeyboardPauseEvent = input_send_fastpath_keyboard_pause_event; |
873 | 0 | input->UnicodeKeyboardEvent = input_send_fastpath_unicode_keyboard_event; |
874 | 0 | input->MouseEvent = input_send_fastpath_mouse_event; |
875 | 0 | input->RelMouseEvent = input_send_fastpath_relmouse_event; |
876 | 0 | input->ExtendedMouseEvent = input_send_fastpath_extended_mouse_event; |
877 | 0 | input->FocusInEvent = input_send_fastpath_focus_in_event; |
878 | 0 | input->QoEEvent = input_send_fastpath_qoe_event; |
879 | 0 | } |
880 | 0 | else |
881 | 0 | { |
882 | 0 | input->SynchronizeEvent = input_send_synchronize_event; |
883 | 0 | input->KeyboardEvent = input_send_keyboard_event; |
884 | 0 | input->KeyboardPauseEvent = input_send_keyboard_pause_event; |
885 | 0 | input->UnicodeKeyboardEvent = input_send_unicode_keyboard_event; |
886 | 0 | input->MouseEvent = input_send_mouse_event; |
887 | 0 | input->RelMouseEvent = input_send_relmouse_event; |
888 | 0 | input->ExtendedMouseEvent = input_send_extended_mouse_event; |
889 | 0 | input->FocusInEvent = input_send_focus_in_event; |
890 | 0 | } |
891 | |
|
892 | 0 | return TRUE; |
893 | 0 | } |
894 | | |
895 | | /* Save last input timestamp and/or mouse position in prevent-session-lock mode */ |
896 | | static BOOL input_update_last_event(rdpInput* input, BOOL mouse, UINT16 x, UINT16 y) |
897 | 0 | { |
898 | 0 | rdp_input_internal* in = input_cast(input); |
899 | |
|
900 | 0 | WINPR_ASSERT(input); |
901 | 0 | WINPR_ASSERT(input->context); |
902 | | |
903 | 0 | if (freerdp_settings_get_uint32(input->context->settings, FreeRDP_FakeMouseMotionInterval) > 0) |
904 | 0 | { |
905 | 0 | const time_t now = time(NULL); |
906 | 0 | in->lastInputTimestamp = now; |
907 | |
|
908 | 0 | if (mouse) |
909 | 0 | { |
910 | 0 | in->lastX = x; |
911 | 0 | in->lastY = y; |
912 | 0 | } |
913 | 0 | } |
914 | 0 | return TRUE; |
915 | 0 | } |
916 | | |
917 | | BOOL freerdp_input_send_synchronize_event(rdpInput* input, UINT32 flags) |
918 | 0 | { |
919 | 0 | if (!input || !input->context) |
920 | 0 | return FALSE; |
921 | | |
922 | 0 | if (freerdp_settings_get_bool(input->context->settings, FreeRDP_SuspendInput)) |
923 | 0 | return TRUE; |
924 | | |
925 | 0 | return IFCALLRESULT(TRUE, input->SynchronizeEvent, input, flags); |
926 | 0 | } |
927 | | |
928 | | BOOL freerdp_input_send_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code) |
929 | 0 | { |
930 | 0 | if (!input || !input->context) |
931 | 0 | return FALSE; |
932 | | |
933 | 0 | if (freerdp_settings_get_bool(input->context->settings, FreeRDP_SuspendInput)) |
934 | 0 | return TRUE; |
935 | | |
936 | 0 | input_update_last_event(input, FALSE, 0, 0); |
937 | |
|
938 | 0 | return IFCALLRESULT(TRUE, input->KeyboardEvent, input, flags, code); |
939 | 0 | } |
940 | | |
941 | | BOOL freerdp_input_send_keyboard_event_ex(rdpInput* input, BOOL down, BOOL repeat, |
942 | | UINT32 rdp_scancode) |
943 | 0 | { |
944 | 0 | UINT16 flags = (RDP_SCANCODE_EXTENDED(rdp_scancode) ? KBD_FLAGS_EXTENDED : 0); |
945 | 0 | if (down && repeat) |
946 | 0 | flags |= KBD_FLAGS_DOWN; |
947 | 0 | else if (!down) |
948 | 0 | flags |= KBD_FLAGS_RELEASE; |
949 | |
|
950 | 0 | return freerdp_input_send_keyboard_event(input, flags, RDP_SCANCODE_CODE(rdp_scancode)); |
951 | 0 | } |
952 | | |
953 | | BOOL freerdp_input_send_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) |
954 | 0 | { |
955 | 0 | if (!input || !input->context) |
956 | 0 | return FALSE; |
957 | | |
958 | 0 | if (freerdp_settings_get_bool(input->context->settings, FreeRDP_SuspendInput)) |
959 | 0 | return TRUE; |
960 | | |
961 | 0 | input_update_last_event(input, FALSE, 0, 0); |
962 | |
|
963 | 0 | return IFCALLRESULT(TRUE, input->UnicodeKeyboardEvent, input, flags, code); |
964 | 0 | } |
965 | | |
966 | | BOOL freerdp_input_send_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) |
967 | 0 | { |
968 | 0 | if (!input || !input->context) |
969 | 0 | return FALSE; |
970 | | |
971 | 0 | if (freerdp_settings_get_bool(input->context->settings, FreeRDP_SuspendInput)) |
972 | 0 | return TRUE; |
973 | | |
974 | 0 | input_update_last_event( |
975 | 0 | input, flags & (PTR_FLAGS_MOVE | PTR_FLAGS_BUTTON1 | PTR_FLAGS_BUTTON2 | PTR_FLAGS_BUTTON3), |
976 | 0 | x, y); |
977 | |
|
978 | 0 | return IFCALLRESULT(TRUE, input->MouseEvent, input, flags, x, y); |
979 | 0 | } |
980 | | |
981 | | BOOL freerdp_input_send_rel_mouse_event(rdpInput* input, UINT16 flags, INT16 xDelta, INT16 yDelta) |
982 | 0 | { |
983 | 0 | if (!input || !input->context) |
984 | 0 | return FALSE; |
985 | | |
986 | 0 | if (freerdp_settings_get_bool(input->context->settings, FreeRDP_SuspendInput)) |
987 | 0 | return TRUE; |
988 | | |
989 | 0 | return IFCALLRESULT(TRUE, input->RelMouseEvent, input, flags, xDelta, yDelta); |
990 | 0 | } |
991 | | |
992 | | BOOL freerdp_input_send_qoe_timestamp(rdpInput* input, UINT32 timestampMS) |
993 | 0 | { |
994 | 0 | if (!input || !input->context) |
995 | 0 | return FALSE; |
996 | | |
997 | 0 | return IFCALLRESULT(TRUE, input->QoEEvent, input, timestampMS); |
998 | 0 | } |
999 | | |
1000 | | BOOL freerdp_input_send_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) |
1001 | 0 | { |
1002 | 0 | if (!input || !input->context) |
1003 | 0 | return FALSE; |
1004 | | |
1005 | 0 | if (freerdp_settings_get_bool(input->context->settings, FreeRDP_SuspendInput)) |
1006 | 0 | return TRUE; |
1007 | | |
1008 | 0 | input_update_last_event(input, TRUE, x, y); |
1009 | |
|
1010 | 0 | return IFCALLRESULT(TRUE, input->ExtendedMouseEvent, input, flags, x, y); |
1011 | 0 | } |
1012 | | |
1013 | | BOOL freerdp_input_send_focus_in_event(rdpInput* input, UINT16 toggleStates) |
1014 | 0 | { |
1015 | 0 | if (!input || !input->context) |
1016 | 0 | return FALSE; |
1017 | | |
1018 | 0 | if (freerdp_settings_get_bool(input->context->settings, FreeRDP_SuspendInput)) |
1019 | 0 | return TRUE; |
1020 | | |
1021 | 0 | return IFCALLRESULT(TRUE, input->FocusInEvent, input, toggleStates); |
1022 | 0 | } |
1023 | | |
1024 | | BOOL freerdp_input_send_keyboard_pause_event(rdpInput* input) |
1025 | 0 | { |
1026 | 0 | if (!input || !input->context) |
1027 | 0 | return FALSE; |
1028 | | |
1029 | 0 | if (freerdp_settings_get_bool(input->context->settings, FreeRDP_SuspendInput)) |
1030 | 0 | return TRUE; |
1031 | | |
1032 | 0 | return IFCALLRESULT(TRUE, input->KeyboardPauseEvent, input); |
1033 | 0 | } |
1034 | | |
1035 | | int input_process_events(rdpInput* input) |
1036 | 0 | { |
1037 | 0 | if (!input) |
1038 | 0 | return FALSE; |
1039 | | |
1040 | 0 | return input_message_queue_process_pending_messages(input); |
1041 | 0 | } |
1042 | | |
1043 | | static void input_free_queued_message(void* obj) |
1044 | 0 | { |
1045 | 0 | wMessage* msg = (wMessage*)obj; |
1046 | 0 | input_message_queue_free_message(msg); |
1047 | 0 | } |
1048 | | |
1049 | | rdpInput* input_new(rdpRdp* rdp) |
1050 | 14.9k | { |
1051 | 14.9k | const wObject cb = { NULL, NULL, NULL, input_free_queued_message, NULL }; |
1052 | 14.9k | rdp_input_internal* input = (rdp_input_internal*)calloc(1, sizeof(rdp_input_internal)); |
1053 | | |
1054 | 14.9k | WINPR_UNUSED(rdp); |
1055 | | |
1056 | 14.9k | if (!input) |
1057 | 0 | return NULL; |
1058 | | |
1059 | 14.9k | input->common.context = rdp->context; |
1060 | 14.9k | input->queue = MessageQueue_New(&cb); |
1061 | | |
1062 | 14.9k | if (!input->queue) |
1063 | 0 | { |
1064 | 0 | free(input); |
1065 | 0 | return NULL; |
1066 | 0 | } |
1067 | | |
1068 | 14.9k | return &input->common; |
1069 | 14.9k | } |
1070 | | |
1071 | | void input_free(rdpInput* input) |
1072 | 14.9k | { |
1073 | 14.9k | if (input != NULL) |
1074 | 14.9k | { |
1075 | 14.9k | rdp_input_internal* in = input_cast(input); |
1076 | | |
1077 | 14.9k | MessageQueue_Free(in->queue); |
1078 | 14.9k | free(in); |
1079 | 14.9k | } |
1080 | 14.9k | } |