1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #if !defined(__has_feature) || !__has_feature(objc_arc) 6 #error "This file requires ARC support." 7 #endif 8 9 #import "remoting/ios/key_input.h" 10 #import "remoting/ios/key_map_us.h" 11 12 @interface KeyInput (Private) 13 - (void)transmitAppropriateKeyCode:(NSString*)text; 14 - (void)transmitKeyCode:(NSInteger)keyCode needShift:(bool)needShift; 15 @end 16 17 @implementation KeyInput 18 19 @synthesize delegate = _delegate; 20 21 // Override UIKeyInput::UITextInputTraits property 22 - (UIKeyboardType)keyboardType { 23 return UIKeyboardTypeAlphabet; 24 } 25 26 // Override UIView::UIResponder, when this interface is the first responder 27 // on-screen keyboard input will create events for Chromoting keyboard input 28 - (BOOL)canBecomeFirstResponder { 29 return YES; 30 } 31 32 // Override UIView::UIResponder 33 // Keyboard was dismissed 34 - (BOOL)resignFirstResponder { 35 BOOL wasFirstResponder = self.isFirstResponder; 36 BOOL didResignFirstReponder = 37 [super resignFirstResponder]; // I'm not sure that this returns YES when 38 // first responder was resigned, but for 39 // now I don't actually need to know what 40 // the return from super means. 41 if (wasFirstResponder) { 42 [_delegate keyboardDismissed]; 43 } 44 45 return didResignFirstReponder; 46 } 47 48 // @protocol UIKeyInput, Send backspace 49 - (void)deleteBackward { 50 [self transmitKeyCode:kKeyCodeUS[kBackspaceIndex] needShift:false]; 51 } 52 53 // @protocol UIKeyInput, Assume this is a text input 54 - (BOOL)hasText { 55 return YES; 56 } 57 58 // @protocol UIKeyInput, Translate inserted text to key presses, one char at a 59 // time 60 - (void)insertText:(NSString*)text { 61 [self transmitAppropriateKeyCode:text]; 62 } 63 64 - (void)ctrlAltDel { 65 if (_delegate) { 66 [_delegate keyboardActionKeyCode:kKeyCodeUS[kCtrlIndex] isKeyDown:YES]; 67 [_delegate keyboardActionKeyCode:kKeyCodeUS[kAltIndex] isKeyDown:YES]; 68 [_delegate keyboardActionKeyCode:kKeyCodeUS[kDelIndex] isKeyDown:YES]; 69 [_delegate keyboardActionKeyCode:kKeyCodeUS[kDelIndex] isKeyDown:NO]; 70 [_delegate keyboardActionKeyCode:kKeyCodeUS[kAltIndex] isKeyDown:NO]; 71 [_delegate keyboardActionKeyCode:kKeyCodeUS[kCtrlIndex] isKeyDown:NO]; 72 } 73 } 74 75 // When inserting multiple characters, process them one at a time. |text| is as 76 // it was output on the device. The shift key is not naturally presented in the 77 // input stream, and must be inserted by inspecting each char and considering 78 // that if the key was input on a traditional keyboard that the character would 79 // have required a shift. Assume caps lock does not exist. 80 - (void)transmitAppropriateKeyCode:(NSString*)text { 81 for (int i = 0; i < [text length]; ++i) { 82 NSInteger charToSend = [text characterAtIndex:i]; 83 84 if (charToSend <= kKeyboardKeyMaxUS) { 85 [self transmitKeyCode:kKeyCodeUS[charToSend] 86 needShift:kIsShiftRequiredUS[charToSend]]; 87 } 88 } 89 } 90 91 // |charToSend| is as it was output on the device. Some call this a 92 // 'key press'. For Chromoting this must be transferred as a key down (press 93 // down with a finger), followed by a key up (finger is removed from the 94 // keyboard) 95 // 96 // The delivery may be an upper case or special character. Chromoting is just 97 // interested in the button that was pushed, so to create an upper case 98 // character, first send a shift press, then the button, then release shift 99 - (void)transmitKeyCode:(NSInteger)keyCode needShift:(bool)needShift { 100 if (keyCode > 0 && _delegate) { 101 if (needShift) { 102 [_delegate keyboardActionKeyCode:kKeyCodeUS[kShiftIndex] isKeyDown:YES]; 103 } 104 [_delegate keyboardActionKeyCode:keyCode isKeyDown:YES]; 105 [_delegate keyboardActionKeyCode:keyCode isKeyDown:NO]; 106 if (needShift) { 107 [_delegate keyboardActionKeyCode:kKeyCodeUS[kShiftIndex] isKeyDown:NO]; 108 } 109 } 110 } 111 @end 112