// // TextFieldKeyboardDelegate.m // Moonlight // // Created by Cameron Gutman on 3/24/20. // Copyright © 2020 Moonlight Game Streaming Project. All rights reserved. // #import "TextFieldKeyboardDelegate.h" #import "KeyboardSupport.h" #include @implementation TextFieldKeyboardDelegate { NSDictionary *dictCodes; } - (id)initWithTextField:(UITextField*)textField { self = [self init]; [textField addTarget:self action:@selector(onKeyboardPressed:) forControlEvents:UIControlEventEditingChanged]; textField.delegate = self; return self; } - (BOOL)textFieldShouldReturn:(UITextField *)textField { // This method is called when the "Return" key is pressed. LiSendKeyboardEvent(0x0d, KEY_ACTION_DOWN, 0); usleep(50 * 1000); LiSendKeyboardEvent(0x0d, KEY_ACTION_UP, 0); return NO; } - (void)onKeyboardPressed:(UITextField *)textField { NSString* inputText = textField.text; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ // If the text became empty, we know the user pressed the backspace key. if ([inputText isEqual:@""]) { LiSendKeyboardEvent(0x08, KEY_ACTION_DOWN, 0); usleep(50 * 1000); LiSendKeyboardEvent(0x08, KEY_ACTION_UP, 0); } else { // Character 0 will be our known sentinel value for (int i = 1; i < [inputText length]; i++) { struct KeyEvent event = [KeyboardSupport translateKeyEvent:[inputText characterAtIndex:i] withModifierFlags:0]; if (event.keycode == 0) { // If we don't know the code, don't send anything. Log(LOG_W, @"Unknown key code: [%c]", [inputText characterAtIndex:i]); continue; } [self sendLowLevelEvent:event]; } } }); // Reset text field back to known state textField.text = @"0"; // Move the insertion point back to the end of the text box UITextRange *textRange = [textField textRangeFromPosition:textField.endOfDocument toPosition:textField.endOfDocument]; [textField setSelectedTextRange:textRange]; } - (void)specialCharPressed:(UIKeyCommand *)cmd { struct KeyEvent event = [KeyboardSupport translateKeyEvent:0x20 withModifierFlags:[cmd modifierFlags]]; event.keycode = [[dictCodes valueForKey:[cmd input]] intValue]; [self sendLowLevelEvent:event]; } - (void)keyPressed:(UIKeyCommand *)cmd { struct KeyEvent event = [KeyboardSupport translateKeyEvent:[[cmd input] characterAtIndex:0] withModifierFlags:[cmd modifierFlags]]; [self sendLowLevelEvent:event]; } - (void)sendLowLevelEvent:(struct KeyEvent)event { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ // When we want to send a modified key (like uppercase letters) we need to send the // modifier ("shift") seperately from the key itself. if (event.modifier != 0) { LiSendKeyboardEvent(event.modifierKeycode, KEY_ACTION_DOWN, event.modifier); } LiSendKeyboardEvent(event.keycode, KEY_ACTION_DOWN, event.modifier); usleep(50 * 1000); LiSendKeyboardEvent(event.keycode, KEY_ACTION_UP, event.modifier); if (event.modifier != 0) { LiSendKeyboardEvent(event.modifierKeycode, KEY_ACTION_UP, event.modifier); } }); } - (NSArray *)keyCommands { NSString *charset = @"qwertyuiopasdfghjklzxcvbnm1234567890\t§[]\\'\"/.,`<>-´ç+`¡'º;ñ= "; NSMutableArray * commands = [NSMutableArray array]; dictCodes = [[NSDictionary alloc] initWithObjectsAndKeys: [NSNumber numberWithInt: 0x0d], @"\r", [NSNumber numberWithInt: 0x08], @"\b", [NSNumber numberWithInt: 0x1b], UIKeyInputEscape, [NSNumber numberWithInt: 0x28], UIKeyInputDownArrow, [NSNumber numberWithInt: 0x26], UIKeyInputUpArrow, [NSNumber numberWithInt: 0x25], UIKeyInputLeftArrow, [NSNumber numberWithInt: 0x27], UIKeyInputRightArrow, nil]; [charset enumerateSubstringsInRange:NSMakeRange(0, charset.length) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) { [commands addObject:[UIKeyCommand keyCommandWithInput:substring modifierFlags:0 action:@selector(keyPressed:)]]; [commands addObject:[UIKeyCommand keyCommandWithInput:substring modifierFlags:UIKeyModifierShift action:@selector(keyPressed:)]]; [commands addObject:[UIKeyCommand keyCommandWithInput:substring modifierFlags:UIKeyModifierControl action:@selector(keyPressed:)]]; [commands addObject:[UIKeyCommand keyCommandWithInput:substring modifierFlags:UIKeyModifierAlternate action:@selector(keyPressed:)]]; }]; for (NSString *c in [dictCodes keyEnumerator]) { [commands addObject:[UIKeyCommand keyCommandWithInput:c modifierFlags:0 action:@selector(specialCharPressed:)]]; [commands addObject:[UIKeyCommand keyCommandWithInput:c modifierFlags:UIKeyModifierShift action:@selector(specialCharPressed:)]]; [commands addObject:[UIKeyCommand keyCommandWithInput:c modifierFlags:UIKeyModifierShift | UIKeyModifierAlternate action:@selector(specialCharPressed:)]]; [commands addObject:[UIKeyCommand keyCommandWithInput:c modifierFlags:UIKeyModifierShift | UIKeyModifierControl action:@selector(specialCharPressed:)]]; [commands addObject:[UIKeyCommand keyCommandWithInput:c modifierFlags:UIKeyModifierControl action:@selector(specialCharPressed:)]]; [commands addObject:[UIKeyCommand keyCommandWithInput:c modifierFlags:UIKeyModifierControl | UIKeyModifierAlternate action:@selector(specialCharPressed:)]]; [commands addObject:[UIKeyCommand keyCommandWithInput:c modifierFlags:UIKeyModifierAlternate action:@selector(specialCharPressed:)]]; } return commands; } @end