FreeRDP
Loading...
Searching...
No Matches
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#include "ios_cliprdr.h"
15
16#pragma mark -
17#pragma mark Sending compacted input events (from main thread)
18
19// While this function may be called from any thread that has an autorelease pool allocated, it is
20// not threadsafe: caller is responsible for synchronization
21BOOL ios_events_send(mfInfo *mfi, NSDictionary *event_description)
22{
23 NSError *error = nil;
24 NSData *encoded_description = [NSKeyedArchiver archivedDataWithRootObject:event_description
25 requiringSecureCoding:YES
26 error:&error];
27
28 if (!encoded_description)
29 {
30 NSLog(@"%s: Failed to archive event (type: %@): %@", __func__,
31 [event_description objectForKey:@"type"], error);
32 return FALSE;
33 }
34
35 WINPR_ASSERT(mfi);
36
37 if ([encoded_description length] > 32000 || (mfi->event_pipe_producer == -1))
38 return FALSE;
39
40 uint32_t archived_data_len = (uint32_t)[encoded_description length];
41
42 // NSLog(@"writing %d bytes to input event pipe", archived_data_len);
43
44 if (write(mfi->event_pipe_producer, &archived_data_len, 4) == -1)
45 {
46 NSLog(@"%s: Failed to write length descriptor to pipe.", __func__);
47 return FALSE;
48 }
49
50 if (write(mfi->event_pipe_producer, [encoded_description bytes], archived_data_len) == -1)
51 {
52 NSLog(@"%s: Failed to write %d bytes into the event queue (event type: %@).", __func__,
53 (int)[encoded_description length], [event_description objectForKey:@"type"]);
54 return FALSE;
55 }
56
57 return TRUE;
58}
59
60#pragma mark -
61#pragma mark Processing compacted input events (from connection thread runloop)
62
63static BOOL ios_events_handle_event(mfInfo *mfi, NSDictionary *event_description)
64{
65 NSString *event_type = [event_description objectForKey:@"type"];
66 BOOL should_continue = TRUE;
67 rdpInput *input;
68
69 WINPR_ASSERT(mfi);
70
71 freerdp *instance = mfi->instance;
72 WINPR_ASSERT(instance);
73 WINPR_ASSERT(instance->context);
74
75 input = instance->context->input;
76 WINPR_ASSERT(input);
77
78 if ([event_type isEqualToString:@"mouse"])
79 {
80 if (!input->MouseEvent(input,
81 [[event_description objectForKey:@"flags"] unsignedShortValue],
82 [[event_description objectForKey:@"coord_x"] unsignedShortValue],
83 [[event_description objectForKey:@"coord_y"] unsignedShortValue]))
84 {
85 // Returning an error here can terminate the connection.
86 NSLog(@"%s: MouseEvent failed.", __func__);
87 }
88 }
89 else if ([event_type isEqualToString:@"keyboard"])
90 {
91 if ([[event_description objectForKey:@"subtype"] isEqualToString:@"scancode"])
92 freerdp_input_send_keyboard_event(
93 input, [[event_description objectForKey:@"flags"] unsignedShortValue],
94 [[event_description objectForKey:@"scancode"] unsignedShortValue]);
95 else if ([[event_description objectForKey:@"subtype"] isEqualToString:@"unicode"])
96 freerdp_input_send_unicode_keyboard_event(
97 input, [[event_description objectForKey:@"flags"] unsignedShortValue],
98 [[event_description objectForKey:@"unicode_char"] unsignedShortValue]);
99 else
100 NSLog(@"%s: doesn't know how to send keyboard input with subtype %@", __func__,
101 [event_description objectForKey:@"subtype"]);
102 }
103 else if ([event_type isEqualToString:@"clipboard"])
104 {
105 mfContext *afc = mfi->context;
106 afc->clipboardHasText = [[event_description objectForKey:@"has_text"] boolValue];
107
108 // before the channel is ready the monitor ready handler sends the list instead
109 if (afc->cliprdr && afc->clipboardSync &&
110 (ios_cliprdr_send_client_format_list(afc->cliprdr) != CHANNEL_RC_OK))
111 NSLog(@"%s: failed to send the clipboard format list.", __func__);
112 }
113 else if ([event_type isEqualToString:@"disconnect"])
114 should_continue = FALSE;
115 else
116 NSLog(@"%s: unrecognized event type: %@", __func__, event_type);
117
118 return should_continue;
119}
120
121BOOL ios_events_check_handle(mfInfo *mfi)
122{
123 WINPR_ASSERT(mfi);
124
125 if (WaitForSingleObject(mfi->handle, 0) != WAIT_OBJECT_0)
126 return TRUE;
127
128 if (mfi->event_pipe_consumer == -1)
129 return TRUE;
130
131 uint32_t archived_data_length = 0;
132 ssize_t bytes_read;
133
134 // First, read the length of the blob
135 bytes_read = read(mfi->event_pipe_consumer, &archived_data_length, 4);
136
137 if (bytes_read == -1 || archived_data_length < 1 || archived_data_length > 32000)
138 {
139 NSLog(@"%s: just read length descriptor. bytes_read=%ld, archived_data_length=%u", __func__,
140 bytes_read, archived_data_length);
141 return FALSE;
142 }
143
144 // NSLog(@"reading %d bytes from input event pipe", archived_data_length);
145
146 NSMutableData *archived_object_data =
147 [[NSMutableData alloc] initWithLength:archived_data_length];
148 bytes_read =
149 read(mfi->event_pipe_consumer, [archived_object_data mutableBytes], archived_data_length);
150
151 if (bytes_read != archived_data_length)
152 {
153 NSLog(@"%s: attempted to read data; read %ld bytes but wanted %d bytes.", __func__,
154 bytes_read, archived_data_length);
155 [archived_object_data release];
156 return FALSE;
157 }
158
159 NSError *error = nil;
160 NSDictionary *unarchived_object_data = [NSKeyedUnarchiver
161 unarchivedObjectOfClasses:[NSSet setWithObjects:[NSDictionary class], [NSString class],
162 [NSNumber class], nil]
163 fromData:archived_object_data
164 error:&error];
165 [archived_object_data release];
166
167 if (!unarchived_object_data)
168 {
169 // just return TRUE and ignore data. (if return FALSE, sesison can be terminated)
170 NSLog(@"%s: Failed to unarchive input event: %@", __func__, error);
171 return TRUE;
172 }
173
174 return ios_events_handle_event(mfi, unarchived_object_data);
175}
176
177HANDLE ios_events_get_handle(mfInfo *mfi)
178{
179 WINPR_ASSERT(mfi);
180 return mfi->handle;
181}
182
183// Sets up the event pipe
184BOOL ios_events_create_pipe(mfInfo *mfi)
185{
186 int pipe_fds[2];
187
188 WINPR_ASSERT(mfi);
189
190 if (pipe(pipe_fds) == -1)
191 {
192 NSLog(@"%s: pipe failed.", __func__);
193 return FALSE;
194 }
195
196 mfi->event_pipe_consumer = pipe_fds[0];
197 mfi->event_pipe_producer = pipe_fds[1];
198 mfi->handle = CreateFileDescriptorEvent(nullptr, FALSE, FALSE, mfi->event_pipe_consumer,
199 WINPR_FD_READ | WINPR_FD_WRITE);
200 return TRUE;
201}
202
203void ios_events_free_pipe(mfInfo *mfi)
204{
205 WINPR_ASSERT(mfi);
206 int consumer_fd = mfi->event_pipe_consumer, producer_fd = mfi->event_pipe_producer;
207
208 mfi->event_pipe_consumer = mfi->event_pipe_producer = -1;
209 close(producer_fd);
210 close(consumer_fd);
211 (void)CloseHandle(mfi->handle);
212}