FreeRDP
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
20 BOOL 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 
52 static 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 
95 BOOL 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 
139 HANDLE ios_events_get_handle(mfInfo *mfi)
140 {
141  WINPR_ASSERT(mfi);
142  return mfi->handle;
143 }
144 
145 // Sets up the event pipe
146 BOOL 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 
165 void 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 }