Adding virtual keyboard support for interactive objects

Flash Player 10.2 and later, AIR 2.6 and later (but not supported on iOS)

Normally, the virtual keyboard only opens when a TextField object is tapped. You can configure an instance of the InteractiveObject class to open the virtual keyboard when it receives focus.

To configure an InteractiveObject instance to open the soft keyboard, set its needsSoftKeyboard property to true . Whenever the object is assigned to the stage focus property, the soft keyboard automatically opens. In addition, you can raise the keyboard by calling the requestSoftKeyboard() method of the InteractiveObject.

The following example illustrates how you can program an InteractiveObject to act as a text entry field. The TextInput class shown in the example sets the needsSoftKeyboard property so that the keyboard is raised when needed. The object then listens for keyDown events and inserts the typed character into the field.

The example uses the Flash text engine to append and display any typed text and handles some important events. For simplicity, the example does not implement a full-featured text field.

package  { 
    import flash.geom.Rectangle; 
    import flash.display.Sprite; 
    import flash.text.engine.TextElement; 
    import flash.text.engine.TextBlock; 
    import flash.events.MouseEvent; 
    import flash.events.FocusEvent; 
    import flash.events.KeyboardEvent; 
    import flash.text.engine.TextLine; 
    import flash.text.engine.ElementFormat; 
    import flash.events.Event; 
     
    public class TextInput extends Sprite 
    { 
         
        public var text:String = " "; 
         public  var textSize:Number = 24; 
        public var textColor:uint = 0x000000; 
        private var _bounds:Rectangle = new Rectangle( 0, 0, 100, textSize ); 
        private var textElement: TextElement; 
        private var textBlock:TextBlock = new  TextBlock(); 
         
        public function TextInput( text:String = "" ) 
        { 
            this.text = text; 
            this.scrollRect = _bounds; 
            this.focusRect= false; 
             
            //Enable keyboard support 
            this.needsSoftKeyboard = true; 
            this.addEventListener(MouseEvent.MOUSE_DOWN, onSelect); 
            this.addEventListener(FocusEvent.FOCUS_IN, onFocusIn); 
            this.addEventListener(FocusEvent.FOCUS_OUT, onFocusOut); 
             
            //Setup text engine 
            textElement = new TextElement( text, new ElementFormat( null, textSize, textColor ) ); 
            textBlock.content = textElement; 
            var firstLine:TextLine = textBlock.createTextLine( null, _bounds.width - 8 ); 
            firstLine.x = 4; 
            firstLine.y = 4 + firstLine.totalHeight; 
            this.addChild( firstLine ); 
             
        } 
         
        private function onSelect( event:MouseEvent ):void 
        { 
            stage.focus = this; 
        } 
        private function onFocusIn( event:FocusEvent ):void 
        { 
            this.addEventListener( KeyboardEvent.KEY_DOWN, onKey ); 
        } 
     
        private function onFocusOut( event:FocusEvent ):void 
        { 
            this.removeEventListener( KeyboardEvent.KEY_UP, onKey ); 
        }         
         
        private function onKey( event:KeyboardEvent ):void 
        { 
            textElement.replaceText( textElement.text.length, textElement.text.length, String.fromCharCode( event.charCode ) ); 
            updateText(); 
        } 
        public function set bounds( newBounds:Rectangle ):void 
        { 
            _bounds = newBounds.clone(); 
            drawBackground(); 
            updateText(); 
            this.scrollRect = _bounds; 
             
            //force update to focus rect, if needed 
            if( this.stage!= null && this.focusRect && this.stage.focus == this ) 
                this.stage.focus = this; 
        } 
         
        private function updateText():void 
        { 
            //clear text lines 
            while( this.numChildren > 0 ) this.removeChildAt( 0 ); 
             
            //and recreate them 
            var textLine:TextLine = textBlock.createTextLine( null, _bounds.width - 8); 
            while ( textLine) 
            { 
                textLine.x = 4; 
                if( textLine.previousLine != null ) 
                { 
                    textLine.y = textLine.previousLine.y + 
                                textLine.previousLine.totalHeight + 2; 
                } 
                                  else 
                { 
                    textLine.y = 4 + textLine.totalHeight; 
                } 
                this.addChild(textLine); 
                textLine = textBlock.createTextLine(textLine, _bounds.width - 8 );  
                 }             
        } 
         
        private function drawBackground():void 
        { 
            //draw background and border for the field 
            this.graphics.clear(); 
            this.graphics.beginFill( 0xededed ); 
            this.graphics.lineStyle( 1, 0x000000 ); 
            this.graphics.drawRect( _bounds.x + 2, _bounds.y + 2, _bounds.width - 4, _bounds.height - 4); 
            this.graphics.endFill(); 
        } 
    } 
}

The following main application class illustrates how to use the TextInput class and manage the application layout when the keyboard is raised or the device orientation changes. The main class creates a TextInput object and sets its bounds to fill the stage. The class adjusts the size of the TextInput object when either the soft keyboard is raised or the stage changes size. The class listens for soft keyboard events from the TextInput object and resize events from the stage. Irrespective of the cause of the event, the application determines the visible area of the stage and resizes the input control to fill it. Naturally, in a real application, you would need a more sophisticated layout algorithm.

package  { 
 
    import flash.display.MovieClip; 
    import flash.events.SoftKeyboardEvent; 
    import flash.geom.Rectangle; 
    import flash.events.Event; 
    import flash.display.StageScaleMode; 
    import flash.display.StageAlign; 
     
    public class CustomTextField extends MovieClip { 
                     
        private var customField:TextInput = new TextInput("Input text: "); 
         
        public function CustomTextField() {             
            this.stage.scaleMode = StageScaleMode.NO_SCALE; 
            this.stage.align = StageAlign.TOP_LEFT; 
            this.addChild( customField ); 
            customField.bounds = new Rectangle( 0, 0, this.stage.stageWidth, this.stage.stageHeight ); 
             
            //track soft keyboard and stage resize events 
            customField.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATE, onDisplayAreaChange ); 
            customField.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_DEACTIVATE, onDisplayAreaChange ); 
            this.stage.addEventListener( Event.RESIZE, onDisplayAreaChange ); 
        } 
     
        private function onDisplayAreaChange( event:Event ):void 
        { 
            //Fill the stage if possible, but avoid the area covered by a keyboard 
            var desiredBounds = new Rectangle( 0, 0, this.stage.stageWidth, this.stage.stageHeight );             
            if( this.stage.stageHeight - this.stage.softKeyboardRect.height < desiredBounds.height ) 
                desiredBounds.height = this.stage.stageHeight - this.stage.softKeyboardRect.height; 
                 
            customField.bounds = desiredBounds; 
        } 
    } 
}
Note: The stage only dispatches resize events in response to an orientation change when the scaleMode property is set to noScale . In other modes, the dimensions of the stage do not change; instead, the content is scaled to compensate.

// Ethnio survey code removed