commit 92c7a40427ea88fadea4bfd9758d517ace22b7eb Author: Artyom Palvelev Date: Tue Feb 14 11:39:16 2023 +0000 fix hardware keyboard support fix for key events not being passed to InputConnection, which is attached to the main Activity's surface Bug: 262555636 Test: connect a hardware keyboard, run AGDKTunnel and try typing player name Change-Id: If55b371557f103288253958053597fa98af4f2b0 diff --git a/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java b/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java index 0ac91ac603bb..2bf78e375e7a 100644 --- a/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java +++ b/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java @@ -84,6 +84,8 @@ public class InputConnection // Listen for insets changes WindowCompat.setDecorFitsSystemWindows(((Activity)targetView.getContext()).getWindow(), false); ViewCompat.setOnApplyWindowInsetsListener(targetView, this); + + targetView.setOnKeyListener(this); } /** commit 140cb55df2f45411cf967c8f031deefa13cf516e Author: Artyom Palvelev Date: Thu Jun 15 15:07:22 2023 +0100 fix for hardware and software keyboards being out of sync IMM was not properly updated after processKeyEvent() updated the Editable. Bug: b/280409354, b/273978128 Test: connect the hardware kb, open AGDKTunnel and type player name with sw and hw keyboards. Change-Id: I69b477bfae03426af1abff92449ff62133e25627 diff --git a/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java b/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java index 2bf78e375e7a..d0bba2e95574 100644 --- a/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java +++ b/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java @@ -207,13 +207,8 @@ public class InputConnection // From BaseInputConnection @Override public boolean setComposingText(CharSequence text, int newCursorPosition) { - Log.d(TAG, - (new StringBuilder()) - .append("setComposingText: '") - .append(text) - .append("', newCursorPosition=") - .append(newCursorPosition) - .toString()); + Log.d(TAG, String.format("setComposingText='%s' newCursorPosition=%d", + text, newCursorPosition)); if (text == null) { return false; } else { @@ -378,17 +373,21 @@ public class InputConnection } private final void setComposingRegionInternal(int start_in, int end_in) { - if (start_in == -1) { + // start_in might be greater than end_in + int start = Math.min(start_in, end_in); + int end = Math.max(start_in, end_in); + + if (start == -1) { GameTextInput.removeComposingRegion(this.mEditable); } else { - int start = Math.min(this.mEditable.length(), Math.max(0, start_in)); - int end = Math.min(this.mEditable.length(), Math.max(0, end_in)); + start = Math.min(this.mEditable.length(), Math.max(0, start)); + end = Math.min(this.mEditable.length(), Math.max(0, end)); GameTextInput.setComposingRegion(this.mEditable, start, end); } } private boolean processKeyEvent(KeyEvent event) { - Log.d(TAG, "sendKeyEvent"); + Log.d(TAG, "processKeyEvent"); Pair selection = this.getSelection(); if (event == null) { return false; @@ -417,8 +416,26 @@ public class InputConnection if (!dontInsertChars.get(code)) { this.mEditable.insert( selection.first, (CharSequence) Character.toString((char) event.getUnicodeChar())); - int new_cursor = selection.first + 1; - GameTextInput.setSelection(this.mEditable, new_cursor, new_cursor); + int length = this.mEditable.length(); + + // Same logic as in setComposingText(): we must update composing region, + // so make sure it points to a valid range. + Pair composingRegion = this.getComposingRegion(); + if (composingRegion.first == -1) { + composingRegion = this.getSelection(); + if (composingRegion.first == -1) { + composingRegion = new Pair(0, 0); + } + } + + // IMM seems to cache set content of Editable, so we update it with restartInput + // Also it caches selection and composing region, so let's notify it about updates. + composingRegion.second = composingRegion.first + length; + this.setComposingRegion(composingRegion.first, composingRegion.second); + int new_cursor = composingRegion.second; + setSelectionInternal(new_cursor, new_cursor); + this.informIMM(); + this.restartInput(); } this.stateUpdated(false); commit cd73cee28208852f2113727819400bc900cb4583 Author: Artyom Palvelev Date: Thu Aug 31 13:04:57 2023 +0100 fixed multiline mode GameTextInput settings weren't properly propagated on state changes. Bug: b/276725330 Test: modify AGDKTunnel to use multiline mode and run Change-Id: I5414d4ab3dce756b5cb2b4e91711b504b48b00c9 diff --git a/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java b/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java index d13f918c39ed..3d0f05a77ad2 100644 --- a/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java +++ b/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java @@ -126,13 +126,8 @@ public class InputConnection // Listen for insets changes WindowCompat.setDecorFitsSystemWindows(((Activity)targetView.getContext()).getWindow(), false); targetView.setOnKeyListener(this); - - if ((settings.mEditorInfo.inputType & EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE) == 0) { - mEditable.setFilters(new InputFilter[]{ - new InputFilter.LengthFilter(MAX_LENGTH_FOR_SINGLE_LINE_EDIT_TEXT), - new SingeLineFilter() - }); - } + // Apply EditorInfo settings + this.setEditorInfo(settings.mEditorInfo); } /** @@ -185,6 +180,18 @@ public class InputConnection */ public final void setEditorInfo(EditorInfo editorInfo) { this.settings.mEditorInfo = editorInfo; + + // Depending on the multiline state, we might need a different set of filters. + // Filters are being used to filter specific characters for hardware keyboards + // (software input methods already support TYPE_TEXT_FLAG_MULTI_LINE). + if ((settings.mEditorInfo.inputType & EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE) == 0) { + mEditable.setFilters(new InputFilter[]{ + new InputFilter.LengthFilter(MAX_LENGTH_FOR_SINGLE_LINE_EDIT_TEXT), + new SingeLineFilter() + }); + } else { + mEditable.setFilters(new InputFilter[]{ }); + } } /** commit d238783e34976b76c6cfb199450afd492a9e329e Author: Artyom Palvelev Date: Wed Sep 13 15:09:51 2023 +0100 add physical volume buttons to the ignore list for GameTextInput Also fix the behavior so that the default system action is applied in case we don't handle the key. Fix: 289014222 Test: run AGDKTunnel Change-Id: Id62955e9a650f10d31b60be770f8be8f42fe1a02 diff --git a/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java b/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java index 7d5d7c6d2a6f..837c1b8d989b 100644 --- a/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java +++ b/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java @@ -51,7 +51,8 @@ public class InputConnection KeyEvent.KEYCODE_DPAD_CENTER, KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_DOWN_LEFT, KeyEvent.KEYCODE_DPAD_UP_LEFT, KeyEvent.KEYCODE_DPAD_UP_LEFT, KeyEvent.KEYCODE_DPAD_UP_RIGHT, - KeyEvent.KEYCODE_BACK}; + KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_DOWN, + KeyEvent.KEYCODE_VOLUME_MUTE, KeyEvent.KEYCODE_VOLUME_MUTE}; private final InputMethodManager imm; private final View targetView; private final Settings settings; @@ -481,10 +482,11 @@ public class InputConnection setSelectionInternal(new_cursor, new_cursor); this.informIMM(); this.restartInput(); + this.stateUpdated(false); + return true; + } else { + return false; } - - this.stateUpdated(false); - return true; } } commit b2f598f0ad85035dba90ea13cabe6e4e99cfa902 Author: Artyom Palvelev Date: Fri Sep 15 13:00:43 2023 +0100 fix GameTextInput editing functions The implementation was broken during refactoring. Fix: 300465694 Test: run AGDKTunnel and test edit box Change-Id: I011397d924d2b75b8039d6fa1cc81bd9b8dc947e diff --git a/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java b/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java index 837c1b8d989b..76f3a7181fe0 100644 --- a/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java +++ b/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java @@ -323,9 +323,25 @@ public class InputConnection @Override public boolean deleteSurroundingText(int beforeLength, int afterLength) { Log.d(TAG, "deleteSurroundingText: " + beforeLength + ":" + afterLength); - boolean res = super.deleteSurroundingText(beforeLength, afterLength); + Pair selection = this.getSelection(); + int first = Math.min(selection.first, selection.second); + int second = Math.max(selection.first, selection.second); + + if (first == -1) { + return false; + } + + if (afterLength > 0) { + this.mEditable.delete(Math.max(0, second), + Math.min(this.mEditable.length(), second - afterLength)); + } + + if (beforeLength > 0) { + this.mEditable.delete(Math.max(0, first - beforeLength), first); + } + this.stateUpdated(false); - return res; + return true; } // From BaseInputConnection @@ -453,9 +469,13 @@ public class InputConnection this.mEditable.delete(selection.first, selection.second); } else if (event.getKeyCode() == KeyEvent.KEYCODE_DEL && selection.first > 0) { this.mEditable.delete(selection.first - 1, selection.first); + this.stateUpdated(false); + return true; } else if (event.getKeyCode() == KeyEvent.KEYCODE_FORWARD_DEL && selection.first < this.mEditable.length() - 1) { this.mEditable.delete(selection.first, selection.first + 1); + this.stateUpdated(false); + return true; } int code = event.getKeyCode(); commit 18fc8e25c509e891df2cc26fed61ef159670fff0 Author: Artyom Palvelev Date: Fri Sep 15 17:33:30 2023 +0100 fix a race condition in GameTextInput This commit fixes the problem with concurrent access to the currentState_ variable in gametextinput.cpp. A mutex has been added to guarantee safe multithreaded access to it. Fix: 294112477 Test: N/A Change-Id: I09729504c863217fe5530bc980e83655c979d461 diff --git a/game-text-input/prefab-src/modules/game-text-input/include/game-text-input/gametextinput.cpp b/game-text-input/prefab-src/modules/game-text-input/include/game-text-input/gametextinput.cpp index 98d8f7cb4239..278b48221772 100644 --- a/game-text-input/prefab-src/modules/game-text-input/include/game-text-input/gametextinput.cpp +++ b/game-text-input/prefab-src/modules/game-text-input/include/game-text-input/gametextinput.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #define LOG_TAG "GameTextInput" @@ -43,7 +44,10 @@ struct GameTextInput { GameTextInput(JNIEnv *env, uint32_t max_string_size); ~GameTextInput(); void setState(const GameTextInputState &state); - const GameTextInputState &getState() const { return currentState_; } + GameTextInputState getState() const { + std::lock_guard lock(currentStateMutex_); + return currentState_; + } void setInputConnection(jobject inputConnection); void processEvent(jobject textInputEvent); void showIme(uint32_t flags); @@ -69,6 +73,8 @@ struct GameTextInput { jclass stateJavaClass_ = nullptr; // The latest text input update. GameTextInputState currentState_ = {}; + // A mutex to protect currentState_. + mutable std::mutex currentStateMutex_; // An instance of gametextinput.InputConnection. jclass inputConnectionClass_ = nullptr; jobject inputConnection_ = nullptr; @@ -142,7 +148,8 @@ void GameTextInput_setState(GameTextInput *input, void GameTextInput_getState(GameTextInput *input, GameTextInputGetStateCallback callback, void *context) { - callback(context, &input->getState()); + GameTextInputState state = input->getState(); + callback(context, &state); } void GameTextInput_setInputConnection(GameTextInput *input, @@ -245,6 +252,8 @@ void GameTextInput::setState(const GameTextInputState &state) { } void GameTextInput::setStateInner(const GameTextInputState &state) { + std::lock_guard lock(currentStateMutex_); + // Check if we're setting using our own string (other parts may be // different) if (state.text_UTF8 == currentState_.text_UTF8) { @@ -280,6 +289,7 @@ void GameTextInput::setInputConnection(jobject inputConnection) { void GameTextInput::processEvent(jobject textInputEvent) { stateFromJava(textInputEvent, processCallback, this); if (eventCallback_) { + std::lock_guard lock(currentStateMutex_); eventCallback_(eventCallbackContext_, ¤tState_); } } diff --git a/game-text-input/prefab-src/modules/game-text-input/include/game-text-input/gametextinput.h b/game-text-input/prefab-src/modules/game-text-input/include/game-text-input/gametextinput.h index c37fd92eee98..1c79ae7f582a 100644 --- a/game-text-input/prefab-src/modules/game-text-input/include/game-text-input/gametextinput.h +++ b/game-text-input/prefab-src/modules/game-text-input/include/game-text-input/gametextinput.h @@ -229,6 +229,9 @@ typedef void (*GameTextInputEventCallback)( * @param input A valid GameTextInput library handle. * @param callback Called by the library when the IME state changes. * @param context Context passed as first argument to the callback. + * This function is deprecated. Don't perform any complex processing inside + * the callback other than copying the state variable. Using any synchronization + * primitives inside this callback may cause a deadlock. */ void GameTextInput_setEventCallback(GameTextInput *input, GameTextInputEventCallback callback, commit dfca49441b074e6384ce321f46f34d42505f981e Author: Artyom Palvelev Date: Wed Oct 18 16:39:02 2023 +0100 refactor GameActivity and GameTextInput interfaces These changes are made to address the feedback by NDK Council review. This CL does not change behavior of these libraries. Mostly these changes are cosmetic. Since we changed API earlier (GameActivityMotionEvent structure), we bump major versions of GameActivity and GameTextInput. Since we're making a major release, we fix a few other interfaces: * onEditorAction changes its return type from boolean to void * setImeEditorInfo now expects enum parameters, not integers * some code has been moved from GameActivityMotionEvent_fromJava into onTouchEvent_native * internal functions of GameActivityEvents are moved into GameActivityEvents_internal.h. Fix: 301147938 Test: run AGDKSample or any other sample Change-Id: I97d0479bd3bfaf137505258abb681528491abae0 diff --git a/game-text-input/prefab-src/modules/game-text-input/include/game-text-input/gametextinput.h b/game-text-input/prefab-src/modules/game-text-input/include/game-text-input/gametextinput.h index 1c79ae7f582a..8a30b936f960 100644 --- a/game-text-input/prefab-src/modules/game-text-input/include/game-text-input/gametextinput.h +++ b/game-text-input/prefab-src/modules/game-text-input/include/game-text-input/gametextinput.h @@ -302,10 +302,6 @@ void GameTextInputState_fromJava(const GameTextInput *input, jobject state, void *context); -/* - * Below there are definitions for arguments of GameActivity_setImeEditorInfo(). - */ - /** * Definitions for inputType argument of GameActivity_setImeEditorInfo() * @@ -355,7 +351,7 @@ void GameTextInputState_fromJava(const GameTextInput *input, jobject state, * |-------|-------|-------|-------| */ -enum { +enum GameTextInputType : unsigned int { /** * Mask of bits that determine the overall class * of text being given. Currently supported classes are: @@ -701,7 +697,7 @@ enum { }; /** - * Masks for imeOptions argument of GameActivity_setImeEditorInfo(). + * actionId and imeOptions argument of GameActivity_setImeEditorInfo(). * *
  * |-------|-------|-------|-------|
