Monday, May 2, 2016

Developing your own keyboard

Writing/ Developing your own keyboard is easy task,

follow the steps given below and you will have your own keyboard in your cellpahone.

1. Create a normal Android Project using Android Studio.

2. Edit Application tab in Manifest;
    Add the following lines into Application tab

<service
    android:name=".utils.SoftKeyboard"
    android:permission="android.permission.BIND_INPUT_METHOD">
    <intent-filter>
        <action android:name="android.view.InputMethod" />
    </intent-filter>
    <meta-data
        android:name="android.view.im"
        android:resource="@xml/method" />
</service>

<activity
    android:name=".activities.ImePreferences"
    android:label="@string/settings_name">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
    </intent-filter>
</activity>

3. Create a folder "xml" in res and Create method.xml

paste following line to method.xml

<input-method xmlns:android="http://schemas.android.com/apk/res/android"
    android:settingsActivity="com.example.android.softkeyboard.ImePreferences"
    android:supportsSwitchingToNextInputMethod="true">
    <subtype
        android:imeSubtypeLocale="en_US"
        android:imeSubtypeMode="keyboard"
        android:label="Ankit" />
    <subtype
        android:imeSubtypeLocale="en_GB"
        android:imeSubtypeMode="keyboard"
        android:label="Ankit" />
</input-method>

4. Create input keyboard layout input.xml in res/layout

<?xml version="1.0" encoding="utf-8"?>
<com.divyankit.keyboard.utils.LatinKeyboardView
xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/keyboard"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true" />



5.  Java Code for LatinKeyboardView is here

LatinKeyboardView.java

public class LatinKeyboardView extends KeyboardView {
    static final int KEYCODE_OPTIONS = -100;
    static final int KEYCODE_LANGUAGE_SWITCH = -101;
    static final int KEYCODE_API = -600;

    public LatinKeyboardView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public LatinKeyboardView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override    protected boolean onLongPress(Key key) {
        if (key.codes[0] == Keyboard.KEYCODE_CANCEL) {
            getOnKeyboardActionListener().onKey(KEYCODE_OPTIONS, null);
            return true;
        } else {
            return super.onLongPress(key);
        }
    }

    void setSubtypeOnSpaceKey(final InputMethodSubtype subtype) {
        final LatinKeyboard keyboard = (LatinKeyboard) getKeyboard();
         
         // keyboard.setSpaceIcon(getResources().getDrawable(subtype.getIconResId()));    
         // keyboard.setShifted(true);       
        
        invalidateAllKeys();
    }
}


6. Java Code for LatinKeyboard is here
LtinKeyboard.java
public class LatinKeyboard extends Keyboard {
    private Key mEnterKey;
    private Key mSpaceKey;
    
/**
* Stores the current state of the mode change key.
 Its width will be dynamically updated to    
 * match the region of {@link #mModeChangeKey} when {@link #mModeChangeKey} 
becomes invisible.*/

    private Key mModeChangeKey;
/**
* Stores the current state of the language switch key (a.k.a. globe key). This should be     
* visible while {@link InputMethodManager#shouldOfferSwitchingToNextInputMethod(IBinder)}  
   * returns true. When this key becomes invisible, its width will be shrunk to zero.*/
    private Key mLanguageSwitchKey;
    /**
* Stores the size and other information of {@link #mModeChangeKey} when   
* {@link #mLanguageSwitchKey} is visible. This should be immutable and will be used only as a
* reference size when the visibility of {@link #mLanguageSwitchKey} is changed.*/
    private Key mSavedModeChangeKey;
/**
* Stores the size and other information of {@link #mLanguageSwitchKey} when it is visible.
* This should be immutable and will be used only as a reference size when the visibility of 
* {@link #mLanguageSwitchKey} is changed.*/
    private Key mSavedLanguageSwitchKey;

    public LatinKeyboard(Context context, int xmlLayoutResId) {
        super(context, xmlLayoutResId);
    }

    public LatinKeyboard(Context context, int layoutTemplateResId,
                         CharSequence characters, int columns, int horizontalPadding) {
        super(context, layoutTemplateResId, characters, columns, horizontalPadding);
    }

