GameTextInput   Part of Android Game Development Kit.

Using the GameTextInput library is a simpler alternative to writing a full-screen Android app that uses the soft keyboard for text input.

GameTextInput provides a straightforward API to show or hide the soft keyboard, set or get the currently-edited text, and receive notifications when the text is changed. This is not meant for fully-fledged text editor apps, but still provides selection and composing region support for typical uses cases in games. Also, this library supports advanced input method editor (IME) features such as spell- checking, completions, and multi-key characters.

Internally, GameTextInput accumulates the input text (together with the relevant states) to the internal buffer GameTextInput::currentState_ and notifies the app of any changes in it. The app then performs text processing in its registered callback function.

Availability

GameTextInput can be used in the following ways:

  • Together with GameActivity: GameActivity integrates GameTextInput. Applications that use GameActivity can only use the integrated GameTextInput. Usage instructions are fully documented on the GameActivity page . For a sample of GameActivity and GameTextInput integration, see the games-samples repository. This usage model is not within the scope of this guide.

  • As a standalone library: the rest of the guide describes the usage steps.

Note that the above two methods are mutually exclusive.

Formal GameTextInput releases are available in the following channels:

This guide covers the first usage case. To use the zip file releases, refer to the instructions shipped inside the package.

Set up your build

GameTextInput is distributed as an Android Archive (AAR). This AAR contains the Java classes and the C source code, which implements the native features of GameTextInput. You need to include these source files as part of your build process via Prefab, which exposes native libraries and source code to your CMake project or NDK build.

  1. Follow the instructions on the Jetpack Android Games page to add the GameTextInput library dependency to your game's build.gradle file. Note that if your applications are using GameActivity, they cannot use the standalone GameTextInput library.

  2. Make sure gradle.properties contains the following lines:

    # Tell Android Studio we are using AndroidX.
    android.useAndroidX=true
    # Use Prefab 1.1.2 or higher, which contains a fix for "header only" libs.
    android.prefabVersion=1.1.2
    # Required only if you're using Android Studio 4.0 (4.1 is recommended).
    # android.enablePrefab=true
    
  3. Import the game-text-input package and add it to your target in your project's CMakeLists.txt file:

    find_package(game-text-input REQUIRED CONFIG)
    ...
    target_link_libraries(... game-text-input::game-text-input)
    
  4. In one of the .cpp files in your game, add the following line to include the GameTextInput implementation:

    #include <game-text-input/gametextinput.cpp>
    
  5. In the source files that use the GameTextInput C API, include the header file:

    #include <game-text-input/gametextinput.h>
    
  6. Compile and run the app. If you have CMake errors, verify the AAR and the build.gradle files are properly set up. If the #include file is not found, verify your CMakeLists.txt configuration file.

Integrate your build

  1. From your C thread that is already attached to the JVM, or the app main thread, call GameTextInput_init with a JNIEnv pointer.

    static GameTextInput* gameTextInput = nullptr;
    
    extern "C"
    JNIEXPORT void JNICALL
    Java_com_gametextinput_testbed_MainActivity_onCreated(JNIEnv* env,
      jobject this) {
    {
        if(!gameTextInput)
          gameTextInput = GameTextInput_init(env);
        ...
    }
    
  2. Create a InputEnabledTextView Java class with access to InputConnection.

    public class InputEnabledTextView extends View implements Listener {
      public InputConnection mInputConnection;
      public InputEnabledTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
      }
    
      public InputEnabledTextView(Context context) {
        super(context);
      }
      public void createInputConnection(int inputType) {
        EditorInfo editorInfo = new EditorInfo();
        editorInfo.inputType = inputType;
        editorInfo.actionId = IME_ACTION_NONE;
        editorInfo.imeOptions = IME_FLAG_NO_FULLSCREEN;
        mInputConnection = new InputConnection(this.getContext(), this,
                new Settings(editorInfo, true)
        ).setListener(this);
      }
    
      @Override
      public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
        if (outAttrs != null) {
            GameTextInput.copyEditorInfo(mInputConnection.getEditorInfo(), outAttrs);
        }
        return mInputConnection;
      }
    
      // Called when the IME input changes.
      @Override
      public void stateChanged(State newState, boolean dismissed) {
        onTextInputEventNative(newState);
      }
      @Override
      public void onImeInsetsChanged(Insets insets) {
        // handle Inset changes here
      }
    
      private native void onTextInputEventNative(State softKeyboardEvent);
    }
    
  3. Add the created InputEnabledTextView to UI layout. For example, the following code in activity_main.xml can position it at the bottom of the screen:

    <com.android.example.gametextinputjava.InputEnabledTextView
        android:id="@+id/input_enabled_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />
    
  4. Retrieve this new InputEnabledTextView class to your Java activity. This is relative simple when you use View Binding:

    public class MainActivity extends AppCompatActivity {
      ...
      private ActivityMainBinding binding;
      private InputEnabledTextView inputEnabledTextView;
    
      private native void setInputConnectionNative(InputConnection c);
    
      @Override
      protected void onCreate(Bundle savedInstanceState) {
        ...
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        inputEnabledTextView = binding.inputEnabledTextView;
        inputEnabledTextView.createInputConnection(InputType.TYPE_CLASS_TEXT);
        setInputConnectionNative(inputEnabledTextView.mInputConnection);
      }
    
  5. In your C library, pass inputConnection into GameTextInput_setInputConnection. Pass a callback in GameTextInput_setEventCallback to be notified of events as C state struct GameTextInputState.

    extern "C"JNIEXPORT void JNICALL
    Java_com_gametextinput_testbed_MainActivity_setInputConnectionNative(
      JNIEnv *env, jobject this, jobject inputConnection) {
      GameTextInput_setInputConnection(gameTextInput, inputConnection);
      GameTextInput_setEventCallback(gameTextInput,[](void *ctx, const GameTexgtInputState *state) {
        if (!env || !state) return;
        // process the newly arrived text input from user.
        __android_log_print(ANDROID_LOG_INFO, "TheGreateGameTextInput", state->text_UTF8);
      }, env);
    }
    
  6. In your C library, call GameTextInput_processEvent , which internally calls your callback registered in the previous step, for your app to handle events when the state changes.

    extern "C"
    JNIEXPORT void JNICALL
    Java_com_gametextinput_testbed_InputEnabledTextView_onTextInputEventNative(
      JNIEnv* env, jobject this, jobject soft_keyboard_event) {
      GameTextInput_processEvent(gameTextInput, soft_keyboard_event);
    }
    

Utility functions

The GameTextInput library includes utility functions that lets you convert between Java state objects and C state structs. Access functionality for showing and hiding the IME through the GameTextInput_showIme and GameTextInput_hideIme functions.

References

Developers may find the following helpful when creating apps with GameTextInput:

Feedback

For any issues and questions for GameTextInput, create a bug on the Google IssueTracker.