FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
ios_freerdp_events.m
1/*
2 RDP event queuing
3
4 Copyright 2013 Thincast Technologies GmbH, Author: Dorian Johnson
5
6 This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
7 If a copy of the MPL was not distributed with this file, You can obtain one at
8 http://mozilla.org/MPL/2.0/.
9 */
10
11#include <winpr/assert.h>
12
13#include "ios_freerdp_events.h"
14
15#pragma mark -
16#pragma mark Sending compacted input events (from main thread)
17
18// While this function may be called from any thread that has an autorelease pool allocated, it is
19// not threadsafe: caller is responsible for synchronization
20BOOL ios_events_send(mfInfo *mfi, NSDictionary *event_description)
21{
22 NSData *encoded_description = [NSKeyedArchiver archivedDataWithRootObject:event_description];
23
24 WINPR_ASSERT(mfi);
25
26 if ([encoded_description length] > 32000 || (mfi->event_pipe_producer == -1))
27 return FALSE;
28
29 uint32_t archived_data_len = (uint32_t)[encoded_description length];
30
31 // NSLog(@"writing %d bytes to input event pipe", archived_data_len);
32
33 if (write(mfi->event_pipe_producer, &archived_data_len, 4) == -1)
34 {
35 NSLog(@"%s: Failed to write length descriptor to pipe.", __func__);
36 return FALSE;
37 }
38
39 if (write(mfi->event_pipe_producer, [encoded_description bytes], archived_data_len) == -1)
40 {
41 NSLog(@"%s: Failed to write %d bytes into the event queue (event type: %@).", __func__,
42 (int)[encoded_description length], [event_description objectForKey:@"type"]);
43 return FALSE;
44 }
45
46 return TRUE;
47}
48
49#pragma mark -
50#pragma mark Processing compacted input events (from connection thread runloop)
51
52static BOOL ios_events_handle_event(mfInfo *mfi, NSDictionary *event_description)
53{
54 NSString *event_type = [event_description objectForKey:@"type"];
55 BOOL should_continue = TRUE;
56 rdpInput *input;
57
58 WINPR_ASSERT(mfi);
59
60 freerdp *instance = mfi->instance;
61 WINPR_ASSERT(instance);
62 WINPR_ASSERT(instance->context);
63
64 input = instance->context->input;
65 WINPR_ASSERT(input);
66
67 if ([event_type isEqualToString:@"mouse"])
68 {
69 input->MouseEvent(input, [[event_description objectForKey:@"flags"] unsignedShortValue],
70 [[event_description objectForKey:@"coord_x"] unsignedShortValue],
71 [[event_description objectForKey:@"coord_y"] unsignedShortValue]);
72 }
73 else if ([event_type isEqualToString:@"keyboard"])
74 {
75 if ([[event_description objectForKey:@"subtype"] isEqualToString:@"scancode"])
76 freerdp_input_send_keyboard_event(
77 input, [[event_description objectForKey:@"flags"] unsignedShortValue],
78 [[event_description objectForKey:@"scancode"] unsignedShortValue]);
79 else if ([[event_description objectForKey:@"subtype"] isEqualToString:@"unicode"])
80 freerdp_input_send_unicode_keyboard_event(
81 input, [[event_description objectForKey:@"flags"] unsignedShortValue],
82 [[event_description objectForKey:@"unicode_char"] unsignedShortValue]);
83 else
84 NSLog(@"%s: doesn't know how to send keyboard input with subtype %@", __func__,
85 [event_description objectForKey:@"subtype"]);
86 }
87 else if ([event_type isEqualToString:@"disconnect"])
88 should_continue = FALSE;
89 else
90 NSLog(@"%s: unrecognized event type: %@", __func__, event_type);
91
92 return should_continue;
93}
94
95BOOL ios_events_check_handle(mfInfo *mfi)
96{
97 WINPR_ASSERT(mfi);
98
99 if (WaitForSingleObject(mfi->handle, 0) != WAIT_OBJECT_0)
100 return TRUE;
101
102 if (mfi->event_pipe_consumer == -1)
103 return TRUE;
104
105 uint32_t archived_data_length = 0;
106 ssize_t bytes_read;
107
108 // First, read the length of the blob
109 bytes_read = read(mfi->event_pipe_consumer, &archived_data_length, 4);
110
111 if (bytes_read == -1 || archived_data_length < 1 || archived_data_length > 32000)
112 {
113 NSLog(@"%s: just read length descriptor. bytes_read=%ld, archived_data_length=%u", __func__,
114 bytes_read, archived_data_length);
115 return FALSE;
116 }
117
118 // NSLog(@"reading %d bytes from input event pipe", archived_data_length);
119
120 NSMutableData *archived_object_data =
121 [[NSMutableData alloc] initWithLength:archived_data_length];
122 bytes_read =
123 read(mfi->event_pipe_consumer, [archived_object_data mutableBytes], archived_data_length);
124
125 if (bytes_read != archived_data_length)
126 {
127 NSLog(@"%s: attempted to read data; read %ld bytes but wanted %d bytes.", __func__,
128 bytes_read, archived_data_length);
129 [archived_object_data release];
130 return FALSE;
131 }
132
133 id unarchived_object_data = [NSKeyedUnarchiver unarchiveObjectWithData:archived_object_data];
134 [archived_object_data release];
135
136 return ios_events_handle_event(mfi, unarchived_object_data);
137}
138
139HANDLE ios_events_get_handle(mfInfo *mfi)
140{
141 WINPR_ASSERT(mfi);
142 return mfi->handle;
143}
144
145// Sets up the event pipe
146BOOL ios_events_create_pipe(mfInfo *mfi)
147{
148 int pipe_fds[2];
149
150 WINPR_ASSERT(mfi);
151
152 if (pipe(pipe_fds) == -1)
153 {
154 NSLog(@"%s: pipe failed.", __func__);
155 return FALSE;
156 }
157
158 mfi->event_pipe_consumer = pipe_fds[0];
159 mfi->event_pipe_producer = pipe_fds[1];
160 mfi->handle = CreateFileDescriptorEvent(NULL, FALSE, FALSE, mfi->event_pipe_consumer,
161 WINPR_FD_READ | WINPR_FD_WRITE);
162 return TRUE;
163}
164
165void ios_events_free_pipe(mfInfo *mfi)
166{
167 WINPR_ASSERT(mfi);
168 int consumer_fd = mfi->event_pipe_consumer, producer_fd = mfi->event_pipe_producer;
169
170 mfi->event_pipe_consumer = mfi->event_pipe_producer = -1;
171 close(producer_fd);
172 close(consumer_fd);
173 (void)CloseHandle(mfi->handle);
174}