    @Override
    protected Key createKeyFromXml(Resources res, Row parent, int x, int y,
     XmlResourceParser parser) {
        Key key = new LatinKey(res, parent, x, y, parser);
        if (key.codes[0] == 10) {
            mEnterKey = key;
        } else if (key.codes[0] == ' ') {
            mSpaceKey = key;
        } else if (key.codes[0] == Keyboard.KEYCODE_MODE_CHANGE) {
            mModeChangeKey = key;
            mSavedModeChangeKey = new LatinKey(res, parent, x, y, parser);
        } else if (key.codes[0] == LatinKeyboardView.KEYCODE_LANGUAGE_SWITCH) {
            mLanguageSwitchKey = key;
            mSavedLanguageSwitchKey = new LatinKey(res, parent, x, y, parser);
        }
        return key;
    }

/**
* Dynamically change the visibility of the language switch key (a.k.a. globe key). 
* * @param visible True if the language switch key should be visible.     */

void setLanguageSwitchKeyVisibility(boolean visible) {
        if (visible) {
      // The language switch key should be visible. Restore the size of the mode change key  
      // and language switch key using the saved layout.           

 mModeChangeKey.width = mSavedModeChangeKey.width;
            mModeChangeKey.x = mSavedModeChangeKey.x;
            mLanguageSwitchKey.width = mSavedLanguageSwitchKey.width;
            mLanguageSwitchKey.icon = mSavedLanguageSwitchKey.icon;
            mLanguageSwitchKey.iconPreview = mSavedLanguageSwitchKey.iconPreview;
        } else {
      // The language switch key should be hidden. Change the width of the mode change key 
      // to fill the space of the language key so that the user will not see any strange gap.         
            mModeChangeKey.width = mSavedModeChangeKey.width + mSavedLanguageSwitchKey.width;
            mLanguageSwitchKey.width = 0;
            mLanguageSwitchKey.icon = null;
            mLanguageSwitchKey.iconPreview = null;
        }
    }

    /**
* This looks at the ime options given by the current editor, to set the   
* appropriate label on the keyboard's enter key (if it has one).     */ 

    void setImeOptions(Resources res, int options) {
        if (mEnterKey == null) {
            return;
        }
        switch (options & (EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION)) {
            case EditorInfo.IME_ACTION_GO:
                mEnterKey.iconPreview = null;
                mEnterKey.icon = null;
                mEnterKey.label = res.getText(R.string.label_go_key);
                break;
            case EditorInfo.IME_ACTION_NEXT:
                mEnterKey.iconPreview = null;
                mEnterKey.icon = null;
                mEnterKey.label = res.getText(R.string.label_next_key);
                break;
            case EditorInfo.IME_ACTION_SEARCH:
                mEnterKey.icon = res.getDrawable(R.drawable.sym_keyboard_search);
                mEnterKey.label = null;
                break;
            case EditorInfo.IME_ACTION_SEND:
                mEnterKey.iconPreview = null;
                mEnterKey.icon = null;
                mEnterKey.label = res.getText(R.string.label_send_key);
                break;
            default:
                mEnterKey.icon = res.getDrawable(R.drawable.sym_keyboard_return);
                mEnterKey.label = null;
                break;
        }
    }
    void setSpaceIcon(final Drawable icon) {
        if (mSpaceKey != null) {
            mSpaceKey.icon = icon;
        }
    }
    static class LatinKey extends Key {

        public LatinKey(Resources res, Row parent, int x, int y,
                        XmlResourceParser parser) {
            super(res, parent, x, y, parser);
        }
        /**
* Overriding this method so that we can reduce the target area for the key that
* closes the keyboard.         */   
     @Override
        public boolean isInside(int x, int y) {
            return super.isInside(x, codes[0] == KEYCODE_CANCEL ? y - 10 : y);
        }
    }
}

