FreeRDP
Loading...
Searching...
No Matches
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)sendUnicodeKey:(NSInteger)character up:(BOOL)up;
16- (void)handleSpecialKey:(NSInteger)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, altGrPressed = _altgr_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(_virtual_key_shift_map, 0, sizeof(_virtual_key_shift_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 // some server does not accept unicode key event
75 // so, send physical key combinations
76 _virtual_key_map[' '] = VK_SPACE;
77 _virtual_key_map['`'] = _virtual_key_map['~'] = VK_OEM_3;
78 _virtual_key_map['-'] = _virtual_key_map['_'] = VK_OEM_MINUS;
79 _virtual_key_map['='] = _virtual_key_map['+'] = VK_OEM_PLUS;
80 _virtual_key_map['['] = _virtual_key_map['{'] = VK_OEM_4;
81 _virtual_key_map[']'] = _virtual_key_map['}'] = VK_OEM_6;
82 _virtual_key_map['\\'] = _virtual_key_map['|'] = VK_OEM_5;
83 _virtual_key_map[';'] = _virtual_key_map[':'] = VK_OEM_1;
84 _virtual_key_map['\''] = _virtual_key_map['\"'] = VK_OEM_7;
85 _virtual_key_map[','] = _virtual_key_map['<'] = VK_OEM_COMMA;
86 _virtual_key_map['.'] = _virtual_key_map['>'] = VK_OEM_PERIOD;
87 _virtual_key_map['/'] = _virtual_key_map['?'] = VK_OEM_2;
88
89 const char *shifted = "~_+{}|:\"<>?!@#$%^&*()";
90 for (const char *p = shifted; *p != '\0'; p++)
91 _virtual_key_shift_map[(unsigned char)*p] = YES;
92
93 _virtual_key_map['!'] = VK_KEY_1;
94 _virtual_key_map['@'] = VK_KEY_2;
95 _virtual_key_map['#'] = VK_KEY_3;
96 _virtual_key_map['] = VK_KEY_4;
97 _virtual_key_map['%'] = VK_KEY_5;
98 _virtual_key_map['^'] = VK_KEY_6;
99 _virtual_key_map['&'] = VK_KEY_7;
100 _virtual_key_map['*'] = VK_KEY_8;
101 _virtual_key_map['('] = VK_KEY_9;
102 _virtual_key_map[')'] = VK_KEY_0;
103 }
104 return self;
105}
106
107- (void)dealloc
108{
109 [super dealloc];
110}
111
112#pragma mark -
113#pragma mark class methods
114
115// return a keyboard instance
116+ (RDPKeyboard *)getSharedRDPKeyboard
117{
118 static RDPKeyboard *_shared_keyboard = nil;
119
120 if (_shared_keyboard == nil)
121 {
122 @synchronized(self)
123 {
124 if (_shared_keyboard == nil)
125 _shared_keyboard = [[RDPKeyboard alloc] init];
126 }
127 }
128
129 return _shared_keyboard;
130}
131
132// reset the keyboard instance and assign the given rdp instance
133- (void)initWithSession:(RDPSession *)session delegate:(NSObject<RDPKeyboardDelegate> *)delegate
134{
135 _alt_pressed = NO;
136 _ctrl_pressed = NO;
137 _shift_pressed = NO;
138 _win_pressed = NO;
139 _altgr_pressed = NO;
140
141 _session = session;
142 _delegate = delegate;
143}
144
145- (void)reset
146{
147 // reset pressed ctrl, alt, alt gr, shift or win key
148 if (_shift_pressed)
149 [self toggleShiftKey];
150 if (_alt_pressed)
151 [self toggleAltKey];
152 if (_ctrl_pressed)
153 [self toggleCtrlKey];
154 if (_win_pressed)
155 [self toggleWinKey];
156 if (_altgr_pressed)
157 [self toggleAltGrKey];
158}
159
160// handles button pressed input event from the iOS keyboard
161// performs all conversions etc.
162- (void)sendUnicode:(NSInteger)character
163{
164 if ((character >= 0) && (character < 256) && isalnum((unsigned char)character))
165 [self handleAlphaNumChar:(int)character];
166 else
167 [self handleSpecialKey:character];
168
169 [self reset];
170}
171
172// send a key press and release modifier key
173- (void)sendVirtualKeyCode:(NSInteger)keyCode
174{
175 [self sendVirtualKey:keyCode up:NO];
176 [self sendVirtualKey:keyCode up:YES];
177
178 // release modifier key
179 [self reset];
180}
181
182// sends the vk code to the session
183- (void)sendVirtualKey:(NSInteger)vKey up:(BOOL)up
184{
185 const DWORD dvKey = WINPR_ASSERTING_INT_CAST(DWORD, vKey);
186 DWORD scancode = GetVirtualScanCodeFromVirtualKeyCode(dvKey, 4);
187 int flags = (up ? KBD_FLAGS_RELEASE : KBD_FLAGS_DOWN);
188 flags |= ((scancode & KBDEXT) ? KBD_FLAGS_EXTENDED : 0);
189 [_session
190 sendInputEvent:[NSDictionary
191 dictionaryWithObjectsAndKeys:@"keyboard", @"type", @"scancode",
192 @"subtype",
193 [NSNumber numberWithUnsignedShort:flags],
194 @"flags",
195 [NSNumber
196 numberWithUnsignedShort:(scancode &
197 0xFF)],
198 @"scancode", nil]];
199}
200
201#pragma mark modifier key handling
202// toggle ctrl key, returns true if pressed, otherwise false
203- (void)toggleCtrlKey
204{
205 [self sendVirtualKey:VK_LCONTROL up:_ctrl_pressed];
206 _ctrl_pressed = !_ctrl_pressed;
207 [self notifyDelegateModifiersChanged];
208}
209
210// toggle alt key, returns true if pressed, otherwise false
211- (void)toggleAltKey
212{
213 [self sendVirtualKey:VK_LMENU up:_alt_pressed];
214 _alt_pressed = !_alt_pressed;
215 [self notifyDelegateModifiersChanged];
216}
217
218// toggle shift key, returns true if pressed, otherwise false
219- (void)toggleShiftKey
220{
221 [self sendVirtualKey:VK_LSHIFT up:_shift_pressed];
222 _shift_pressed = !_shift_pressed;
223 [self notifyDelegateModifiersChanged];
224}
225
226// toggle windows key, returns true if pressed, otherwise false
227- (void)toggleWinKey
228{
229 [self sendVirtualKey:(VK_LWIN | KBDEXT) up:_win_pressed];
230 _win_pressed = !_win_pressed;
231 [self notifyDelegateModifiersChanged];
232}
233
234// toggle alt gr (RightAlt) key, returns true if pressed, otherwise false
235- (void)toggleAltGrKey
236{
237 [self sendVirtualKey:(VK_RMENU | KBDEXT) up:_altgr_pressed];
238 _altgr_pressed = !_altgr_pressed;
239 [self notifyDelegateModifiersChanged];
240}
241
242#pragma mark Sending special key strokes
243
244- (void)sendEnterKeyStroke
245{
246 [self sendVirtualKeyCode:(VK_RETURN | KBDEXT)];
247}
248
249- (void)sendEscapeKeyStroke
250{
251 [self sendVirtualKeyCode:VK_ESCAPE];
252}
253
254- (void)sendBackspaceKeyStroke
255{
256 [self sendVirtualKeyCode:VK_BACK];
257}
258
259- (void)sendDeleteKeyStroke
260{
261 [self sendVirtualKeyCode:(VK_DELETE | KBDEXT)];
262}
263
264- (void)sendTabKeyStroke
265{
266 [self sendVirtualKeyCode:VK_TAB];
267}
268
269@end
270
271#pragma mark -
272@implementation RDPKeyboard (Private)
273
274- (void)handleAlphaNumChar:(int)character
275{
276 // if we receive an uppercase letter - make it lower and send an shift down event to server
277 BOOL shift_was_sent = NO;
278 if (isupper(character) && _shift_pressed == NO)
279 {
280 character = tolower(character);
281 [self sendVirtualKey:VK_LSHIFT up:NO];
282 shift_was_sent = YES;
283 }
284
285 // convert the character to a VK
286 int vk = _virtual_key_map[character];
287 if (vk != 0)
288 {
289 // send key pressed
290 [self sendVirtualKey:vk up:NO];
291 [self sendVirtualKey:vk up:YES];
292 }
293
294 // send the missing shift up if we had a shift down
295 if (shift_was_sent)
296 [self sendVirtualKey:VK_LSHIFT up:YES];
297}
298
299- (void)handleSpecialKey:(NSInteger)character
300{
301 if ((character >= 0) && (character < 256) && (_virtual_key_map[character] != 0))
302 {
303 BOOL shift_was_sent = NO;
304 if (_virtual_key_shift_map[character] && !_shift_pressed)
305 {
306 [self sendVirtualKey:VK_LSHIFT up:NO];
307 shift_was_sent = YES;
308 }
309
310 [self sendVirtualKey:_virtual_key_map[character] up:NO];
311 [self sendVirtualKey:_virtual_key_map[character] up:YES];
312
313 if (shift_was_sent)
314 [self sendVirtualKey:VK_LSHIFT up:YES];
315 return;
316 }
317
318 // Fall back for characters that have no US keyboard scancode representation.
319 [self sendUnicodeKey:character up:NO];
320 [self sendUnicodeKey:character up:YES];
321}
322
323- (void)sendUnicodeKey:(NSInteger)character up:(BOOL)up
324{
325 const UINT16 ucharacter = WINPR_ASSERTING_INT_CAST(UINT16, character);
326 [_session
327 sendInputEvent:[NSDictionary
328 dictionaryWithObjectsAndKeys:
329 @"keyboard", @"type", @"unicode", @"subtype",
330 [NSNumber numberWithUnsignedShort:(up ? KBD_FLAGS_RELEASE : 0)],
331 @"flags", [NSNumber numberWithUnsignedShort:ucharacter],
332 @"unicode_char", nil]];
333}
334
335- (void)notifyDelegateModifiersChanged
336{
337 if ([[self delegate] respondsToSelector:@selector(modifiersChangedForKeyboard:)])
338 [[self delegate] modifiersChangedForKeyboard:self];
339}
340
341@end