Blame client/iOS/Models/RDPKeyboard.m

Packit 1fb8d4
/*
Packit 1fb8d4
 RDP Keyboard helper 
Packit 1fb8d4
 
Packit 1fb8d4
 Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz
Packit 1fb8d4
 
Packit 1fb8d4
 This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. 
Packit 1fb8d4
 If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#import "RDPKeyboard.h"
Packit 1fb8d4
#include <freerdp/locale/keyboard.h>
Packit 1fb8d4
Packit 1fb8d4
@interface RDPKeyboard (Private)
Packit 1fb8d4
- (void)sendVirtualKey:(int)vKey up:(BOOL)up;
Packit 1fb8d4
- (void)handleSpecialKey:(int)character;
Packit 1fb8d4
- (void)handleAlphaNumChar:(int)character;
Packit 1fb8d4
- (void)notifyDelegateModifiersChanged;
Packit 1fb8d4
@end
Packit 1fb8d4
Packit 1fb8d4
@implementation RDPKeyboard
Packit 1fb8d4
Packit 1fb8d4
@synthesize delegate = _delegate, ctrlPressed = _ctrl_pressed, altPressed = _alt_pressed, shiftPressed = _shift_pressed, winPressed = _win_pressed;
Packit 1fb8d4
Packit 1fb8d4
- (id)init
Packit 1fb8d4
{
Packit 1fb8d4
	if((self = [super init]) != nil)
Packit 1fb8d4
	{
Packit 1fb8d4
        [self initWithSession:nil delegate:nil];
Packit 1fb8d4
        
Packit 1fb8d4
		memset(_virtual_key_map, 0, sizeof(_virtual_key_map));
Packit 1fb8d4
        memset(_unicode_map, 0, sizeof(_unicode_map));
Packit 1fb8d4
		
Packit 1fb8d4
		// init vkey map - used for alpha-num characters
Packit 1fb8d4
		_virtual_key_map['0'] = VK_KEY_0;
Packit 1fb8d4
		_virtual_key_map['1'] = VK_KEY_1;
Packit 1fb8d4
		_virtual_key_map['2'] = VK_KEY_2;
Packit 1fb8d4
		_virtual_key_map['3'] = VK_KEY_3;
Packit 1fb8d4
		_virtual_key_map['4'] = VK_KEY_4;
Packit 1fb8d4
		_virtual_key_map['5'] = VK_KEY_5;
Packit 1fb8d4
		_virtual_key_map['6'] = VK_KEY_6;
Packit 1fb8d4
		_virtual_key_map['7'] = VK_KEY_7;
Packit 1fb8d4
		_virtual_key_map['8'] = VK_KEY_8;
Packit 1fb8d4
		_virtual_key_map['9'] = VK_KEY_9;
Packit 1fb8d4
		
Packit 1fb8d4
		_virtual_key_map['a'] = VK_KEY_A;
Packit 1fb8d4
		_virtual_key_map['b'] = VK_KEY_B;
Packit 1fb8d4
		_virtual_key_map['c'] = VK_KEY_C;
Packit 1fb8d4
		_virtual_key_map['d'] = VK_KEY_D;
Packit 1fb8d4
		_virtual_key_map['e'] = VK_KEY_E;
Packit 1fb8d4
		_virtual_key_map['f'] = VK_KEY_F;
Packit 1fb8d4
		_virtual_key_map['g'] = VK_KEY_G;
Packit 1fb8d4
		_virtual_key_map['h'] = VK_KEY_H;
Packit 1fb8d4
		_virtual_key_map['i'] = VK_KEY_I;
Packit 1fb8d4
		_virtual_key_map['j'] = VK_KEY_J;
Packit 1fb8d4
		_virtual_key_map['k'] = VK_KEY_K;
Packit 1fb8d4
		_virtual_key_map['l'] = VK_KEY_L;
Packit 1fb8d4
		_virtual_key_map['m'] = VK_KEY_M;
Packit 1fb8d4
		_virtual_key_map['n'] = VK_KEY_N;
Packit 1fb8d4
		_virtual_key_map['o'] = VK_KEY_O;
Packit 1fb8d4
		_virtual_key_map['p'] = VK_KEY_P;
Packit 1fb8d4
		_virtual_key_map['q'] = VK_KEY_Q;
Packit 1fb8d4
		_virtual_key_map['r'] = VK_KEY_R;
Packit 1fb8d4
		_virtual_key_map['s'] = VK_KEY_S;
Packit 1fb8d4
		_virtual_key_map['t'] = VK_KEY_T;
Packit 1fb8d4
		_virtual_key_map['u'] = VK_KEY_U;
Packit 1fb8d4
		_virtual_key_map['v'] = VK_KEY_V;
Packit 1fb8d4
		_virtual_key_map['w'] = VK_KEY_W;
Packit 1fb8d4
		_virtual_key_map['x'] = VK_KEY_X;
Packit 1fb8d4
		_virtual_key_map['y'] = VK_KEY_Y;
Packit 1fb8d4
		_virtual_key_map['z'] = VK_KEY_Z;
Packit 1fb8d4
        
Packit 1fb8d4
        // init scancode map - used for special characters
Packit 1fb8d4
        _unicode_map['-'] = 45;
Packit 1fb8d4
        _unicode_map['/'] = 47;
Packit 1fb8d4
        _unicode_map[':'] = 58;
Packit 1fb8d4
        _unicode_map[';'] = 59;
Packit 1fb8d4
        _unicode_map['('] = 40;
Packit 1fb8d4
        _unicode_map[')'] = 41;
Packit 1fb8d4
        _unicode_map['&'] = 38;
Packit 1fb8d4
        _unicode_map['@'] = 64;        
Packit 1fb8d4
        _unicode_map['.'] = 46;
Packit 1fb8d4
        _unicode_map[','] = 44;
Packit 1fb8d4
        _unicode_map['?'] = 63;
Packit 1fb8d4
        _unicode_map['!'] = 33;
Packit 1fb8d4
        _unicode_map['\''] = 39;
Packit 1fb8d4
        _unicode_map['\"'] = 34;
Packit 1fb8d4
		
Packit 1fb8d4
        _unicode_map['['] = 91;
Packit 1fb8d4
        _unicode_map[']'] = 93;        
Packit 1fb8d4
        _unicode_map['{'] = 123;
Packit 1fb8d4
        _unicode_map['}'] = 125;
Packit 1fb8d4
        _unicode_map['#'] = 35;
Packit 1fb8d4
        _unicode_map['%'] = 37;
Packit 1fb8d4
        _unicode_map['^'] = 94;
Packit 1fb8d4
        _unicode_map['*'] = 42;
Packit 1fb8d4
        _unicode_map['+'] = 43;
Packit 1fb8d4
        _unicode_map['='] = 61;
Packit 1fb8d4
Packit 1fb8d4
        _unicode_map['_'] = 95;
Packit 1fb8d4
        _unicode_map['\\'] = 92;
Packit 1fb8d4
        _unicode_map['|'] = 124;
Packit 1fb8d4
        _unicode_map['~'] = 126;
Packit 1fb8d4
        _unicode_map['<'] = 60;
Packit 1fb8d4
        _unicode_map['>'] = 62;
Packit 1fb8d4
        _unicode_map['$'] = 36;
Packit 1fb8d4
    }
Packit 1fb8d4
	return self;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
- (void)dealloc
Packit 1fb8d4
{
Packit 1fb8d4
	[super dealloc];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
#pragma mark -
Packit 1fb8d4
#pragma mark class methods
Packit 1fb8d4
Packit 1fb8d4
// return a keyboard instance
Packit 1fb8d4
+ (RDPKeyboard*)getSharedRDPKeyboard
Packit 1fb8d4
{
Packit 1fb8d4
	static RDPKeyboard* _shared_keyboard = nil;
Packit 1fb8d4
	
Packit 1fb8d4
	if (_shared_keyboard == nil)
Packit 1fb8d4
	{
Packit 1fb8d4
		@synchronized(self)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (_shared_keyboard == nil)
Packit 1fb8d4
				_shared_keyboard = [[RDPKeyboard alloc] init];		
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	
Packit 1fb8d4
	return _shared_keyboard;	
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
// reset the keyboard instance and assign the given rdp instance
Packit 1fb8d4
- (void)initWithSession:(RDPSession *)session delegate:(NSObject<RDPKeyboardDelegate> *)delegate
Packit 1fb8d4
{
Packit 1fb8d4
    _alt_pressed = NO;
Packit 1fb8d4
    _ctrl_pressed = NO;
Packit 1fb8d4
    _shift_pressed = NO;
Packit 1fb8d4
    _win_pressed = NO;
Packit 1fb8d4
    
Packit 1fb8d4
    _session = session;
Packit 1fb8d4
    _delegate = delegate;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
- (void)reset
Packit 1fb8d4
{
Packit 1fb8d4
    // reset pressed ctrl, alt, shift or win key
Packit 1fb8d4
    if(_shift_pressed)
Packit 1fb8d4
        [self toggleShiftKey];
Packit 1fb8d4
    if(_alt_pressed)
Packit 1fb8d4
        [self toggleAltKey];
Packit 1fb8d4
    if(_ctrl_pressed)
Packit 1fb8d4
        [self toggleCtrlKey];
Packit 1fb8d4
    if(_win_pressed)
Packit 1fb8d4
        [self toggleWinKey];        
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
// handles button pressed input event from the iOS keyboard
Packit 1fb8d4
// performs all conversions etc.
Packit 1fb8d4
- (void)sendUnicode:(int)character
Packit 1fb8d4
{   
Packit 1fb8d4
    if(isalnum(character))
Packit 1fb8d4
        [self handleAlphaNumChar:character];
Packit 1fb8d4
    else
Packit 1fb8d4
        [self handleSpecialKey:character];
Packit 1fb8d4
Packit 1fb8d4
    [self reset];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
// send a backspace key press
Packit 1fb8d4
- (void)sendVirtualKeyCode:(int)keyCode
Packit 1fb8d4
{
Packit 1fb8d4
    [self sendVirtualKey:keyCode up:NO];    
Packit 1fb8d4
    [self sendVirtualKey:keyCode up:YES];        
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
#pragma mark modifier key handling
Packit 1fb8d4
// toggle ctrl key, returns true if pressed, otherwise false
Packit 1fb8d4
- (void)toggleCtrlKey
Packit 1fb8d4
{    
Packit 1fb8d4
    [self sendVirtualKey:VK_LCONTROL up:_ctrl_pressed];
Packit 1fb8d4
    _ctrl_pressed = !_ctrl_pressed;
Packit 1fb8d4
    [self notifyDelegateModifiersChanged];    
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
// toggle alt key, returns true if pressed, otherwise false
Packit 1fb8d4
- (void)toggleAltKey
Packit 1fb8d4
{
Packit 1fb8d4
    [self sendVirtualKey:VK_LMENU up:_alt_pressed];
Packit 1fb8d4
    _alt_pressed = !_alt_pressed;
Packit 1fb8d4
    [self notifyDelegateModifiersChanged];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
// toggle shift key, returns true if pressed, otherwise false
Packit 1fb8d4
- (void)toggleShiftKey
Packit 1fb8d4
{
Packit 1fb8d4
    [self sendVirtualKey:VK_LSHIFT up:_shift_pressed];
Packit 1fb8d4
    _shift_pressed = !_shift_pressed;
Packit 1fb8d4
    [self notifyDelegateModifiersChanged];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
// toggle windows key, returns true if pressed, otherwise false
Packit 1fb8d4
- (void)toggleWinKey
Packit 1fb8d4
{
Packit 1fb8d4
    [self sendVirtualKey:(VK_LWIN | KBDEXT) up:_win_pressed];
Packit 1fb8d4
    _win_pressed = !_win_pressed;
Packit 1fb8d4
    [self notifyDelegateModifiersChanged];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
#pragma mark Sending special key strokes
Packit 1fb8d4
Packit 1fb8d4
- (void)sendEnterKeyStroke
Packit 1fb8d4
{
Packit 1fb8d4
    [self sendVirtualKeyCode:(VK_RETURN | KBDEXT)];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
- (void)sendEscapeKeyStroke
Packit 1fb8d4
{
Packit 1fb8d4
    [self sendVirtualKeyCode:VK_ESCAPE];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
- (void)sendBackspaceKeyStroke
Packit 1fb8d4
{
Packit 1fb8d4
    [self sendVirtualKeyCode:VK_BACK];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
@end
Packit 1fb8d4
Packit 1fb8d4
#pragma mark -
Packit 1fb8d4
@implementation RDPKeyboard (Private)
Packit 1fb8d4
Packit 1fb8d4
- (void)handleAlphaNumChar:(int)character
Packit 1fb8d4
{
Packit 1fb8d4
    // if we recive an uppercase letter - make it lower and send an shift down event to server
Packit 1fb8d4
    BOOL shift_was_sent = NO;
Packit 1fb8d4
    if(isupper(character) && _shift_pressed == NO)
Packit 1fb8d4
    {
Packit 1fb8d4
        character = tolower(character);
Packit 1fb8d4
        [self sendVirtualKey:VK_LSHIFT up:NO];
Packit 1fb8d4
        shift_was_sent = YES;
Packit 1fb8d4
    }
Packit 1fb8d4
    
Packit 1fb8d4
    // convert the character to a VK
Packit 1fb8d4
    int vk = _virtual_key_map[character];
Packit 1fb8d4
    if(vk != 0)
Packit 1fb8d4
    {
Packit 1fb8d4
        // send key pressed
Packit 1fb8d4
        [self sendVirtualKey:vk up:NO];    
Packit 1fb8d4
        [self sendVirtualKey:vk up:YES];        
Packit 1fb8d4
    }
Packit 1fb8d4
    
Packit 1fb8d4
    // send the missing shift up if we had a shift down
Packit 1fb8d4
    if(shift_was_sent)
Packit 1fb8d4
        [self sendVirtualKey:VK_LSHIFT up:YES];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
- (void)handleSpecialKey:(int)character
Packit 1fb8d4
{
Packit 1fb8d4
    NSDictionary* eventDescriptor = nil;
Packit 1fb8d4
    if(character < 256)
Packit 1fb8d4
    {
Packit 1fb8d4
        // convert the character to a unicode character
Packit 1fb8d4
        int code = _unicode_map[character];
Packit 1fb8d4
        if(code != 0)
Packit 1fb8d4
            eventDescriptor = [NSDictionary dictionaryWithObjectsAndKeys:	
Packit 1fb8d4
                               @"keyboard", @"type",
Packit 1fb8d4
                               @"unicode", @"subtype",
Packit 1fb8d4
                               [NSNumber numberWithUnsignedShort:0], @"flags",
Packit 1fb8d4
                               [NSNumber numberWithUnsignedShort:code], @"unicode_char",
Packit 1fb8d4
                               nil];
Packit 1fb8d4
    }
Packit 1fb8d4
Packit 1fb8d4
    if (eventDescriptor == nil)
Packit 1fb8d4
        eventDescriptor = [NSDictionary dictionaryWithObjectsAndKeys:	
Packit 1fb8d4
                           @"keyboard", @"type",
Packit 1fb8d4
                           @"unicode", @"subtype",
Packit 1fb8d4
                           [NSNumber numberWithUnsignedShort:0], @"flags",
Packit 1fb8d4
                           [NSNumber numberWithUnsignedShort:character], @"unicode_char",
Packit 1fb8d4
                           nil];        
Packit 1fb8d4
Packit 1fb8d4
    [_session sendInputEvent:eventDescriptor];        
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
// sends the vk code to the session
Packit 1fb8d4
- (void)sendVirtualKey:(int)vKey up:(BOOL)up
Packit 1fb8d4
{
Packit 1fb8d4
    DWORD scancode = GetVirtualScanCodeFromVirtualKeyCode(vKey, 4);
Packit 1fb8d4
    int flags = (up ? KBD_FLAGS_RELEASE : KBD_FLAGS_DOWN);
Packit 1fb8d4
    flags |= ((scancode & KBDEXT) ? KBD_FLAGS_EXTENDED : 0);
Packit 1fb8d4
    [_session sendInputEvent:[NSDictionary dictionaryWithObjectsAndKeys:	
Packit 1fb8d4
                                @"keyboard", @"type",
Packit 1fb8d4
                                @"scancode", @"subtype",
Packit 1fb8d4
                                [NSNumber numberWithUnsignedShort:flags], @"flags",
Packit 1fb8d4
                                [NSNumber numberWithUnsignedShort:(scancode & 0xFF)], @"scancode",
Packit 1fb8d4
                                nil]];        
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
- (void)notifyDelegateModifiersChanged
Packit 1fb8d4
{
Packit 1fb8d4
    if ([[self delegate] respondsToSelector:@selector(modifiersChangedForKeyboard:)])
Packit 1fb8d4
        [[self delegate] modifiersChangedForKeyboard:self];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
@end