5. Define the Keyboard Keys: 

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:horizontalGap="0px"
    android:keyHeight="@dimen/key_height"
    android:keyWidth="10%p"
    android:verticalGap="0px">
    <Row>
        <Key
            android:codes="113"
            android:keyEdgeFlags="left"
            android:keyLabel="q" />
        <Key
            android:codes="119"
            android:keyLabel="w" />
        <Key
            android:codes="101"
            android:keyLabel="e" />
        <Key
            android:codes="114"
            android:keyLabel="r" />
        <Key
            android:codes="116"
            android:keyLabel="t" />
        <Key
            android:codes="121"
            android:keyLabel="y" />
        <Key
            android:codes="117"
            android:keyLabel="u" />
        <Key
            android:codes="105"
            android:keyLabel="i" />
        <Key
            android:codes="111"
            android:keyLabel="o" />
        <Key
            android:codes="112"
            android:keyEdgeFlags="right"
            android:keyLabel="p" />
    </Row>

    <Row>
        <Key
            android:codes="97"
            android:horizontalGap="5%p"
            android:keyEdgeFlags="left"
            android:keyLabel="a" />
        <Key
            android:codes="115"
            android:keyLabel="s" />
        <Key
            android:codes="100"
            android:keyLabel="d" />
        <Key
            android:codes="102"
            android:keyLabel="f" />
        <Key
            android:codes="103"
            android:keyLabel="g" />
        <Key
            android:codes="104"
            android:keyLabel="h" />
        <Key
            android:codes="106"
            android:keyLabel="j" />
        <Key
            android:codes="107"
            android:keyLabel="k" />
        <Key
            android:codes="108"
            android:keyEdgeFlags="right"
            android:keyLabel="l" />
    </Row>

    <Row>
        <Key
            android:codes="-1"
            android:isModifier="true"
            android:isSticky="true"
            android:keyEdgeFlags="left"
            android:keyIcon="@drawable/sym_keyboard_shift"
            android:keyWidth="15%p" />
        <Key
            android:codes="122"
            android:keyLabel="z" />
        <Key
            android:codes="120"
            android:keyLabel="x" />
        <Key
            android:codes="99"
            android:keyLabel="c" />
        <Key
            android:codes="118"
            android:keyLabel="v" />
        <Key
            android:codes="98"
            android:keyLabel="b" />
        <Key
            android:codes="110"
            android:keyLabel="n" />
        <Key
            android:codes="109"
            android:keyLabel="m" />
        <Key
            android:codes="-5"
            android:isRepeatable="true"
            android:keyEdgeFlags="right"
            android:keyIcon="@drawable/sym_keyboard_delete"
            android:keyWidth="15%p" />
    </Row>

    <Row android:rowEdgeFlags="bottom">
        <Key
            android:codes="-2"
            android:keyLabel="\?123"
            android:keyWidth="12%p" />
        <Key
            android:codes="44"
            android:keyLabel=","
            android:keyWidth="13%p" />
        <Key
            android:codes="-101"
            android:keyIcon="@drawable/sym_keyboard_language_switch"
            android:keyWidth="10%p" />
        <Key
            android:codes="32"
            android:isRepeatable="true"
            android:keyIcon="@drawable/sym_keyboard_space"
            android:keyWidth="35%p" />
        <Key
            android:codes="46"
            android:keyLabel="."
            android:keyWidth="13%p" />
        <Key
            android:codes="10"
            android:keyEdgeFlags="right"
            android:keyIcon="@drawable/sym_keyboard_return"
            android:keyWidth="17%p" />
    </Row>
</Keyboard>  

   // Other layout can be found in github repo


6. Create a Class (Service) 


