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;
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
140 _session = session;
141 _delegate = delegate;
142}
143
144- (void)reset
145{
146 // reset pressed ctrl, alt, shift or win key
147 if (_shift_pressed)
148 [self toggleShiftKey];
149 if (_alt_pressed)
150 [self toggleAltKey];
151 if (_ctrl_pressed)
152 [self toggleCtrlKey];
153 if (_win_pressed)
154 [self toggleWinKey];
155}
156
157// handles button pressed input event from the iOS keyboard
158// performs all conversions etc.
159- (void)sendUnicode:(NSInteger)character
160{
161 if ((character >= 0) && (character < 256) && isalnum((unsigned char)character))
162 [self handleAlphaNumChar:(int)character];
163 else
164 [self handleSpecialKey:character];
165
166 [self reset];
167}
168
169// send a backspace key press
170- (void)sendVirtualKeyCode:(NSInteger)keyCode
171{
172 [self sendVirtualKey:keyCode up:NO];
173 [self sendVirtualKey:keyCode up:YES];
174}
175
176// sends the vk code to the session
177- (void)sendVirtualKey:(NSInteger)vKey up:(BOOL)up
178{
179 const DWORD dvKey = WINPR_ASSERTING_INT_CAST(DWORD, vKey);
180 DWORD scancode = GetVirtualScanCodeFromVirtualKeyCode(dvKey, 4);
181 int flags = (up ? KBD_FLAGS_RELEASE : KBD_FLAGS_DOWN);
182 flags |= ((scancode & KBDEXT) ? KBD_FLAGS_EXTENDED : 0);
183 [_session
184 sendInputEvent:[NSDictionary
185 dictionaryWithObjectsAndKeys:@"keyboard", @"type", @"scancode",
186 @"subtype",
187 [NSNumber numberWithUnsignedShort:flags],
188 @"flags",
189 [NSNumber
190 numberWithUnsignedShort:(scancode &
191 0xFF)],
192 @"scancode", nil]];
193}
194
195#pragma mark modifier key handling
196// toggle ctrl key, returns true if pressed, otherwise false
197- (void)toggleCtrlKey
198{
199 [self sendVirtualKey:VK_LCONTROL up:_ctrl_pressed];
200 _ctrl_pressed = !_ctrl_pressed;
201 [self notifyDelegateModifiersChanged];
202}
203
204// toggle alt key, returns true if pressed, otherwise false
205- (void)toggleAltKey
206{
207 [self sendVirtualKey:VK_LMENU up:_alt_pressed];
208 _alt_pressed = !_alt_pressed;
209 [self notifyDelegateModifiersChanged];
210}
211
212// toggle shift key, returns true if pressed, otherwise false
213- (void)toggleShiftKey
214{
215 [self sendVirtualKey:VK_LSHIFT up:_shift_pressed];
216 _shift_pressed = !_shift_pressed;
217 [self notifyDelegateModifiersChanged];
218}
219
220// toggle windows key, returns true if pressed, otherwise false
221- (void)toggleWinKey
222{
223 [self sendVirtualKey:(VK_LWIN | KBDEXT) up:_win_pressed];
224 _win_pressed = !_win_pressed;
225 [self notifyDelegateModifiersChanged];
226}
227
228#pragma mark Sending special key strokes
229
230- (void)sendEnterKeyStroke
231{
232 [self sendVirtualKeyCode:(VK_RETURN | KBDEXT)];
233}
234
235- (void)sendEscapeKeyStroke
236{
237 [self sendVirtualKeyCode:VK_ESCAPE];
238}
239
240- (void)sendBackspaceKeyStroke
241{
242 [self sendVirtualKeyCode:VK_BACK];
243}
244
245@end
246
247#pragma mark -
248@implementation RDPKeyboard (Private)
249
250- (void)handleAlphaNumChar:(int)character
251{
252 // if we receive an uppercase letter - make it lower and send an shift down event to server
253 BOOL shift_was_sent = NO;
254 if (isupper(character) && _shift_pressed == NO)
255 {
256 character = tolower(character);
257 [self sendVirtualKey:VK_LSHIFT up:NO];
258 shift_was_sent = YES;
259 }
260
261 // convert the character to a VK
262 int vk = _virtual_key_map[character];
263 if (vk != 0)
264 {
265 // send key pressed
266 [self sendVirtualKey:vk up:NO];
267 [self sendVirtualKey:vk up:YES];
268 }
269
270 // send the missing shift up if we had a shift down
271 if (shift_was_sent)
272 [self sendVirtualKey:VK_LSHIFT up:YES];
273}
274
275- (void)handleSpecialKey:(NSInteger)character
276{
277 if ((character >= 0) && (character < 256) && (_virtual_key_map[character] != 0))
278 {
279 BOOL shift_was_sent = NO;
280 if (_virtual_key_shift_map[character] && !_shift_pressed)
281 {
282 [self sendVirtualKey:VK_LSHIFT up:NO];
283 shift_was_sent = YES;
284 }
285
286 [self sendVirtualKey:_virtual_key_map[character] up:NO];
287 [self sendVirtualKey:_virtual_key_map[character] up:YES];
288
289 if (shift_was_sent)
290 [self sendVirtualKey:VK_LSHIFT up:YES];
291 return;
292 }
293
294 // Fall back for characters that have no US keyboard scancode representation.
295 [self sendUnicodeKey:character up:NO];
296 [self sendUnicodeKey:character up:YES];
297}
298
299- (void)sendUnicodeKey:(NSInteger)character up:(BOOL)up
300{
301 const UINT16 ucharacter = WINPR_ASSERTING_INT_CAST(UINT16, character);
302 [_session
303 sendInputEvent:[NSDictionary
304 dictionaryWithObjectsAndKeys:
305 @"keyboard", @"type", @"unicode", @"subtype",
306 [NSNumber numberWithUnsignedShort:(up ? KBD_FLAGS_RELEASE : 0)],
307 @"flags", [NSNumber numberWithUnsignedShort:ucharacter],
308 @"unicode_char", nil]];
309}
310
311- (void)notifyDelegateModifiersChanged
312{
313 if ([[self delegate] respondsToSelector:@selector(modifiersChangedForKeyboard:)])
314 [[self delegate] modifiersChangedForKeyboard:self];
315}
316
317@end