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