Skip to content

Commit

Permalink
Android: use real editable text and mimic the edit operations to gene…
Browse files Browse the repository at this point in the history
…rate key events

This fixes issues where the IME and the output would get out of sync
  • Loading branch information
slouken committed Sep 30, 2022
1 parent 1b89591 commit 82e341b
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 41 deletions.
Empty file modified Android.mk
100644 → 100755
Empty file.
174 changes: 133 additions & 41 deletions android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
Expand Down Expand Up @@ -1874,9 +1875,17 @@ public InputConnection onCreateInputConnection(EditorInfo outAttrs) {

class SDLInputConnection extends BaseInputConnection {

protected EditText mEditText;
protected int m_nLastContentLength = 0;

public SDLInputConnection(View targetView, boolean fullEditor) {
super(targetView, fullEditor);
mEditText = new EditText(SDL.getContext());
}

@Override
public Editable getEditable() {
return mEditText.getEditableText();
}

@Override
Expand All @@ -1899,57 +1908,154 @@ public boolean sendKeyEvent(KeyEvent event) {
}
}


return super.sendKeyEvent(event);
}

@Override
public boolean commitText(CharSequence text, int newCursorPosition) {
replaceText(text, newCursorPosition, false);

return super.commitText(text, newCursorPosition);
}

@Override
public boolean setComposingText(CharSequence text, int newCursorPosition) {
replaceText(text, newCursorPosition, true);

/* Generate backspaces for the text we're going to replace */
return super.setComposingText(text, newCursorPosition);
}

@Override
public boolean setComposingRegion(int start, int end) {
final Editable content = getEditable();
if (content != null) {
int a = getComposingSpanStart(content);
int b = getComposingSpanEnd(content);
if (a == -1 || b == -1) {
a = Selection.getSelectionStart(content);
b = Selection.getSelectionEnd(content);
}
if (a < 0) a = 0;
if (b < 0) b = 0;
if (b < a) {
int a = start;
int b = end;
if (a > b) {
int tmp = a;
a = b;
b = tmp;
}
int backspaces = (b - a);

for (int i = 0; i < backspaces; i++) {
nativeGenerateScancodeForUnichar('\b');
// Clip the end points to be within the content bounds.
final int length = content.length();
if (a < 0) {
a = 0;
}
if (b < 0) {
b = 0;
}
if (a > length) {
a = length;
}
if (b > length) {
b = length;
}

deleteText(a, b);
}

for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
if (c == '\n') {
if (SDLActivity.onNativeSoftReturnKey()) {
return true;
return super.setComposingRegion(start, end);
}

@Override
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
final Editable content = getEditable();
if (content != null) {
int a = Selection.getSelectionStart(content);
int b = Selection.getSelectionEnd(content);

if (a > b) {
int tmp = a;
a = b;
b = tmp;
}

// ignore the composing text.
int ca = getComposingSpanStart(content);
int cb = getComposingSpanEnd(content);
if (cb < ca) {
int tmp = ca;
ca = cb;
cb = tmp;
}

if (ca != -1 && cb != -1) {
if (ca < a) {
a = ca;
}
if (cb > b) {
b = cb;
}
}
nativeGenerateScancodeForUnichar(c);
}

SDLInputConnection.nativeCommitText(text.toString(), newCursorPosition);
if (beforeLength > 0) {
int start = a - beforeLength;
if (start < 0) {
start = 0;
}
deleteText(start, a);
}
}

return super.commitText(text, newCursorPosition);
return super.deleteSurroundingText(beforeLength, afterLength);
}

@Override
public boolean setComposingText(CharSequence text, int newCursorPosition) {
protected void replaceText(CharSequence text, int newCursorPosition, boolean composing) {
final Editable content = getEditable();
if (content == null) {
return;
}

// delete composing text set previously.
int a = getComposingSpanStart(content);
int b = getComposingSpanEnd(content);

if (b < a) {
int tmp = a;
a = b;
b = tmp;
}
if (a == -1 || b == -1) {
a = Selection.getSelectionStart(content);
b = Selection.getSelectionEnd(content);
if (a < 0) {
a = 0;
}
if (b < 0) {
b = 0;
}
if (b < a) {
int tmp = a;
a = b;
b = tmp;
}
}

nativeSetComposingText(text.toString(), newCursorPosition);
deleteText(a, b);

return super.setComposingText(text, newCursorPosition);
if (composing) {
nativeSetComposingText(text.toString(), newCursorPosition);
} else {
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
if (c == '\n') {
if (SDLActivity.onNativeSoftReturnKey()) {
return;
}
}
++m_nLastContentLength;
nativeGenerateScancodeForUnichar(c);
}
SDLInputConnection.nativeCommitText(text.toString(), newCursorPosition);
}
}

protected void deleteText(int start, int end) {
while (m_nLastContentLength > start) {
--m_nLastContentLength;
nativeGenerateScancodeForUnichar('\b');
}
}

public static native void nativeCommitText(String text, int newCursorPosition);
Expand All @@ -1958,20 +2064,6 @@ public boolean setComposingText(CharSequence text, int newCursorPosition) {

public native void nativeSetComposingText(String text, int newCursorPosition);

@Override
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
// Workaround to capture backspace key. Ref: http://stackoverflow.com/questions/14560344/android-backspace-in-webview-baseinputconnection
// and https://bugzilla.libsdl.org/show_bug.cgi?id=2265
if (beforeLength > 0 && afterLength == 0) {
// backspace(s)
while (beforeLength-- > 0) {
nativeGenerateScancodeForUnichar('\b');
}
return true;
}

return super.deleteSurroundingText(beforeLength, afterLength);
}
}

class SDLClipboardHandler implements
Expand Down

0 comments on commit 82e341b

Please sign in to comment.