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.
For a sample that integrates GameTextInput, see the games-samples repository.
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.
If you aren't using
GameActivity
, follow the instructions on the Jetpack Android Games page to add theGameTextInput
library dependency to your game'sbuild.gradle
file. TheGameTextInput
library is included as part ofGameActivity
, so you can skip this step if you're usingGameActivity
.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
If you aren't using
GameActivity
, in your project'sCMakeLists.txt
file, import thegame-text-input
package and add it to your target:find_package(game-text-input REQUIRED CONFIG) ... target_link_libraries(... game-text-input::game-text-input)
In one of the
.cpp
files in your game, add the following line to include theGameTextInput
implementation:#include <game-text-input/gametextinput.cpp>
You may have already performed this step if you integrated
GameActivity
.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 yourCMakeLists.txt
configuration file.#include <game-text-input/gametextinput.h>
Integrate your build
You can integrate GameTextInput
into your build either
with or
without GameActivity
.
Integrating with GameActivity
is the recommended option to have your
implementation in C or C++.
Integrate with GameActivity
Complete the following steps to integrate your build with GameActivity
. Some
of these steps involve the
Endless Tunnel
NDK sample. You may have different UI components and scenes in your game, but
the concept remains the same.
Ensure that your main Java activity extends
GameActivity
as described in Integrate Game Activity.In the following example from Endless Tunnel, create a button
mNameEdit
and useGameInputState
to handle text input.class WelcomeScene : public UiScene { protected: UiWidget* mNameEdit; GameInputState mTextInputState; ... }
Initialize
GameInputState
with default values. In the following example from Endless Tunnel, perform this in theWelcomeScene
constructor.WelcomeScene::WelcomeScene() : mTextInputState{} { mTextInputState.text_UTF8 = INITIAL_NAME; mTextInputState.text_length = strlen(INITIAL_NAME); mTextInputState.selection.start = 0; mTextInputState.selection.end = mTextInputState.text_length; mTextInputState.composingRegion.start = -1; mTextInputState.composingRegion.end = -1; }
Use
GameActivity_setTextInputState
andGameActivity_showSoftInput
to show the keyboard and set the default edit text presented to the user. In the following example from Endless Tunnel, add this when the button is clicked.void WelcomeScene::OnButtonClicked(int id) { if (id == mNameEdit->GetId()) { auto activity = NativeEngine::GetInstance()->GetAndroidApp()->activity; // Note: the UI is resized when the IME is shown and OnCreateWidgets is // called again. sNameEdit = mTextInputState.text_UTF8; mNameEdit->SetText(sNameEdit.c_str()); GameActivity_setTextInputState(activity, &mTextInputState); GameActivity_showSoftInput(activity, 0); }
Use
GameActivity
to listen to a text event. We recommend usingGameActivity
with theandroid_native_app_glue
library, which is bundled withGameActivity
. You can also use it directly with the native callbacks. See the following generic examples for these two different methods:If using with the
android_native_app_glue
library, check in your game loop whether a text input state change occurred:static void yourGameLoop(...) { ... if (mApp->textInputState) { // Handle the event here. See the next step with GameInputState_set // and GameActivity_getTextInputState. } }
If using with native callbacks, register the callback
onTextInputEvent
.// Use the callback that will handle the event: static void onTextInputEvent(GameActivity* activity, const GameInputState* state) { // Store or notify your game thread about the text input. You're not // forced to store the state here, because you can obtain it later. // See the next step. } // Register the callback: JNIEXPORT void GameActivity_onCreate(GameActivity* activity, void* savedState, size_t savedStateSize) { // ... activity->callbacks->onTextInputEvent = onTextInputEvent; }
Use
GameActivity_getTextInputState
,GameInputState_set
to read the text that was entered and store it in memory. You should display this to the user. In the following example, perform this inWelcomeScene::OnTextInputEvent
.void WelcomeScene::OnTextInputEvent() { auto activity = NativeEngine::GetInstance()->GetAndroidApp()->activity; GameInputState_set(&mTextInputState, GameActivity_getTextInputState(activity)); sNameEdit = std::string(mTextInputState.text_UTF8); mNameEdit->SetText(sNameEdit.c_str()); }
Integrate without GameActivity
If you have integrated GameTextInput
with GameActivity
, skip to Utility
Functions.
From your main C thread, call
GameInput_init
with aJNIEnv
pointer.static GameInput* gameInput = nullptr; extern "C" JNIEXPORT void JNICALL Java_com_gameinput_testbed_MainActivity_onCreated(JNIEnv* env, jobject this) { { gameInput = GameInput_init(env); ... }
Create a
InputEnabledTextView
Java class with access toInputConnection
.public class InputEnabledTextView extends View implements Listener { public InputConnection mInputConnection; public void createInputConnection(int inputType) { EditorInfo editorInfo = new EditorInfo(); editorInfo.inputType = inputType; editorInfo.actionId = IME_ACTION_NONE; mInputConnection = new InputConnection(this.getContext(), this, new Settings(editorInfo, true) ).setListener(this); } @Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { if (outAttrs != null) { GameInput.copyEditorInfo(mInputConnection.getEditorInfo(), outAttrs); } return mInputConnection; } // Called when the IME input changes. @Override public void stateChanged(State newState, boolean dismissed) { onTextInputEventNative(newState); } private native void onTextInputEventNative(State softKeyboardEvent); }
Add this new
InputEnabledTextView
class to your Java activity.public class MainActivity extends AppCompatActivity { ... InputEnabledTextView inputEnabledTextView; native void setInputConnectionNative(InputConnection c); @Override protected void onCreate(Bundle savedInstanceState) { ... inputEnabledTextView.createInputConnection(InputType.TYPE_CLASS_TEXT); setInputConnectionNative(inputEnabledTextView.mInputConnection); }
In your C library, pass
inputConnection
intoGameInput_setInputConnection
. Pass a callback inGameInput_setEventCallback
to be notified of events as C state structs.extern "C" JNIEXPORT void JNICALL Java_com_gameinput_testbed_MainActivity_setInputConnectionNative( JNIEnv *env, jobject this, jobject inputConnection) { GameInput_setInputConnection(gameInput, inputConnection); GameInput_setEventCallback(gameInput, onEvent, env); }
In your C library, call
GameInput_processEvent
to handle events when the state changes.extern "C" JNIEXPORT void JNICALL Java_com_gameinput_testbed_InputEnabledTextView_onTextInputEventNative( JNIEnv* env, jobject this, jobject soft_keyboard_event) { GameInput_processEvent(gameInput, 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
GameInput_showIme
and GameInput_hideIme
functions.