2 * FreeRDP: A Remote Desktop Protocol Client
5 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 void rdp_write_client_input_pdu_header(STREAM* s, uint16 number)
24 stream_write_uint16(s, 1); /* numberEvents (2 bytes) */
25 stream_write_uint16(s, 0); /* pad2Octets (2 bytes) */
28 void rdp_write_input_event_header(STREAM* s, uint32 time, uint16 type)
30 stream_write_uint32(s, time); /* eventTime (4 bytes) */
31 stream_write_uint16(s, type); /* messageType (2 bytes) */
34 STREAM* rdp_client_input_pdu_init(rdpRdp* rdp, uint16 type)
37 s = rdp_data_pdu_init(rdp);
38 rdp_write_client_input_pdu_header(s, 1);
39 rdp_write_input_event_header(s, 0, type);
43 void rdp_send_client_input_pdu(rdpRdp* rdp, STREAM* s)
45 rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_INPUT, rdp->mcs->user_id);
48 void input_write_synchronize_event(STREAM* s, uint32 flags)
50 stream_write_uint16(s, 0); /* pad2Octets (2 bytes) */
51 stream_write_uint32(s, flags); /* toggleFlags (4 bytes) */
54 void input_send_synchronize_event(rdpInput* input, uint32 flags)
57 rdpRdp* rdp = input->context->rdp;
59 s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_SYNC);
60 input_write_synchronize_event(s, flags);
61 rdp_send_client_input_pdu(rdp, s);
64 void input_write_keyboard_event(STREAM* s, uint16 flags, uint16 code)
66 stream_write_uint16(s, flags); /* keyboardFlags (2 bytes) */
67 stream_write_uint16(s, code); /* keyCode (2 bytes) */
68 stream_write_uint16(s, 0); /* pad2Octets (2 bytes) */
71 void input_send_keyboard_event(rdpInput* input, uint16 flags, uint16 code)
74 rdpRdp* rdp = input->context->rdp;
76 s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_SCANCODE);
77 input_write_keyboard_event(s, flags, code);
78 rdp_send_client_input_pdu(rdp, s);
81 void input_write_unicode_keyboard_event(STREAM* s, uint16 flags, uint16 code)
83 stream_write_uint16(s, flags); /* keyboardFlags (2 bytes) */
84 stream_write_uint16(s, code); /* unicodeCode (2 bytes) */
85 stream_write_uint16(s, 0); /* pad2Octets (2 bytes) */
88 void input_send_unicode_keyboard_event(rdpInput* input, uint16 flags, uint16 code)
91 uint16 keyboardFlags = 0;
92 rdpRdp* rdp = input->context->rdp;
95 * According to the specification, the slow path Unicode Keyboard Event
96 * (TS_UNICODE_KEYBOARD_EVENT) contains KBD_FLAGS_RELEASE flag when key
97 * is released, but contains no flags when it is pressed.
98 * This is different from the slow path Keyboard Event
99 * (TS_KEYBOARD_EVENT) which does contain KBD_FLAGS_DOWN flag when the
101 * There is no KBD_FLAGS_EXTENDED flag in TS_UNICODE_KEYBOARD_EVENT.
103 keyboardFlags |= (flags & KBD_FLAGS_RELEASE) ? KBD_FLAGS_RELEASE : 0;
105 s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_UNICODE);
106 input_write_unicode_keyboard_event(s, flags, code);
107 rdp_send_client_input_pdu(rdp, s);
110 void input_write_mouse_event(STREAM* s, uint16 flags, uint16 x, uint16 y)
112 stream_write_uint16(s, flags); /* pointerFlags (2 bytes) */
113 stream_write_uint16(s, x); /* xPos (2 bytes) */
114 stream_write_uint16(s, y); /* yPos (2 bytes) */
117 void input_send_mouse_event(rdpInput* input, uint16 flags, uint16 x, uint16 y)
120 rdpRdp* rdp = input->context->rdp;
122 s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_MOUSE);
123 input_write_mouse_event(s, flags, x, y);
124 rdp_send_client_input_pdu(rdp, s);
127 void input_write_extended_mouse_event(STREAM* s, uint16 flags, uint16 x, uint16 y)
129 stream_write_uint16(s, flags); /* pointerFlags (2 bytes) */
130 stream_write_uint16(s, x); /* xPos (2 bytes) */
131 stream_write_uint16(s, y); /* yPos (2 bytes) */
134 void input_send_extended_mouse_event(rdpInput* input, uint16 flags, uint16 x, uint16 y)
137 rdpRdp* rdp = input->context->rdp;
139 s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_MOUSEX);
140 input_write_extended_mouse_event(s, flags, x, y);
141 rdp_send_client_input_pdu(rdp, s);
144 void input_send_fastpath_synchronize_event(rdpInput* input, uint32 flags)
147 rdpRdp* rdp = input->context->rdp;
149 /* The FastPath Synchronization eventFlags has identical values as SlowPath */
150 s = fastpath_input_pdu_init(rdp->fastpath, (uint8) flags, FASTPATH_INPUT_EVENT_SYNC);
151 fastpath_send_input_pdu(rdp->fastpath, s);
154 void input_send_fastpath_keyboard_event(rdpInput* input, uint16 flags, uint16 code)
157 uint8 eventFlags = 0;
158 rdpRdp* rdp = input->context->rdp;
160 eventFlags |= (flags & KBD_FLAGS_RELEASE) ? FASTPATH_INPUT_KBDFLAGS_RELEASE : 0;
161 eventFlags |= (flags & KBD_FLAGS_EXTENDED) ? FASTPATH_INPUT_KBDFLAGS_EXTENDED : 0;
162 s = fastpath_input_pdu_init(rdp->fastpath, eventFlags, FASTPATH_INPUT_EVENT_SCANCODE);
163 stream_write_uint8(s, code); /* keyCode (1 byte) */
164 fastpath_send_input_pdu(rdp->fastpath, s);
167 void input_send_fastpath_unicode_keyboard_event(rdpInput* input, uint16 flags, uint16 code)
170 uint8 eventFlags = 0;
171 rdpRdp* rdp = input->context->rdp;
173 eventFlags |= (flags & KBD_FLAGS_RELEASE) ? FASTPATH_INPUT_KBDFLAGS_RELEASE : 0;
174 s = fastpath_input_pdu_init(rdp->fastpath, eventFlags, FASTPATH_INPUT_EVENT_UNICODE);
175 stream_write_uint16(s, code); /* unicodeCode (2 bytes) */
176 fastpath_send_input_pdu(rdp->fastpath, s);
179 void input_send_fastpath_mouse_event(rdpInput* input, uint16 flags, uint16 x, uint16 y)
182 rdpRdp* rdp = input->context->rdp;
184 s = fastpath_input_pdu_init(rdp->fastpath, 0, FASTPATH_INPUT_EVENT_MOUSE);
185 input_write_mouse_event(s, flags, x, y);
186 fastpath_send_input_pdu(rdp->fastpath, s);
189 void input_send_fastpath_extended_mouse_event(rdpInput* input, uint16 flags, uint16 x, uint16 y)
192 rdpRdp* rdp = input->context->rdp;
194 s = fastpath_input_pdu_init(rdp->fastpath, 0, FASTPATH_INPUT_EVENT_MOUSEX);
195 input_write_extended_mouse_event(s, flags, x, y);
196 fastpath_send_input_pdu(rdp->fastpath, s);
199 static boolean input_recv_sync_event(rdpInput* input, STREAM* s)
203 if (stream_get_left(s) < 6)
206 stream_seek(s, 2); /* pad2Octets (2 bytes) */
207 stream_read_uint32(s, toggleFlags); /* toggleFlags (4 bytes) */
209 IFCALL(input->SynchronizeEvent, input, toggleFlags);
214 static boolean input_recv_keyboard_event(rdpInput* input, STREAM* s)
216 uint16 keyboardFlags, keyCode;
218 if (stream_get_left(s) < 6)
221 stream_read_uint16(s, keyboardFlags); /* keyboardFlags (2 bytes) */
222 stream_read_uint16(s, keyCode); /* keyCode (2 bytes) */
223 stream_seek(s, 2); /* pad2Octets (2 bytes) */
225 IFCALL(input->KeyboardEvent, input, keyboardFlags, keyCode);
230 static boolean input_recv_unicode_keyboard_event(rdpInput* input, STREAM* s)
232 uint16 keyboardFlags, unicodeCode;
234 if (stream_get_left(s) < 6)
237 stream_read_uint16(s, keyboardFlags); /* keyboardFlags (2 bytes) */
238 stream_read_uint16(s, unicodeCode); /* unicodeCode (2 bytes) */
239 stream_seek(s, 2); /* pad2Octets (2 bytes) */
242 * According to the specification, the slow path Unicode Keyboard Event
243 * (TS_UNICODE_KEYBOARD_EVENT) contains KBD_FLAGS_RELEASE flag when key
244 * is released, but contains no flags when it is pressed.
245 * This is different from the slow path Keyboard Event
246 * (TS_KEYBOARD_EVENT) which does contain KBD_FLAGS_DOWN flag when the
248 * Set the KBD_FLAGS_DOWN flag if the KBD_FLAGS_RELEASE flag is missing.
251 if ((keyboardFlags & KBD_FLAGS_RELEASE) == 0)
252 keyboardFlags |= KBD_FLAGS_DOWN;
254 IFCALL(input->UnicodeKeyboardEvent, input, keyboardFlags, unicodeCode);
259 static boolean input_recv_mouse_event(rdpInput* input, STREAM* s)
261 uint16 pointerFlags, xPos, yPos;
263 if (stream_get_left(s) < 6)
266 stream_read_uint16(s, pointerFlags); /* pointerFlags (2 bytes) */
267 stream_read_uint16(s, xPos); /* xPos (2 bytes) */
268 stream_read_uint16(s, yPos); /* yPos (2 bytes) */
270 IFCALL(input->MouseEvent, input, pointerFlags, xPos, yPos);
275 static boolean input_recv_extended_mouse_event(rdpInput* input, STREAM* s)
277 uint16 pointerFlags, xPos, yPos;
279 if (stream_get_left(s) < 6)
282 stream_read_uint16(s, pointerFlags); /* pointerFlags (2 bytes) */
283 stream_read_uint16(s, xPos); /* xPos (2 bytes) */
284 stream_read_uint16(s, yPos); /* yPos (2 bytes) */
286 IFCALL(input->ExtendedMouseEvent, input, pointerFlags, xPos, yPos);
291 static boolean input_recv_event(rdpInput* input, STREAM* s)
295 if (stream_get_left(s) < 4)
298 stream_seek(s, 4); /* eventTime (4 bytes), ignored by the server */
299 stream_read_uint16(s, messageType); /* messageType (2 bytes) */
303 case INPUT_EVENT_SYNC:
304 if (!input_recv_sync_event(input, s))
308 case INPUT_EVENT_SCANCODE:
309 if (!input_recv_keyboard_event(input, s))
313 case INPUT_EVENT_UNICODE:
314 if (!input_recv_unicode_keyboard_event(input, s))
318 case INPUT_EVENT_MOUSE:
319 if (!input_recv_mouse_event(input, s))
323 case INPUT_EVENT_MOUSEX:
324 if (!input_recv_extended_mouse_event(input, s))
329 printf("Unknown messageType %u\n", messageType);
330 /* Each input event uses 6 bytes. */
338 boolean input_recv(rdpInput* input, STREAM* s)
340 uint16 i, numberEvents;
342 if (stream_get_left(s) < 4)
345 stream_read_uint16(s, numberEvents); /* numberEvents (2 bytes) */
346 stream_seek(s, 2); /* pad2Octets (2 bytes) */
348 /* Each input event uses 6 exactly bytes. */
349 if (stream_get_left(s) < 6 * numberEvents)
352 for (i = 0; i < numberEvents; i++)
354 if (!input_recv_event(input, s))
361 void input_register_client_callbacks(rdpInput* input)
363 rdpRdp* rdp = input->context->rdp;
365 if (rdp->settings->fastpath_input)
367 input->SynchronizeEvent = input_send_fastpath_synchronize_event;
368 input->KeyboardEvent = input_send_fastpath_keyboard_event;
369 input->UnicodeKeyboardEvent = input_send_fastpath_unicode_keyboard_event;
370 input->MouseEvent = input_send_fastpath_mouse_event;
371 input->ExtendedMouseEvent = input_send_fastpath_extended_mouse_event;
375 input->SynchronizeEvent = input_send_synchronize_event;
376 input->KeyboardEvent = input_send_keyboard_event;
377 input->UnicodeKeyboardEvent = input_send_unicode_keyboard_event;
378 input->MouseEvent = input_send_mouse_event;
379 input->ExtendedMouseEvent = input_send_extended_mouse_event;
383 rdpInput* input_new(rdpRdp* rdp)
387 input = (rdpInput*) xzalloc(sizeof(rdpInput));
397 void input_free(rdpInput* input)