FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
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