/** * Created by ankit on 4/4/16. */
   public class SoftKeyboard extends InputMethodService
        implements KeyboardView.OnKeyboardActionListener {
    static final boolean DEBUG = false;
    LinearLayout view;

    /**
  * This boolean indicates the optional example code for performing   
  * processing of hard keys in addition to regular text generation    
  * from on-screen interaction.  It would be used for input methods that  
  * perform language translations (such as converting text entered on   
  * a QWERTY keyboard to Chinese), but may not be used for input methods  
  * that are primarily intended to be used for on-screen text entry.     */  
  static final boolean PROCESS_HARD_KEYS = true;
    private InputMethodManager mInputMethodManager;
    private LatinKeyboardView mInputView;
    private CandidateView mCandidateView;
    private CompletionInfo[] mCompletions;

    private StringBuilder mComposing = new StringBuilder();
    private boolean mPredictionOn;
    private boolean mCompletionOn;
    private int mLastDisplayWidth;
    private boolean mCapsLock;
    private long mLastShiftTime;
    private long mMetaState;

    private LatinKeyboard mSymbolsKeyboard;
    private LatinKeyboard mSymbolsShiftedKeyboard;
    private LatinKeyboard mQwertyKeyboard;

    private LatinKeyboard mCurKeyboard;

    private String mWordSeparators;


    //Added for image upload 
   private String UPLOAD_URL = "http://simplifiedcoding.16mb.com/VolleyUpload/upload.php";
    private static final String KEY_IMAGE = "key_image";
    private static final String KEY_NAME = "key_name";
    private Bitmap bitmap;

    //
    /**
   * Main initialization of the input method component.  Be sure to call  
   * to super class.     */  
  @Override
    public void onCreate() {
        super.onCreate();
        mInputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
        mWordSeparators = getResources().getString(R.string.word_separators);
    }

    /**
      * This is the point where you can do all of your UI initialization.  It  
      * is called after creation and any configuration change.    
      */ 

   @Override 
   public void onInitializeInterface() {
        if (mQwertyKeyboard != null) {
          
   // Configuration changes can happen after the keyboard gets recreated,        
    // so we need to be able to re-build the keyboards if the available        
    // space has changed.       
     int displayWidth = getMaxWidth();
            if (displayWidth == mLastDisplayWidth) return;
            mLastDisplayWidth = displayWidth;
        }
        mQwertyKeyboard = new LatinKeyboard(this, R.xml.qwerty);
        mSymbolsKeyboard = new LatinKeyboard(this, R.xml.symbols);
        mSymbolsShiftedKeyboard = new LatinKeyboard(this, R.xml.symbols_shift);
    }

    /**
     * Called by the framework when your view for creating input needs to  
       * be generated.  This will be called the first time your input method    
      * is displayed, and every time it needs to be re-created such as due to   
         * a configuration change.     */   
 @Override 
   public View onCreateInputView() {
        mInputView = (LatinKeyboardView) getLayoutInflater().inflate(R.layout.input, null);
        mInputView.setOnKeyboardActionListener(this);
        setLatinKeyboard(mQwertyKeyboard);
        return mInputView;
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    private void setLatinKeyboard(LatinKeyboard nextKeyboard) {
        final boolean shouldSupportLanguageSwitchKey =
                mInputMethodManager.shouldOfferSwitchingToNextInputMethod(getToken());
        nextKeyboard.setLanguageSwitchKeyVisibility(shouldSupportLanguageSwitchKey);
        mInputView.setKeyboard(nextKeyboard);
    }


    /**
      * Called by the framework when your view for showing candidates needs to 
    * be generated, like {@link #onCreateInputView}.     */  
 
 @Override 
   public View onCreateCandidatesView() {
        mCandidateView = new CandidateView(this);
        mCandidateView.setService(this);
        return mCandidateView;
    }

    /**
  * This is the main point where we do our initialization of the input method  
  * to begin operating on an application.  At this point we have been     
    * bound to the client, and are now receiving all of the detailed information  
  * about the target of our edits.   
  */    
@Override  
  public void onStartInput(EditorInfo attribute, boolean restarting) {
        super.onStartInput(attribute, restarting);

        // Reset our state.  We want to do this even if restarting, because   
     // the underlying state of the text editor could have changed in any way.     
   mComposing.setLength(0);
        updateCandidates();

        if (!restarting) {
            // Clear shift states.        
    mMetaState = 0;
        }

        mPredictionOn = false;
        mCompletionOn = false;
        mCompletions = null;

        // We are now going to initialize our state based on the type of  
      // text being edited.    
    switch (attribute.inputType & InputType.TYPE_MASK_CLASS) {
            case InputType.TYPE_CLASS_NUMBER:
            case InputType.TYPE_CLASS_DATETIME:
              
           // Numbers and dates default to the symbols keyboard, with    
            // no extra features.              
  mCurKeyboard = mSymbolsKeyboard;
                break;

            case InputType.TYPE_CLASS_PHONE:
                
         // Phones will also default to the symbols keyboard, though 
         // often you will want to have a dedicated phone keyboard.         
       mCurKeyboard = mSymbolsKeyboard;
                break;

            case InputType.TYPE_CLASS_TEXT:
         // This is general text editing.  We will default to the       
         // normal alphabetic keyboard, and assume that we should              
         // be doing predictive text (showing candidates as the
         // user types).        
        mCurKeyboard = mQwertyKeyboard;
                mPredictionOn = true;

          // We now look for a few special variations of text that will      
          // modify our behavior.           
     int variation = attribute.inputType & InputType.TYPE_MASK_VARIATION;
                if (variation == InputType.TYPE_TEXT_VARIATION_PASSWORD ||
                        variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {
       // Do not display predictions / what the user is typing             
       // when they are entering a password.           
         mPredictionOn = false;
                }

                if (variation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS 
 || variation == InputType.TYPE_TEXT_VARIATION_URI 
 || variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
                  
  // Our predictions are not useful for e-mail addresses  or URIs.            
        mPredictionOn = false;
                }

                if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
                 
       // If this is an auto-complete text view, then our predictions               
        // will not be shown and instead we will allow the editor         
      // to supply their own.  We only show the editor's         
      // candidates when in fullscreen mode, otherwise relying        
      // own it displaying its own UI.             
            mPredictionOn = false;
                    mCompletionOn = isFullscreenMode();
                }

      // We also want to look at the current state of the editor          
      // to decide whether our alphabetic keyboard should start out            
        // shifted.             
   updateShiftKeyState(attribute);
                break;

            default:
         // For all unknown input types, default to the alphabetic       
         // keyboard with no special features.          
      mCurKeyboard = mQwertyKeyboard;
                updateShiftKeyState(attribute);
        }

        // Update the label on the enter key, depending on what the application   
            // says it will do.      
  mCurKeyboard.setImeOptions(getResources(), attribute.imeOptions);
    }

    /** 
     * This is called when the user is done editing a field.  We can use  
      * this to reset our state.     */  
  @Override   
 public void onFinishInput() {
        super.onFinishInput();

        // Clear current composing text and candidates.   
     mComposing.setLength(0);
        updateCandidates();

    // We only hide the candidates window when finishing input on    
    // a particular editor, to avoid popping the underlying application     
   // up and down if the user is entering text into the bottom of     
   // its window.     
   setCandidatesViewShown(false);
        mCurKeyboard = mQwertyKeyboard;
        if (mInputView != null) {
            mInputView.closing();
        }
    }

    @Override    public void onStartInputView(EditorInfo attribute, boolean restarting) {
        super.onStartInputView(attribute, restarting);
        // Apply the selected keyboard to the input view.   
     setLatinKeyboard(mCurKeyboard);
        mInputView.closing();
        final InputMethodSubtype subtype = mInputMethodManager.getCurrentInputMethodSubtype();
        mInputView.setSubtypeOnSpaceKey(subtype);
    }

    @Override    public void onCurrentInputMethodSubtypeChanged(InputMethodSubtype subtype) {
        mInputView.setSubtypeOnSpaceKey(subtype);
    }

    /**     * Deal with the editor reporting movement of its cursor.     */   
 @Override    public void onUpdateSelection(int oldSelStart, int oldSelEnd,
                                  int newSelStart, int newSelEnd,
                                  int candidatesStart, int candidatesEnd) {
        super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
                candidatesStart, candidatesEnd);

   // If the current selection in the text view changes, we should     
   // clear whatever candidate text we have.   
     if (mComposing.length() > 0 && (newSelStart != candidatesEnd
                || newSelEnd != candidatesEnd)) {
            mComposing.setLength(0);
            updateCandidates();
            InputConnection ic = getCurrentInputConnection();
            if (ic != null) {
                ic.finishComposingText();
            }
        }
    }

    /** * This tells us about completions that the editor has determined based    
 * on the current text in it.  We want to use this in fullscreen mode   
  * to show the completions ourself, since the editor can not be seen   
  * in that situation.     */  
  @Override
   public void onDisplayCompletions(CompletionInfo[] completions) {
        if (mCompletionOn) {
            mCompletions = completions;
            if (completions == null) {
                setSuggestions(null, false, false);
                return;
            }

            List<String> stringList = new ArrayList<String>();
            for (int i = 0; i < completions.length; i++) {
                CompletionInfo ci = completions[i];
                if (ci != null) stringList.add(ci.getText().toString());
            }
            setSuggestions(stringList, true, true);
        }
    }

    /**
 * This translates incoming hard key events in to edit operations on an   
  * InputConnection.  It is only needed when using the  
   * PROCESS_HARD_KEYS option.     */  
  private boolean translateKeyDown(int keyCode, KeyEvent event) {
        mMetaState = MetaKeyKeyListener.handleKeyDown(mMetaState,
                keyCode, event);
        int c = event.getUnicodeChar(MetaKeyKeyListener.getMetaState(mMetaState));
        mMetaState = MetaKeyKeyListener.adjustMetaAfterKeypress(mMetaState);
        InputConnection ic = getCurrentInputConnection();
        if (c == 0 || ic == null) {
            return false;
        }

        boolean dead = false;
        if ((c & KeyCharacterMap.COMBINING_ACCENT) != 0) {
            dead = true;
            c = c & KeyCharacterMap.COMBINING_ACCENT_MASK;
        }

        if (mComposing.length() > 0) {
            char accent = mComposing.charAt(mComposing.length() - 1);
            int composed = KeyEvent.getDeadChar(accent, c);
            if (composed != 0) {
                c = composed;
                mComposing.setLength(mComposing.length() - 1);
            }
        }

        onKey(c, null);

        return true;
    }

    /**
* Use this to monitor key events being delivered to the application.   
  * We get first crack at them, and can either resume them or let them   
  * continue to the app.     */  

  @Override    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_BACK:
               
     // The InputMethodService already takes care of the back         
       // key for us, to dismiss the input method if it is shown.           
     // However, our keyboard could be showing a pop-up window        
        // that back should dismiss, so we first allow it to do that.  

              if (event.getRepeatCount() == 0 && mInputView != null) {
                    if (mInputView.handleBack()) {
                        return true;
                    }
                }
                break;

            case KeyEvent.KEYCODE_DEL:
               
       // Special handling of the delete key: if we currently are        
       // composing text for the user, we want to modify that instead      
       // of let the application to the delete itself.        

        if (mComposing.length() > 0) {
                    onKey(Keyboard.KEYCODE_DELETE, null);
                    return true;
                }
                break;

            case KeyEvent.KEYCODE_ENTER:
                // Let the underlying text editor always handle these.        
        return false;

            default:
       // For all other keys, if we want to do transformations on        
        // text being entered with a hard keyboard, we need to process         
       // it and do the appropriate action.      
          if (PROCESS_HARD_KEYS) {
                    if (keyCode == KeyEvent.KEYCODE_SPACE && (event.getMetaState() & KeyEvent.META_ALT_ON) != 0) {
         // A silly example: in our input method, Alt+Space                
        // is a shortcut for 'android' in lower case.

         InputConnection ic = getCurrentInputConnection();
                        if (ic != null) {
           // First, tell the editor that it is no longer in the            
            // shift state, since we are consuming this.       
                ic.clearMetaKeyStates(KeyEvent.META_ALT_ON);
                            keyDownUp(KeyEvent.KEYCODE_A);
                            keyDownUp(KeyEvent.KEYCODE_N);
                            keyDownUp(KeyEvent.KEYCODE_D);
                            keyDownUp(KeyEvent.KEYCODE_R);
                            keyDownUp(KeyEvent.KEYCODE_O);
                            keyDownUp(KeyEvent.KEYCODE_I);
                            keyDownUp(KeyEvent.KEYCODE_D);
                          
            // And we consume this event.            
                return true;
                        }
                    }
                    if (mPredictionOn && translateKeyDown(keyCode, event)) {
                        return true;
                    }
                }
        }

        return super.onKeyDown(keyCode, event);
    }

    /**
* Use this to monitor key events being delivered to the application. 
* We get first crack at them, and can either resume them or let them  
* continue to the app.     */ 
   @Override    public boolean onKeyUp(int keyCode, KeyEvent event) {
    // If we want to do transformations on text being entered with a hard   
     // keyboard, we need to process the up events to update the meta key    
    // state we are tracking.  

      if (PROCESS_HARD_KEYS) {
            if (mPredictionOn) {
                mMetaState = MetaKeyKeyListener.handleKeyUp(mMetaState,
                        keyCode, event);
            }
        }

        return super.onKeyUp(keyCode, event);
    }

    /**
    * Helper function to commit any text being composed in to the editor.  
   */  

  private void commitTyped(InputConnection inputConnection) {
        if (mComposing.length() > 0) {
            inputConnection.commitText(mComposing, mComposing.length());
            mComposing.setLength(0);
            updateCandidates();
        }
    }

    /**
* Helper to update the shift state of our keyboard based on the initial  
   * editor state.     */ 
   private void updateShiftKeyState(EditorInfo attr) {
        if (attr != null && mInputView != null && mQwertyKeyboard == mInputView.getKeyboard()) {
            int caps = 0;
            EditorInfo ei = getCurrentInputEditorInfo();
            if (ei != null && ei.inputType != InputType.TYPE_NULL) {
                caps = getCurrentInputConnection().getCursorCapsMode(attr.inputType);
            }
            mInputView.setShifted(mCapsLock || caps != 0);
        }
    }

    /** * Helper to determine if a given character code is alphabetic.     */   

 private boolean isAlphabet(int code) {
        if (Character.isLetter(code)) {
            return true;
        } else {
            return false;
        }
    }

    /** * Helper to send a key down / key up pair to the current editor.     */  
 
 private void keyDownUp(int keyEventCode) {
        getCurrentInputConnection().sendKeyEvent(
                new KeyEvent(KeyEvent.ACTION_DOWN, keyEventCode));
        getCurrentInputConnection().sendKeyEvent(
                new KeyEvent(KeyEvent.ACTION_UP, keyEventCode));
    }

    /*** Helper to send a character to the editor as raw key events.     */  

  private void sendKey(int keyCode) {
        switch (keyCode) {
            case '\n':
                keyDownUp(KeyEvent.KEYCODE_ENTER);
                break;
            default:
                if (keyCode >= '0' && keyCode <= '9') {
                    keyDownUp(keyCode - '0' + KeyEvent.KEYCODE_0);
                } else {
                    getCurrentInputConnection().commitText(String.valueOf((char) keyCode), 1);
                }
                break;
        }
    }

    // Implementation of KeyboardViewListener  
  public void onKey(int primaryCode, int[] keyCodes) {
        if (isWordSeparator(primaryCode)) {
            // Handle separator            if (mComposing.length() > 0) {
                commitTyped(getCurrentInputConnection());
            }
            sendKey(primaryCode);
            updateShiftKeyState(getCurrentInputEditorInfo());
        } else if (primaryCode == Keyboard.KEYCODE_DELETE) {
            handleBackspace();
        } else if (primaryCode == Keyboard.KEYCODE_SHIFT) {
            handleShift();
        } else if (primaryCode == Keyboard.KEYCODE_CANCEL) {
            handleClose();
            return;
        } else if (primaryCode == LatinKeyboardView.KEYCODE_LANGUAGE_SWITCH) {
            handleLanguageSwitch();
            return;
        } else if (primaryCode == LatinKeyboardView.KEYCODE_OPTIONS) {
            // Show a menu or somethin'        
} else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE && mInputView != null) {
            Keyboard current = mInputView.getKeyboard();
            if (current == mSymbolsKeyboard || current == mSymbolsShiftedKeyboard) {
                setLatinKeyboard(mQwertyKeyboard);
            } else {
                setLatinKeyboard(mSymbolsKeyboard);
                mSymbolsKeyboard.setShifted(false);
            }
        } else {
            handleCharacter(primaryCode, keyCodes);
        }
    }

    public void onText(CharSequence text) {
        InputConnection ic = getCurrentInputConnection();
        if (ic == null) return;
        ic.beginBatchEdit();
        if (mComposing.length() > 0) {
            commitTyped(ic);
        }
        ic.commitText(text, 0);
        ic.endBatchEdit();
        updateShiftKeyState(getCurrentInputEditorInfo());
    }

    /**
    * Update the list of available candidates from the current composing  
     * text.  This will need to be filled in by however you are determining   
      * candidates.     */   

 private void updateCandidates() {
        if (!mCompletionOn) {
            if (mComposing.length() > 0) {
                ArrayList<String> list = new ArrayList<String>();
                list.add(mComposing.toString());
                setSuggestions(list, true, true);
            } else {
                setSuggestions(null, false, false);
            }
        }
    }

    public void setSuggestions(List<String> suggestions, boolean completions,
                               boolean typedWordValid) {
        if (suggestions != null && suggestions.size() > 0) {
            setCandidatesViewShown(true);
        } else if (isExtractViewShown()) {
            setCandidatesViewShown(true);
        }
        if (mCandidateView != null) {
            mCandidateView.setSuggestions(suggestions, completions, typedWordValid);
        }
    }

    private void handleBackspace() {
        final int length = mComposing.length();
        if (length > 1) {
            mComposing.delete(length - 1, length);
            getCurrentInputConnection().setComposingText(mComposing, 1);
            updateCandidates();
        } else if (length > 0) {
            mComposing.setLength(0);
            getCurrentInputConnection().commitText("", 0);
            updateCandidates();
        } else {
            keyDownUp(KeyEvent.KEYCODE_DEL);
        }
        updateShiftKeyState(getCurrentInputEditorInfo());
    }

    private void handleShift() {
        if (mInputView == null) {
            return;
        }

        Keyboard currentKeyboard = mInputView.getKeyboard();
        if (mQwertyKeyboard == currentKeyboard) {
            // Alphabet keyboard            checkToggleCapsLock();
            mInputView.setShifted(mCapsLock || !mInputView.isShifted());
        } else if (currentKeyboard == mSymbolsKeyboard) {
            mSymbolsKeyboard.setShifted(true);
            setLatinKeyboard(mSymbolsShiftedKeyboard);
            mSymbolsShiftedKeyboard.setShifted(true);
        } else if (currentKeyboard == mSymbolsShiftedKeyboard) {
            mSymbolsShiftedKeyboard.setShifted(false);
            setLatinKeyboard(mSymbolsKeyboard);
            mSymbolsKeyboard.setShifted(false);
        }
    }

    private void handleCharacter(int primaryCode, int[] keyCodes) {
        if (isInputViewShown()) {
            if (mInputView.isShifted()) {
                primaryCode = Character.toUpperCase(primaryCode);
            }
        }
        if (isAlphabet(primaryCode) && mPredictionOn) {
            mComposing.append((char) primaryCode);
            getCurrentInputConnection().setComposingText(mComposing, 1);
            updateShiftKeyState(getCurrentInputEditorInfo());
            updateCandidates();
        } else {
            getCurrentInputConnection().commitText(
                    String.valueOf((char) primaryCode), 1);
        }
    }

    private void handleClose() {
        commitTyped(getCurrentInputConnection());
        requestHideSelf(0);
        mInputView.closing();
    }

    private IBinder getToken() {
        final Dialog dialog = getWindow();
        if (dialog == null) {
            return null;
        }
        final Window window = dialog.getWindow();
        if (window == null) {
            return null;
        }
        return window.getAttributes().token;
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private void handleLanguageSwitch() {
        mInputMethodManager.switchToNextInputMethod(getToken(), false /* onlyCurrentIme */);
    }

    private void checkToggleCapsLock() {
        long now = System.currentTimeMillis();
        if (mLastShiftTime + 800 > now) {
            mCapsLock = !mCapsLock;
            mLastShiftTime = 0;
        } else {
            mLastShiftTime = now;
        }
    }

    private String getWordSeparators() {
        return mWordSeparators;
    }

    public boolean isWordSeparator(int code) {
        String separators = getWordSeparators();
        return separators.contains(String.valueOf((char) code));
    }

    public void pickDefaultCandidate() {
        pickSuggestionManually(0);
    }

    public void pickSuggestionManually(int index) {
        if (mCompletionOn && mCompletions != null
 && index >= 0 && index < mCompletions.length) {
            CompletionInfo ci = mCompletions[index];
            getCurrentInputConnection().commitCompletion(ci);
            if (mCandidateView != null) {
                mCandidateView.clear();
            }
            updateShiftKeyState(getCurrentInputEditorInfo());
        } else if (mComposing.length() > 0) {
            // If we were generating candidate suggestions for the current  
          // text, we would commit one of them here.  But for this sample,      
      // we will just commit the current text.       

     commitTyped(getCurrentInputConnection());
        }
    }

    public void swipeRight() {
        if (mCompletionOn) {
            pickDefaultCandidate();
        }
    }

    public void swipeLeft() {
        handleBackspace();
    }

    public void swipeDown() {
        handleClose();
    }

    public void swipeUp() {
    }

    public void onPress(int primaryCode) {
    }

    public void onRelease(int primaryCode) {
    }

    @Override    public void onDestroy() {
        super.onDestroy();
    }

    private void takeScreenshot() {
        Date now = new Date();
        android.text.format.DateFormat.format("yyyy-MM-dd_hh:mm:ss", now);

        try {
            // image naming and path  to include sd card  appending name you choose for file    

        String mPath = Environment.getExternalStorageDirectory().toString() + "/" + now + ".jpg";

            view = new LinearLayout(getApplicationContext());
            WindowManager wm = (WindowManager) getApplicationContext()
.getSystemService(Context.WINDOW_SERVICE);
            Display display = wm.getDefaultDisplay();
            Point size = new Point();
            display.getSize(size);
            int width = size.x;
            int height = size.y;
            view.setLayoutParams(new ViewGroup.LayoutParams(width, height));
            // create bitmap screen capture            View v1 = view.getRootView();
            v1.setDrawingCacheEnabled(true);
            Bitmap bitmap = Bitmap.createBitmap(v1.getDrawingCache());
            v1.setDrawingCacheEnabled(false);

            File imageFile = new File(mPath);

            FileOutputStream outputStream = new FileOutputStream(imageFile);
            int quality = 100;
            bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
            outputStream.flush();
            outputStream.close();
            Log.d("Screen", "taken");
            //openScreenshot(imageFile);        } catch (Throwable e) {
            // Several error may come out with file handling or OOM      

      e.printStackTrace();
        }
    }
}
And you are done keyboard now...
If you like it, then like it on Facebook and recommend on G+
Full Source code can be downloaded from here