5

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.

DSlomer64
  • 4,234
  • 4
  • 53
  • 88

2 Answers2

3

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.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Is it not possible to create a custom keyboard view and have it communicate with a focused `EditText` through an `InputConnection`? – Suragch Jul 06 '17 at 05:44
  • @Suragch: I have no idea. On the whole, I do not recommend any of this. Text input is complicated: language, accessibility, etc. Plus, many users expect certain features of their existing input method editor: swipe-based word entry, suggestions, etc. I very strongly recommend that you let the user use whatever keyboard the user chose, rather than imposing your will upon them by forcing some alternative text input in your app. – CommonsWare Jul 06 '17 at 11:14
  • 1
    On the whole I agree with you. However, in Inner Mongolia there are many speakers of Mongolian but few people have a vertical script Mongolian keyboard installed on their phone. (Most use Chinese keyboards.) That's why I am providing a Mongolian keyboard with the apps I am making. – Suragch Jul 06 '17 at 12:02
0

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

Sarvesh
  • 17
  • 9