@@ -726,7 +722,7 @@ enum {
  * |-------|-------|-------|-------|
*/ -enum { +enum GameTextInputActionType : unsigned int { /** * Set of bits in {@link #imeOptions} that provide alternative actions * associated with the "enter" key. This both helps the IME provide @@ -788,7 +784,9 @@ enum { * can be returned to the app if it sets {@link #IME_FLAG_NAVIGATE_PREVIOUS}. */ IME_ACTION_PREVIOUS = 0x00000007, +}; +enum GameTextInputImeOptions : unsigned int { /** * Flag of {@link #imeOptions}: used to request that the IME should not update any personalized * data such as typing history and personalized language model based on what the user typed on diff --git a/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java b/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java index 76f3a7181fe0..33e95ca3b344 100644 --- a/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java +++ b/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java @@ -587,9 +587,10 @@ public class InputConnection @Override public boolean performEditorAction(int action) { if (listener != null) { - return listener.onEditorAction(action); - } else { + listener.onEditorAction(action); return true; + } else { + return false; } } } diff --git a/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/Listener.java b/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/Listener.java index 2c71f2a212f0 ..ff2b4fba3126 100644 --- a/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/Listener.java +++ b/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/Listener.java @@ -52,6 +52,6 @@ public interface Listener { * * @param action Code of the action. A default action is IME_ACTION_DONE. */ - boolean onEditorAction(int action); + void onEditorAction(int action); } commit f1f286b6486ec02fb11eabf4b90664e8b98c4052 Author: Artyom Palvelev Date: Tue Dec 5 15:44:37 2023 +0000 fix text deletion in GameTextInput fix a bug caused by a typo in deleteSurroundingText. Note that the behavior should be the same as in the default handler, BaseInputConnection.deleteSurroundingText(). Test: N/A Fix: 314826655 Change-Id: Ieb56022f18b081fe3d911ae9ebbd827f3440650a diff --git a/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java b/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java index 39582569d084..273b201f5277 100644 --- a/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java +++ b/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java @@ -341,7 +341,7 @@ public class InputConnection if (afterLength > 0) { this.mEditable.delete(Math.max(0, second), - Math.min(this.mEditable.length(), second - afterLength)); + Math.min(this.mEditable.length(), second + afterLength)); } if (beforeLength > 0) { commit 094b21ff9b457e8e11156ec49f804924458a470d Author: Artyom Palvelev Date: Wed Mar 20 17:52:21 2024 +0000 fix selection when typing with hardware keyboard Selection interval haven't been updated correctly in cases when characters are inserted not at the end of the string. Test: build and run AGDKTunnel and test that typing works Fix: 329405226 (cherry picked from https://android-review.googlesource.com/q/commit:5dec41615db92250a0daf80a95d32b83ba8516fb) Merged-In: Idafaae29d87c841d0909282f53f9bd8404114154 Change-Id: Idafaae29d87c841d0909282f53f9bd8404114154 diff --git a/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java b/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java index 469897bf5c06..07aa9f3c9b93 100644 --- a/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java +++ b/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java @@ -517,8 +517,9 @@ public class InputConnection int code = event.getKeyCode(); if (!dontInsertChars.get(code)) { + String charsToInsert = Character.toString((char) event.getUnicodeChar()); this.mEditable.insert( - selection.first, (CharSequence) Character.toString((char) event.getUnicodeChar())); + selection.first, (CharSequence) charsToInsert); int length = this.mEditable.length(); // Same logic as in setComposingText(): we must update composing region, @@ -531,11 +532,11 @@ public class InputConnection } } - // IMM seems to cache set content of Editable, so we update it with restartInput + // IMM seems to cache the content of Editable, so we update it with restartInput // Also it caches selection and composing region, so let's notify it about updates. composingRegion.second = composingRegion.first + length; this.setComposingRegion(composingRegion.first, composingRegion.second); - int new_cursor = composingRegion.second; + int new_cursor = selection.first + charsToInsert.length(); setSelectionInternal(new_cursor, new_cursor); this.informIMM(); this.restartInput(); commit 8bee4e62f5c6e0490f3643051aa3a05ed28b9f27 Author: Artyom Palvelev Date: Wed Mar 20 20:37:05 2024 +0000 fixed state updates propagation State updates should be always propagated, because logic of the text editor should not depend on visibility of IME. Bug: N/A Test: build and run game_test_input_testbed (cherry picked from https://android-review.googlesource.com/q/commit:ebafbf53d267673fa35282431f94756e2310976e) Merged-In: Iae9ca0921e648ad2aa93aad90bb412c5a4296b98 Change-Id: Iae9ca0921e648ad2aa93aad90bb412c5a4296b98 diff --git a/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java b/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java index 07aa9f3c9b93..70527626fa8b 100644 --- a/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java +++ b/game-text-input/src/main/java/com/google/androidgamesdk/gametextinput/InputConnection.java @@ -557,9 +557,9 @@ public class InputConnection // Keep a reference to the listener to avoid a race condition when setting the listener. Listener listener = this.listener; - // Only propagate the state change when the keyboard is set to active. - // If we d on't do this, 'back' events can be passed unnecessarily. - if (listener != null && this.mSoftKeyboardActive) { + // We always propagate state change events because unfortunately keyboard visibility functions + // are unreliable, and text editor logic should not depend on them. + if (listener != null) { listener.stateChanged(state, dismissed); } } commit 80739abf3623b33fd9abb06553fa6abdfe45abc1 Author: Artyom Palvelev Date: Tue Apr 9 16:16:30 2024 +0100 bump GameActivity and GameTextInput to 3.0.3 We release new versions of both libraries in order to integrate a fix for https://buganizer.corp.google.com/issues/314924320 Bug: 314924320 Test: N/A (cherry picked from https://android-review.googlesource.com/q/commit:33d08d318c1bc5d0a62d7c99aa4ee9ca785609c6) Merged-In: Id72a07ac7c65059b2b9b83a43d0e06a8731e7a00 Change-Id: Id72a07ac7c65059b2b9b83a43d0e06a8731e7a00 diff --git a/game-text-input/prefab-src/modules/game-text-input/include/game-text-input/gametextinput.h b/game-text-input/prefab-src/modules/game-text-input/include/game-text-input/gametextinput.h index 47c95a4bdc46..1a3136b8eb01 100644 --- a/game-text-input/prefab-src/modules/game-text-input/include/game-text-input/gametextinput.h +++ b/game-text-input/prefab-src/modules/game-text-input/include/game-text-input/gametextinput.h @@ -35,7 +35,7 @@ extern "C" { #define GAMETEXTINPUT_MAJOR_VERSION 3 #define GAMETEXTINPUT_MINOR_VERSION 0 -#define GAMETEXTINPUT_BUGFIX_VERSION 2 +#define GAMETEXTINPUT_BUGFIX_VERSION 3 #define GAMETEXTINPUT_PACKED_VERSION \ ANDROID_GAMESDK_PACKED_VERSION(GAMETEXTINPUT_MAJOR_VERSION, \ GAMETEXTINPUT_MINOR_VERSION, \