5
votes

I made this "custom keyboard" by following the wonderful outline in this link AND NOT USING ECLIPSE. I used Android Studio (AS) 1.1.0.

Here's a screenshot from my device:

enter image description here

The only problem is that the procedure requires changing settings for Language and Input AND ALSO replaces the keyboard FOR ALL APPS. I don't want that. I just want MY app to change the keyboard for ITSELF and then revert to the previous keyboard as soon as my app goes off screen, otherwise I'm going to be a huge pain in users' butts. Rather than do that, I may as well just add buttons to perform the keypresses I hoped to invoke via a custom keyboard. (It's not gruesome; user just has to pull down the notification bar and select choose input method, but still too intrusive for most users.)

Here's the structure:

enter image description here

The keypad is altered in qwerty.xml by doing lots of this:

<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
          android:keyWidth="10%p"
          android:horizontalGap="0px"
          android:verticalGap="0px"
          android:keyHeight="60dp"
    >
    <Row>
        <Key android:codes="49" android:keyLabel="1" android:keyEdgeFlags="left"/>
        <Key android:codes="50" android:keyLabel="2"/>
        <Key android:codes="51" android:keyLabel="3"/>
        <Key android:codes="52" android:keyLabel="4"/>
        <Key android:codes="53" android:keyLabel="5"/>
        <Key android:codes="54" android:keyLabel="6"/>
        <Key android:codes="55" android:keyLabel="7"/>
        <Key android:codes="56" android:keyLabel="8"/>
        <Key android:codes="57" android:keyLabel="9"/>
        <Key android:codes="48" android:keyLabel="0" android:keyEdgeFlags="right"/>
    </Row>
...

Here's method.xml:

<?xml version="1.0" encoding="utf-8"?>
<input-method xmlns:android="http://schemas.android.com/apk/res/android">
    <subtype
        android:label=              "@string/subtype_en_US"
        android:imeSubtypeLocale=   "en_US"
        android:imeSubtypeMode=     "keyboard" 
    />
</input-method>

Here's AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.dslomer64.simplekeyboard">

    <application

                android:allowBackup="true"
                android:label="@string/app_name"
                android:icon="@mipmap/ic_launcher"
                android:theme="@style/AppTheme">

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

    </application>

</manifest>

The service that's added to the manifest is what gets at the soft keyboard through the code in SimpleIME.java (empty overrides omitted):

import android.inputmethodservice.InputMethodService;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
import android.media.AudioManager;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.InputConnection;

public class SimpleIME extends InputMethodService
    implements KeyboardView.OnKeyboardActionListener
{

  private KeyboardView kv;
  private Keyboard keyboard;

  private boolean caps = false;

  @Override
  public View onCreateInputView() {
    kv = (KeyboardView)getLayoutInflater().inflate(R.layout.keyboard, null);
    keyboard = new Keyboard(this, R.xml.qwerty);
    kv.setKeyboard(keyboard);
    kv.setOnKeyboardActionListener(this);
    return kv;
  }
  private void playClick(int keyCode){
    AudioManager am = (AudioManager)getSystemService(AUDIO_SERVICE);
    switch(keyCode){
      case 32:
        am.playSoundEffect(AudioManager.FX_KEYPRESS_SPACEBAR);
        break;
      case Keyboard.KEYCODE_DONE:
      case 10:
        am.playSoundEffect(AudioManager.FX_KEYPRESS_RETURN);
        break;
      case Keyboard.KEYCODE_DELETE:
        am.playSoundEffect(AudioManager.FX_KEYPRESS_DELETE);
        break;
      default: am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD);
    }
  }
  @Override
  public void onKey(int primaryCode, int[] keyCodes) {
    InputConnection ic = getCurrentInputConnection();
    playClick(primaryCode);
    switch(primaryCode){
      case Keyboard.KEYCODE_DELETE :
        ic.deleteSurroundingText(1, 0);
        break;
      case Keyboard.KEYCODE_SHIFT:
        caps = !caps;
        keyboard.setShifted(caps);
        kv.invalidateAllKeys();
        break;
      case Keyboard.KEYCODE_DONE:
        ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
        break;
      default:
        char code = (char)primaryCode;
        if(Character.isLetter(code) && caps){
          code = Character.toUpperCase(code);
        }
        ic.commitText(String.valueOf(code),1);
    }
  }
    ...
}

I wonder if anyone out there has done what I need: implement a custom keyboard JUST FOR ONE APP and restore original upon loss of screen focus.

2

2 Answers

3
votes

I just want MY app to change the keyboard for ITSELF

That is not possible through the input method editor system. The user, not you, is in charge of the input method that the user uses.

Rather than do that, I may as well just add buttons to perform the keypresses I hoped to invoke via a custom keyboard.

That is your only option.

0
votes

I have come across the same problem. What you have used here is an Input Method class. Instead please try using the Custom Keyboard as a KeyboardView class. Here is the activity_main.xml file of the code:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="1dp"
android:paddingLeft="1dp"
android:paddingRight="1dp"
android:paddingTop="1dp"
tools:context="com.example.t_sadhan.myapplication.MainActivity">

<EditText
    android:id="@+id/editText0"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true"
    android:inputType="text" />

<EditText
    android:id="@+id/editText1"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_below="@id/editText0"
    android:layout_centerHorizontal="true"
    android:inputType="text" />

<!-- NOTE No need to develop a system service for keyboard, there is a standard View for that (well, not completely standard, its in a funny package 'android.inputmethodservice'. -->
<!-- NOTE The graphical layout does not know the package ('java.lang.NoClassDefFoundError: Could not initialize class android.inputmethodservice.KeyboardView') so the keyboard is not shown. -->
<android.inputmethodservice.KeyboardView
    android:id="@+id/keyboardView"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_centerHorizontal="true"
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:visibility="gone"
    android:keyBackground="@color/background_color"
    android:keyTextColor="#37474F"
    android:keyTextSize="20sp"
    android:fontFamily="sans-serif"
    android:background="#ECEFF1"/>

For detailed explanation of how to create the Keyboard View class refer http://www.fampennings.nl/maarten/android/09keyboard/index.htm