iphonecordovaiphone-softkeyboard

Programmatically show soft keyboard on iPhone in a PhoneGap application?


I've been searching far and long, and to this moment, I did not come across a working solution for PhoneGap / Cordova applications that would show soft keyboard programmatically.

Scenario:

We have a PhoneGap application - a website created in jQuery Mobile - that at one point shows a dialog to the user. This dialog is also a web page and has one single INPUT text box where user should enter a code.

Problem:

When the code dialog is shown, the input box is focused using JavaScript. However, due to restrictions placed on iPhone's internal browser, the soft keyboard does not come up until the user actually really clicks inside the input text box.

What we tried:

Any ideas?


EDIT: The restriction mentioned in this question is for built-in browsers only... if you're aiming Opera, you will be successful by using the following code:

var e = jQuery.Event("keydown", { keyCode: 37 });
$('#element').focus().trigger(e);

EDIT2: This is a final working PhoneGap code that can be used in a plugin:

keyboardhelper.h

//
//  keyboardHelper.h
//  soft keyboard displaying plugin for PhoneGap
//
//  Copyright 2012 Martin Ambrus.
//

#import <Foundation/Foundation.h>
#ifdef CORDOVA_FRAMEWORK
#import <Cordova/CDVPlugin.h>
#else
#import "CDVPlugin.h"
#endif

@interface keyboardHelper : CDVPlugin {
    NSString *callbackID;
}

@property (nonatomic, copy) NSString *callbackID;

- (void)showKeyboard:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;

@end

keyboardhelper.m

//
//  keyboardHelper.m
//  soft keyboard displaying plugin for PhoneGap
//
//  Copyright 2012 Martin Ambrus.
//

#import "keyboardHelper.h"
#import "AppDelegate.h"

@implementation keyboardHelper
@synthesize callbackID;

-(void)showKeyboard:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options {
    self.callbackID = [arguments pop];

    //Get text field coordinate from webview. - You should do this after the webview gets loaded
    //myCustomDiv is a div in the html that contains the textField.
    int textFieldContainerHeightOutput = [[((AppDelegate *)[[UIApplication sharedApplication] delegate]).viewController.webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetHeight;"] intValue];

    int textFieldContainerWidthOutput = [[((AppDelegate *)[[UIApplication sharedApplication] delegate]).viewController.webView  stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetWidth;"] intValue];

    int textFieldContainerYOffset = [[((AppDelegate *)[[UIApplication sharedApplication] delegate]).viewController.webView  stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetTop;"] intValue];

    int textFieldContainerXOffset = [[((AppDelegate *)[[UIApplication sharedApplication] delegate]).viewController.webView  stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetLeft;"] intValue];

    UITextField *myTextField = [[UITextField alloc] initWithFrame: CGRectMake(textFieldContainerXOffset, textFieldContainerYOffset, textFieldContainerWidthOutput, textFieldContainerHeightOutput)];

    [((AppDelegate *)[[UIApplication sharedApplication] delegate]).viewController.webView addSubview:myTextField];
    myTextField.delegate = self;

    CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString: @"ok"];

    [self writeJavascript:[pluginResult toSuccessCallbackString:self.callbackID]];
}

-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
//here you create your request to the server
return NO;
}

-(BOOL)textFieldDidEndEditing:(UITextField *)textField
{
//here you create your request to the server
return NO;
}

@end

javascript

var keyboardHelper = {
    showKeyboard: function(types, success, fail) {
        return Cordova.exec(success, fail, "keyboardHelper", "showKeyboard", types);
    }
};

Solution

  • You can get the coordinates for the input field using javascript on the webView. Then, place your own textField right on top of it and in it's delegate method textFieldShouldReturn send a request to the server with the code the user typed in.

        //Get text field coordinate from webview. - You should do this after the webview gets loaded
        //myCustomDiv is a div in the html that contains the textField.
    int textFieldContainerHeightOutput = [[webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetHeight;"] intValue];
    
    int textFieldContainerWidthOutput = [[webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetWidth;"] intValue];
    
    int textFieldContainerYOffset = [[webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetTop;"] intValue];
    
    int textFieldContainerXOffset = [[webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetLeft;"] intValue];
    
    myTextField.frame = CGRectMake(textFieldContainerXOffset, textFieldContainerYOffset, textFieldContainerWidthOutput, textFieldContainerHeightOutput);
    [webView addSubview:myTextField];
    myTextField.delegate = self;
    

    Then you implement textFieldShouldReturn and create your request to the server there.

    -(BOOL)textFieldShouldReturn:(UITextField *)textField
    {
    //here you create your request to the server
    return NO;
    }
    

    This is done in existing project, however without using PhoneGap. I hope you can adapt it to suit your needs.

    To remove the text field, you can hide it

    myTextField.hidden = YES;
    

    or

    myTextField = nil;
    

    or

    [myTextField removeFromSuperView];