Initial commit - from Precise source
[freerdp-ubuntu-pcb-backport.git] / libfreerdp-core / input.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Client
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 "input.h"
21
22 void rdp_write_client_input_pdu_header(STREAM* s, uint16 number)
23 {
24         stream_write_uint16(s, 1); /* numberEvents (2 bytes) */
25         stream_write_uint16(s, 0); /* pad2Octets (2 bytes) */
26 }
27
28 void rdp_write_input_event_header(STREAM* s, uint32 time, uint16 type)
29 {
30         stream_write_uint32(s, time); /* eventTime (4 bytes) */
31         stream_write_uint16(s, type); /* messageType (2 bytes) */
32 }
33
34 STREAM* rdp_client_input_pdu_init(rdpRdp* rdp, uint16 type)
35 {
36         STREAM* s;
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);
40         return s;
41 }
42
43 void rdp_send_client_input_pdu(rdpRdp* rdp, STREAM* s)
44 {
45         rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_INPUT, rdp->mcs->user_id);
46 }
47
48 void input_write_synchronize_event(STREAM* s, uint32 flags)
49 {
50         stream_write_uint16(s, 0); /* pad2Octets (2 bytes) */
51         stream_write_uint32(s, flags); /* toggleFlags (4 bytes) */
52 }
53
54 void input_send_synchronize_event(rdpInput* input, uint32 flags)
55 {
56         STREAM* s;
57         rdpRdp* rdp = input->context->rdp;
58
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);
62 }
63
64 void input_write_keyboard_event(STREAM* s, uint16 flags, uint16 code)
65 {
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) */
69 }
70
71 void input_send_keyboard_event(rdpInput* input, uint16 flags, uint16 code)
72 {
73         STREAM* s;
74         rdpRdp* rdp = input->context->rdp;
75
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);
79 }
80
81 void input_write_unicode_keyboard_event(STREAM* s, uint16 flags, uint16 code)
82 {
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) */
86 }
87
88 void input_send_unicode_keyboard_event(rdpInput* input, uint16 flags, uint16 code)
89 {
90         STREAM* s;
91         uint16 keyboardFlags = 0;
92         rdpRdp* rdp = input->context->rdp;
93
94         /*
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
100          * key is pressed.
101          * There is no KBD_FLAGS_EXTENDED flag in TS_UNICODE_KEYBOARD_EVENT.
102          */
103         keyboardFlags |= (flags & KBD_FLAGS_RELEASE) ? KBD_FLAGS_RELEASE : 0;
104
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);
108 }
109
110 void input_write_mouse_event(STREAM* s, uint16 flags, uint16 x, uint16 y)
111 {
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) */
115 }
116
117 void input_send_mouse_event(rdpInput* input, uint16 flags, uint16 x, uint16 y)
118 {
119         STREAM* s;
120         rdpRdp* rdp = input->context->rdp;
121
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);
125 }
126
127 void input_write_extended_mouse_event(STREAM* s, uint16 flags, uint16 x, uint16 y)
128 {
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) */
132 }
133
134 void input_send_extended_mouse_event(rdpInput* input, uint16 flags, uint16 x, uint16 y)
135 {
136         STREAM* s;
137         rdpRdp* rdp = input->context->rdp;
138
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);
142 }
143
144 void input_send_fastpath_synchronize_event(rdpInput* input, uint32 flags)
145 {
146         STREAM* s;
147         rdpRdp* rdp = input->context->rdp;
148
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);
152 }
153
154 void input_send_fastpath_keyboard_event(rdpInput* input, uint16 flags, uint16 code)
155 {
156         STREAM* s;
157         uint8 eventFlags = 0;
158         rdpRdp* rdp = input->context->rdp;
159
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);
165 }
166
167 void input_send_fastpath_unicode_keyboard_event(rdpInput* input, uint16 flags, uint16 code)
168 {
169         STREAM* s;
170         uint8 eventFlags = 0;
171         rdpRdp* rdp = input->context->rdp;
172
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);
177 }
178
179 void input_send_fastpath_mouse_event(rdpInput* input, uint16 flags, uint16 x, uint16 y)
180 {
181         STREAM* s;
182         rdpRdp* rdp = input->context->rdp;
183
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);
187 }
188
189 void input_send_fastpath_extended_mouse_event(rdpInput* input, uint16 flags, uint16 x, uint16 y)
190 {
191         STREAM* s;
192         rdpRdp* rdp = input->context->rdp;
193
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);
197 }
198
199 static boolean input_recv_sync_event(rdpInput* input, STREAM* s)
200 {
201         uint32 toggleFlags;
202
203         if (stream_get_left(s) < 6)
204                 return false;
205
206         stream_seek(s, 2); /* pad2Octets (2 bytes) */
207         stream_read_uint32(s, toggleFlags); /* toggleFlags (4 bytes) */
208
209         IFCALL(input->SynchronizeEvent, input, toggleFlags);
210
211         return true;
212 }
213
214 static boolean input_recv_keyboard_event(rdpInput* input, STREAM* s)
215 {
216         uint16 keyboardFlags, keyCode;
217
218         if (stream_get_left(s) < 6)
219                 return false;
220
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) */
224
225         IFCALL(input->KeyboardEvent, input, keyboardFlags, keyCode);
226
227         return true;
228 }
229
230 static boolean input_recv_unicode_keyboard_event(rdpInput* input, STREAM* s)
231 {
232         uint16 keyboardFlags, unicodeCode;
233
234         if (stream_get_left(s) < 6)
235                 return false;
236
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) */
240
241         /*
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
247          * key is pressed.
248          * Set the KBD_FLAGS_DOWN flag if the KBD_FLAGS_RELEASE flag is missing.
249          */
250
251         if ((keyboardFlags & KBD_FLAGS_RELEASE) == 0)
252                 keyboardFlags |= KBD_FLAGS_DOWN;
253
254         IFCALL(input->UnicodeKeyboardEvent, input, keyboardFlags, unicodeCode);
255
256         return true;
257 }
258
259 static boolean input_recv_mouse_event(rdpInput* input, STREAM* s)
260 {
261         uint16 pointerFlags, xPos, yPos;
262
263         if (stream_get_left(s) < 6)
264                 return false;
265
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) */
269
270         IFCALL(input->MouseEvent, input, pointerFlags, xPos, yPos);
271
272         return true;
273 }
274
275 static boolean input_recv_extended_mouse_event(rdpInput* input, STREAM* s)
276 {
277         uint16 pointerFlags, xPos, yPos;
278
279         if (stream_get_left(s) < 6)
280                 return false;
281
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) */
285
286         IFCALL(input->ExtendedMouseEvent, input, pointerFlags, xPos, yPos);
287
288         return true;
289 }
290
291 static boolean input_recv_event(rdpInput* input, STREAM* s)
292 {
293         uint16 messageType;
294
295         if (stream_get_left(s) < 4)
296                 return false;
297
298         stream_seek(s, 4); /* eventTime (4 bytes), ignored by the server */
299         stream_read_uint16(s, messageType); /* messageType (2 bytes) */
300
301         switch (messageType)
302         {
303                 case INPUT_EVENT_SYNC:
304                         if (!input_recv_sync_event(input, s))
305                                 return false;
306                         break;
307
308                 case INPUT_EVENT_SCANCODE:
309                         if (!input_recv_keyboard_event(input, s))
310                                 return false;
311                         break;
312
313                 case INPUT_EVENT_UNICODE:
314                         if (!input_recv_unicode_keyboard_event(input, s))
315                                 return false;
316                         break;
317
318                 case INPUT_EVENT_MOUSE:
319                         if (!input_recv_mouse_event(input, s))
320                                 return false;
321                         break;
322
323                 case INPUT_EVENT_MOUSEX:
324                         if (!input_recv_extended_mouse_event(input, s))
325                                 return false;
326                         break;
327
328                 default:
329                         printf("Unknown messageType %u\n", messageType);
330                         /* Each input event uses 6 bytes. */
331                         stream_seek(s, 6);
332                         break;
333         }
334
335         return true;
336 }
337
338 boolean input_recv(rdpInput* input, STREAM* s)
339 {
340         uint16 i, numberEvents;
341
342         if (stream_get_left(s) < 4)
343                 return false;
344
345         stream_read_uint16(s, numberEvents); /* numberEvents (2 bytes) */
346         stream_seek(s, 2); /* pad2Octets (2 bytes) */
347
348         /* Each input event uses 6 exactly bytes. */
349         if (stream_get_left(s) < 6 * numberEvents)
350                 return false;
351
352         for (i = 0; i < numberEvents; i++)
353         {
354                 if (!input_recv_event(input, s))
355                         return false;
356         }
357
358         return true;
359 }
360
361 void input_register_client_callbacks(rdpInput* input)
362 {
363         rdpRdp* rdp = input->context->rdp;
364
365         if (rdp->settings->fastpath_input)
366         {
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;
372         }
373         else
374         {
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;
380         }
381 }
382
383 rdpInput* input_new(rdpRdp* rdp)
384 {
385         rdpInput* input;
386
387         input = (rdpInput*) xzalloc(sizeof(rdpInput));
388
389         if (input != NULL)
390         {
391
392         }
393
394         return input;
395 }
396
397 void input_free(rdpInput* input)
398 {
399         if (input != NULL)
400         {
401                 xfree(input);
402         }
403 }