FreeRDP
RDPKeyboard.m
1 /*
2  RDP Keyboard helper
3 
4  Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz
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 #import "RDPKeyboard.h"
12 #include <freerdp/locale/keyboard.h>
13 
14 @interface RDPKeyboard (Private)
15 - (void)sendVirtualKey:(int)vKey up:(BOOL)up;
16 - (void)handleSpecialKey:(int)character;
17 - (void)handleAlphaNumChar:(int)character;
18 - (void)notifyDelegateModifiersChanged;
19 @end
20 
21 @implementation RDPKeyboard
22 
23 @synthesize delegate = _delegate, ctrlPressed = _ctrl_pressed, altPressed = _alt_pressed,
24  shiftPressed = _shift_pressed, winPressed = _win_pressed;
25 
26 - (id)init
27 {
28  if ((self = [super init]) != nil)
29  {
30  [self initWithSession:nil delegate:nil];
31 
32  memset(_virtual_key_map, 0, sizeof(_virtual_key_map));
33  memset(_unicode_map, 0, sizeof(_unicode_map));
34 
35  // init vkey map - used for alpha-num characters
36  _virtual_key_map['0'] = VK_KEY_0;
37  _virtual_key_map['1'] = VK_KEY_1;
38  _virtual_key_map['2'] = VK_KEY_2;
39  _virtual_key_map['3'] = VK_KEY_3;
40  _virtual_key_map['4'] = VK_KEY_4;
41  _virtual_key_map['5'] = VK_KEY_5;
42  _virtual_key_map['6'] = VK_KEY_6;
43  _virtual_key_map['7'] = VK_KEY_7;
44  _virtual_key_map['8'] = VK_KEY_8;
45  _virtual_key_map['9'] = VK_KEY_9;
46 
47  _virtual_key_map['a'] = VK_KEY_A;
48  _virtual_key_map['b'] = VK_KEY_B;
49  _virtual_key_map['c'] = VK_KEY_C;
50  _virtual_key_map['d'] = VK_KEY_D;
51  _virtual_key_map['e'] = VK_KEY_E;
52  _virtual_key_map['f'] = VK_KEY_F;
53  _virtual_key_map['g'] = VK_KEY_G;
54  _virtual_key_map['h'] = VK_KEY_H;
55  _virtual_key_map['i'] = VK_KEY_I;
56  _virtual_key_map['j'] = VK_KEY_J;
57  _virtual_key_map['k'] = VK_KEY_K;
58  _virtual_key_map['l'] = VK_KEY_L;
59  _virtual_key_map['m'] = VK_KEY_M;
60  _virtual_key_map['n'] = VK_KEY_N;
61  _virtual_key_map['o'] = VK_KEY_O;
62  _virtual_key_map['p'] = VK_KEY_P;
63  _virtual_key_map['q'] = VK_KEY_Q;
64  _virtual_key_map['r'] = VK_KEY_R;
65  _virtual_key_map['s'] = VK_KEY_S;
66  _virtual_key_map['t'] = VK_KEY_T;
67  _virtual_key_map['u'] = VK_KEY_U;
68  _virtual_key_map['v'] = VK_KEY_V;
69  _virtual_key_map['w'] = VK_KEY_W;
70  _virtual_key_map['x'] = VK_KEY_X;
71  _virtual_key_map['y'] = VK_KEY_Y;
72  _virtual_key_map['z'] = VK_KEY_Z;
73 
74  // init scancode map - used for special characters
75  _unicode_map['-'] = 45;
76  _unicode_map['/'] = 47;
77  _unicode_map[':'] = 58;
78  _unicode_map[';'] = 59;
79  _unicode_map['('] = 40;
80  _unicode_map[')'] = 41;
81  _unicode_map['&'] = 38;
82  _unicode_map['@'] = 64;
83  _unicode_map['.'] = 46;
84  _unicode_map[','] = 44;
85  _unicode_map['?'] = 63;
86  _unicode_map['!'] = 33;
87  _unicode_map['\''] = 39;
88  _unicode_map['\"'] = 34;
89 
90  _unicode_map['['] = 91;
91  _unicode_map[']'] = 93;
92  _unicode_map['{'] = 123;
93  _unicode_map['}'] = 125;
94  _unicode_map['#'] = 35;
95  _unicode_map['%'] = 37;
96  _unicode_map['^'] = 94;
97  _unicode_map['*'] = 42;
98  _unicode_map['+'] = 43;
99  _unicode_map['='] = 61;
100 
101  _unicode_map['_'] = 95;
102  _unicode_map['\\'] = 92;
103  _unicode_map['|'] = 124;
104  _unicode_map['~'] = 126;
105  _unicode_map['<'] = 60;
106  _unicode_map['>'] = 62;
107  _unicode_map['] = 36;
108  }
109  return self;
110 }
111 
112 - (void)dealloc
113 {
114  [super dealloc];
115 }
116 
117 #pragma mark -
118 #pragma mark class methods
119 
120 // return a keyboard instance
121 + (RDPKeyboard *)getSharedRDPKeyboard
122 {
123  static RDPKeyboard *_shared_keyboard = nil;
124 
125  if (_shared_keyboard == nil)
126  {
127  @synchronized(self)
128  {
129  if (_shared_keyboard == nil)
130  _shared_keyboard = [[RDPKeyboard alloc] init];
131  }
132  }
133 
134  return _shared_keyboard;
135 }
136 
137 // reset the keyboard instance and assign the given rdp instance
138 - (void)initWithSession:(RDPSession *)session delegate:(NSObject<RDPKeyboardDelegate> *)delegate
139 {
140  _alt_pressed = NO;
141  _ctrl_pressed = NO;
142  _shift_pressed = NO;
143  _win_pressed = NO;
144 
145  _session = session;
146  _delegate = delegate;
147 }
148 
149 - (void)reset
150 {
151  // reset pressed ctrl, alt, shift or win key
152  if (_shift_pressed)
153  [self toggleShiftKey];
154  if (_alt_pressed)
155  [self toggleAltKey];
156  if (_ctrl_pressed)
157  [self toggleCtrlKey];
158  if (_win_pressed)
159  [self toggleWinKey];
160 }
161 
162 // handles button pressed input event from the iOS keyboard
163 // performs all conversions etc.
164 - (void)sendUnicode:(int)character
165 {
166  if (isalnum(character))
167  [self handleAlphaNumChar:character];
168  else
169  [self handleSpecialKey:character];
170 
171  [self reset];
172 }
173 
174 // send a backspace key press
175 - (void)sendVirtualKeyCode:(int)keyCode
176 {
177  [self sendVirtualKey:keyCode up:NO];
178  [self sendVirtualKey:keyCode up:YES];
179 }
180 
181 #pragma mark modifier key handling
182 // toggle ctrl key, returns true if pressed, otherwise false
183 - (void)toggleCtrlKey
184 {
185  [self sendVirtualKey:VK_LCONTROL up:_ctrl_pressed];
186  _ctrl_pressed = !_ctrl_pressed;
187  [self notifyDelegateModifiersChanged];
188 }
189 
190 // toggle alt key, returns true if pressed, otherwise false
191 - (void)toggleAltKey
192 {
193  [self sendVirtualKey:VK_LMENU up:_alt_pressed];
194  _alt_pressed = !_alt_pressed;
195  [self notifyDelegateModifiersChanged];
196 }
197 
198 // toggle shift key, returns true if pressed, otherwise false
199 - (void)toggleShiftKey
200 {
201  [self sendVirtualKey:VK_LSHIFT up:_shift_pressed];
202  _shift_pressed = !_shift_pressed;
203  [self notifyDelegateModifiersChanged];
204 }
205 
206 // toggle windows key, returns true if pressed, otherwise false
207 - (void)toggleWinKey
208 {
209  [self sendVirtualKey:(VK_LWIN | KBDEXT) up:_win_pressed];
210  _win_pressed = !_win_pressed;
211  [self notifyDelegateModifiersChanged];
212 }
213 
214 #pragma mark Sending special key strokes
215 
216 - (void)sendEnterKeyStroke
217 {
218  [self sendVirtualKeyCode:(VK_RETURN | KBDEXT)];
219 }
220 
221 - (void)sendEscapeKeyStroke
222 {
223  [self sendVirtualKeyCode:VK_ESCAPE];
224 }
225 
226 - (void)sendBackspaceKeyStroke
227 {
228  [self sendVirtualKeyCode:VK_BACK];
229 }
230 
231 @end
232 
233 #pragma mark -
234 @implementation RDPKeyboard (Private)
235 
236 - (void)handleAlphaNumChar:(int)character
237 {
238  // if we receive an uppercase letter - make it lower and send an shift down event to server
239  BOOL shift_was_sent = NO;
240  if (isupper(character) && _shift_pressed == NO)
241  {
242  character = tolower(character);
243  [self sendVirtualKey:VK_LSHIFT up:NO];
244  shift_was_sent = YES;
245  }
246 
247  // convert the character to a VK
248  int vk = _virtual_key_map[character];
249  if (vk != 0)
250  {
251  // send key pressed
252  [self sendVirtualKey:vk up:NO];
253  [self sendVirtualKey:vk up:YES];
254  }
255 
256  // send the missing shift up if we had a shift down
257  if (shift_was_sent)
258  [self sendVirtualKey:VK_LSHIFT up:YES];
259 }
260 
261 - (void)handleSpecialKey:(int)character
262 {
263  NSDictionary *eventDescriptor = nil;
264  if (character < 256)
265  {
266  // convert the character to a unicode character
267  int code = _unicode_map[character];
268  if (code != 0)
269  eventDescriptor = [NSDictionary
270  dictionaryWithObjectsAndKeys:@"keyboard", @"type", @"unicode", @"subtype",
271  [NSNumber numberWithUnsignedShort:0], @"flags",
272  [NSNumber numberWithUnsignedShort:code],
273  @"unicode_char", nil];
274  }
275 
276  if (eventDescriptor == nil)
277  eventDescriptor = [NSDictionary
278  dictionaryWithObjectsAndKeys:@"keyboard", @"type", @"unicode", @"subtype",
279  [NSNumber numberWithUnsignedShort:0], @"flags",
280  [NSNumber numberWithUnsignedShort:character],
281  @"unicode_char", nil];
282 
283  [_session sendInputEvent:eventDescriptor];
284 }
285 
286 // sends the vk code to the session
287 - (void)sendVirtualKey:(int)vKey up:(BOOL)up
288 {
289  DWORD scancode = GetVirtualScanCodeFromVirtualKeyCode(vKey, 4);
290  int flags = (up ? KBD_FLAGS_RELEASE : KBD_FLAGS_DOWN);
291  flags |= ((scancode & KBDEXT) ? KBD_FLAGS_EXTENDED : 0);
292  [_session
293  sendInputEvent:[NSDictionary
294  dictionaryWithObjectsAndKeys:@"keyboard", @"type", @"scancode",
295  @"subtype",
296  [NSNumber numberWithUnsignedShort:flags],
297  @"flags",
298  [NSNumber
299  numberWithUnsignedShort:(scancode &
300  0xFF)],
301  @"scancode", nil]];
302 }
303 
304 - (void)notifyDelegateModifiersChanged
305 {
306  if ([[self delegate] respondsToSelector:@selector(modifiersChangedForKeyboard:)])
307  [[self delegate] modifiersChangedForKeyboard:self];
308 }
309 
310 @end