Merge commit '852f2a6343518919e5ca8d3c1bbcab9f493e3cd8'
This commit is contained in:
@ -273,6 +273,7 @@ public class HIDDeviceManager {
|
||||
final int XB1_IFACE_SUBCLASS = 71;
|
||||
final int XB1_IFACE_PROTOCOL = 208;
|
||||
final int[] SUPPORTED_VENDORS = {
|
||||
0x03f0, // HP
|
||||
0x044f, // Thrustmaster
|
||||
0x045e, // Microsoft
|
||||
0x0738, // Mad Catz
|
||||
@ -358,6 +359,12 @@ public class HIDDeviceManager {
|
||||
private void initializeBluetooth() {
|
||||
Log.d(TAG, "Initializing Bluetooth");
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 31 /* Android 12 */ &&
|
||||
mContext.getPackageManager().checkPermission(android.Manifest.permission.BLUETOOTH_CONNECT, mContext.getPackageName()) != PackageManager.PERMISSION_GRANTED) {
|
||||
Log.d(TAG, "Couldn't initialize Bluetooth, missing android.permission.BLUETOOTH_CONNECT");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT <= 30 /* Android 11.0 (R) */ &&
|
||||
mContext.getPackageManager().checkPermission(android.Manifest.permission.BLUETOOTH, mContext.getPackageName()) != PackageManager.PERMISSION_GRANTED) {
|
||||
Log.d(TAG, "Couldn't initialize Bluetooth, missing android.permission.BLUETOOTH");
|
||||
|
@ -23,9 +23,6 @@ import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.text.Editable;
|
||||
import android.text.InputType;
|
||||
import android.text.Selection;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
@ -39,12 +36,9 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.BaseInputConnection;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
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;
|
||||
@ -186,6 +180,14 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
private static final int SDL_SYSTEM_CURSOR_SIZEALL = 9;
|
||||
private static final int SDL_SYSTEM_CURSOR_NO = 10;
|
||||
private static final int SDL_SYSTEM_CURSOR_HAND = 11;
|
||||
private static final int SDL_SYSTEM_CURSOR_WINDOW_TOPLEFT = 12;
|
||||
private static final int SDL_SYSTEM_CURSOR_WINDOW_TOP = 13;
|
||||
private static final int SDL_SYSTEM_CURSOR_WINDOW_TOPRIGHT = 14;
|
||||
private static final int SDL_SYSTEM_CURSOR_WINDOW_RIGHT = 15;
|
||||
private static final int SDL_SYSTEM_CURSOR_WINDOW_BOTTOMRIGHT = 16;
|
||||
private static final int SDL_SYSTEM_CURSOR_WINDOW_BOTTOM = 17;
|
||||
private static final int SDL_SYSTEM_CURSOR_WINDOW_BOTTOMLEFT = 18;
|
||||
private static final int SDL_SYSTEM_CURSOR_WINDOW_LEFT = 19;
|
||||
|
||||
protected static final int SDL_ORIENTATION_UNKNOWN = 0;
|
||||
protected static final int SDL_ORIENTATION_LANDSCAPE = 1;
|
||||
@ -210,7 +212,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
// Main components
|
||||
protected static SDLActivity mSingleton;
|
||||
protected static SDLSurface mSurface;
|
||||
protected static DummyEdit mTextEdit;
|
||||
protected static SDLDummyEdit mTextEdit;
|
||||
protected static boolean mScreenKeyboardShown;
|
||||
protected static ViewGroup mLayout;
|
||||
protected static SDLClipboardHandler mClipboardHandler;
|
||||
@ -238,6 +240,15 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
return mMotionListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a Runnable which invokes SDL_main. The default implementation
|
||||
* uses the getMainSharedObject() and getMainFunction() methods to invoke native
|
||||
* code from the specified shared library.
|
||||
*/
|
||||
protected Runnable createSDLMainRunnable() {
|
||||
return new SDLMain();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the name of the shared object with the application entry point
|
||||
* It can be overridden by derived classes.
|
||||
@ -672,11 +683,11 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
|
||||
// Wait for "SDLThread" thread to end
|
||||
try {
|
||||
// 500ms timeout, because:
|
||||
// Use a timeout because:
|
||||
// C SDLmain() thread might have started (mSDLThread.start() called)
|
||||
// while the SDL_Init() might not have been called yet,
|
||||
// and so the previous QUIT event will be discarded by SDL_Init() and app is running, not exiting.
|
||||
SDLActivity.mSDLThread.join(500);
|
||||
SDLActivity.mSDLThread.join(1000);
|
||||
} catch(Exception e) {
|
||||
Log.v(TAG, "Problem stopping SDLThread: " + e);
|
||||
}
|
||||
@ -777,13 +788,13 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
|
||||
// Try a transition to resumed state
|
||||
if (mNextNativeState == NativeState.RESUMED) {
|
||||
if (mSurface.mIsSurfaceReady && mHasFocus && mIsResumedCalled) {
|
||||
if (mSurface.mIsSurfaceReady && (mHasFocus || mHasMultiWindow) && mIsResumedCalled) {
|
||||
if (mSDLThread == null) {
|
||||
// This is the entry point to the C app.
|
||||
// Start up the C app thread and enable sensor input for the first time
|
||||
// FIXME: Why aren't we enabling sensor input at start?
|
||||
|
||||
mSDLThread = new Thread(new SDLMain(), "SDLThread");
|
||||
mSDLThread = new Thread(SDLActivity.mSingleton.createSDLMainRunnable(), "SDLThread");
|
||||
mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, true);
|
||||
mSDLThread.start();
|
||||
|
||||
@ -799,11 +810,10 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
}
|
||||
|
||||
// Messages from the SDLMain thread
|
||||
static final int COMMAND_CHANGE_TITLE = 1;
|
||||
static final int COMMAND_CHANGE_WINDOW_STYLE = 2;
|
||||
static final int COMMAND_TEXTEDIT_HIDE = 3;
|
||||
static final int COMMAND_SET_KEEP_SCREEN_ON = 5;
|
||||
|
||||
protected static final int COMMAND_CHANGE_TITLE = 1;
|
||||
protected static final int COMMAND_CHANGE_WINDOW_STYLE = 2;
|
||||
protected static final int COMMAND_TEXTEDIT_HIDE = 3;
|
||||
protected static final int COMMAND_SET_KEEP_SCREEN_ON = 5;
|
||||
protected static final int COMMAND_USER = 0x8000;
|
||||
|
||||
protected static boolean mFullscreenModeActive;
|
||||
@ -911,7 +921,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
Handler commandHandler = new SDLCommandHandler();
|
||||
|
||||
// Send a message from the SDLMain thread
|
||||
boolean sendCommand(int command, Object data) {
|
||||
protected boolean sendCommand(int command, Object data) {
|
||||
Message msg = commandHandler.obtainMessage();
|
||||
msg.arg1 = command;
|
||||
msg.obj = data;
|
||||
@ -1123,23 +1133,6 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
* This method is called by SDL using JNI.
|
||||
*/
|
||||
public static boolean shouldMinimizeOnFocusLoss() {
|
||||
/*
|
||||
if (Build.VERSION.SDK_INT >= 24) {
|
||||
if (mSingleton == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mSingleton.isInMultiWindowMode()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mSingleton.isInPictureInPictureMode()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1344,7 +1337,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
params.topMargin = y;
|
||||
|
||||
if (mTextEdit == null) {
|
||||
mTextEdit = new DummyEdit(SDL.getContext());
|
||||
mTextEdit = new SDLDummyEdit(SDL.getContext());
|
||||
|
||||
mLayout.addView(mTextEdit, params);
|
||||
} else {
|
||||
@ -1828,6 +1821,30 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
case SDL_SYSTEM_CURSOR_HAND:
|
||||
cursor_type = 1002; //PointerIcon.TYPE_HAND;
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_WINDOW_TOPLEFT:
|
||||
cursor_type = 1017; //PointerIcon.TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW;
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_WINDOW_TOP:
|
||||
cursor_type = 1015; //PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW;
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_WINDOW_TOPRIGHT:
|
||||
cursor_type = 1016; //PointerIcon.TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW;
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_WINDOW_RIGHT:
|
||||
cursor_type = 1014; //PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW;
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_WINDOW_BOTTOMRIGHT:
|
||||
cursor_type = 1017; //PointerIcon.TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW;
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_WINDOW_BOTTOM:
|
||||
cursor_type = 1015; //PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW;
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_WINDOW_BOTTOMLEFT:
|
||||
cursor_type = 1016; //PointerIcon.TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW;
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_WINDOW_LEFT:
|
||||
cursor_type = 1014; //PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW;
|
||||
break;
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
|
||||
try {
|
||||
@ -1898,11 +1915,11 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
try
|
||||
{
|
||||
class OneShotTask implements Runnable {
|
||||
String mMessage;
|
||||
int mDuration;
|
||||
int mGravity;
|
||||
int mXOffset;
|
||||
int mYOffset;
|
||||
private final String mMessage;
|
||||
private final int mDuration;
|
||||
private final int mGravity;
|
||||
private final int mXOffset;
|
||||
private final int mYOffset;
|
||||
|
||||
OneShotTask(String message, int duration, int gravity, int xOffset, int yOffset) {
|
||||
mMessage = message;
|
||||
@ -1966,186 +1983,6 @@ class SDLMain implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
/* This is a fake invisible editor view that receives the input and defines the
|
||||
* pan&scan region
|
||||
*/
|
||||
class DummyEdit extends View implements View.OnKeyListener {
|
||||
InputConnection ic;
|
||||
|
||||
public DummyEdit(Context context) {
|
||||
super(context);
|
||||
setFocusableInTouchMode(true);
|
||||
setFocusable(true);
|
||||
setOnKeyListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCheckIsTextEditor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||
return SDLActivity.handleKeyEvent(v, keyCode, event, ic);
|
||||
}
|
||||
|
||||
//
|
||||
@Override
|
||||
public boolean onKeyPreIme (int keyCode, KeyEvent event) {
|
||||
// As seen on StackOverflow: http://stackoverflow.com/questions/7634346/keyboard-hide-event
|
||||
// FIXME: Discussion at http://bugzilla.libsdl.org/show_bug.cgi?id=1639
|
||||
// FIXME: This is not a 100% effective solution to the problem of detecting if the keyboard is showing or not
|
||||
// FIXME: A more effective solution would be to assume our Layout to be RelativeLayout or LinearLayout
|
||||
// FIXME: And determine the keyboard presence doing this: http://stackoverflow.com/questions/2150078/how-to-check-visibility-of-software-keyboard-in-android
|
||||
// FIXME: An even more effective way would be if Android provided this out of the box, but where would the fun be in that :)
|
||||
if (event.getAction()==KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
if (SDLActivity.mTextEdit != null && SDLActivity.mTextEdit.getVisibility() == View.VISIBLE) {
|
||||
SDLActivity.onNativeKeyboardFocusLost();
|
||||
}
|
||||
}
|
||||
return super.onKeyPreIme(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
|
||||
ic = new SDLInputConnection(this, true);
|
||||
|
||||
outAttrs.inputType = InputType.TYPE_CLASS_TEXT |
|
||||
InputType.TYPE_TEXT_FLAG_MULTI_LINE;
|
||||
outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI |
|
||||
EditorInfo.IME_FLAG_NO_FULLSCREEN /* API 11 */;
|
||||
|
||||
return ic;
|
||||
}
|
||||
}
|
||||
|
||||
class SDLInputConnection extends BaseInputConnection {
|
||||
|
||||
protected EditText mEditText;
|
||||
protected String mCommittedText = "";
|
||||
|
||||
public SDLInputConnection(View targetView, boolean fullEditor) {
|
||||
super(targetView, fullEditor);
|
||||
mEditText = new EditText(SDL.getContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Editable getEditable() {
|
||||
return mEditText.getEditableText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendKeyEvent(KeyEvent event) {
|
||||
/*
|
||||
* This used to handle the keycodes from soft keyboard (and IME-translated input from hardkeyboard)
|
||||
* However, as of Ice Cream Sandwich and later, almost all soft keyboard doesn't generate key presses
|
||||
* and so we need to generate them ourselves in commitText. To avoid duplicates on the handful of keys
|
||||
* that still do, we empty this out.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Return DOES still generate a key event, however. So rather than using it as the 'click a button' key
|
||||
* as we do with physical keyboards, let's just use it to hide the keyboard.
|
||||
*/
|
||||
|
||||
if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
|
||||
if (SDLActivity.onNativeSoftReturnKey()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return super.sendKeyEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean commitText(CharSequence text, int newCursorPosition) {
|
||||
if (!super.commitText(text, newCursorPosition)) {
|
||||
return false;
|
||||
}
|
||||
updateText();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setComposingText(CharSequence text, int newCursorPosition) {
|
||||
if (!super.setComposingText(text, newCursorPosition)) {
|
||||
return false;
|
||||
}
|
||||
updateText();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
|
||||
if (Build.VERSION.SDK_INT <= 29 /* Android 10.0 (Q) */) {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (!super.deleteSurroundingText(beforeLength, afterLength)) {
|
||||
return false;
|
||||
}
|
||||
updateText();
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void updateText() {
|
||||
final Editable content = getEditable();
|
||||
if (content == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String text = content.toString();
|
||||
int compareLength = Math.min(text.length(), mCommittedText.length());
|
||||
int matchLength, offset;
|
||||
|
||||
/* Backspace over characters that are no longer in the string */
|
||||
for (matchLength = 0; matchLength < compareLength; ) {
|
||||
int codePoint = mCommittedText.codePointAt(matchLength);
|
||||
if (codePoint != text.codePointAt(matchLength)) {
|
||||
break;
|
||||
}
|
||||
matchLength += Character.charCount(codePoint);
|
||||
}
|
||||
/* FIXME: This doesn't handle graphemes, like '🌬️' */
|
||||
for (offset = matchLength; offset < mCommittedText.length(); ) {
|
||||
int codePoint = mCommittedText.codePointAt(offset);
|
||||
nativeGenerateScancodeForUnichar('\b');
|
||||
offset += Character.charCount(codePoint);
|
||||
}
|
||||
|
||||
if (matchLength < text.length()) {
|
||||
String pendingText = text.subSequence(matchLength, text.length()).toString();
|
||||
for (offset = 0; offset < pendingText.length(); ) {
|
||||
int codePoint = pendingText.codePointAt(offset);
|
||||
if (codePoint == '\n') {
|
||||
if (SDLActivity.onNativeSoftReturnKey()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Higher code points don't generate simulated scancodes */
|
||||
if (codePoint < 128) {
|
||||
nativeGenerateScancodeForUnichar((char)codePoint);
|
||||
}
|
||||
offset += Character.charCount(codePoint);
|
||||
}
|
||||
SDLInputConnection.nativeCommitText(pendingText, 0);
|
||||
}
|
||||
mCommittedText = text;
|
||||
}
|
||||
|
||||
public static native void nativeCommitText(String text, int newCursorPosition);
|
||||
|
||||
public static native void nativeGenerateScancodeForUnichar(char c);
|
||||
}
|
||||
|
||||
class SDLClipboardHandler implements
|
||||
ClipboardManager.OnPrimaryClipChangedListener {
|
||||
|
||||
|
62
external/sdl/SDL/android-project/app/src/main/java/org/libsdl/app/SDLDummyEdit.java
vendored
Normal file
62
external/sdl/SDL/android-project/app/src/main/java/org/libsdl/app/SDLDummyEdit.java
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
package org.libsdl.app;
|
||||
|
||||
import android.content.*;
|
||||
import android.text.InputType;
|
||||
import android.view.*;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
|
||||
/* This is a fake invisible editor view that receives the input and defines the
|
||||
* pan&scan region
|
||||
*/
|
||||
public class SDLDummyEdit extends View implements View.OnKeyListener
|
||||
{
|
||||
InputConnection ic;
|
||||
|
||||
public SDLDummyEdit(Context context) {
|
||||
super(context);
|
||||
setFocusableInTouchMode(true);
|
||||
setFocusable(true);
|
||||
setOnKeyListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCheckIsTextEditor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||
return SDLActivity.handleKeyEvent(v, keyCode, event, ic);
|
||||
}
|
||||
|
||||
//
|
||||
@Override
|
||||
public boolean onKeyPreIme (int keyCode, KeyEvent event) {
|
||||
// As seen on StackOverflow: http://stackoverflow.com/questions/7634346/keyboard-hide-event
|
||||
// FIXME: Discussion at http://bugzilla.libsdl.org/show_bug.cgi?id=1639
|
||||
// FIXME: This is not a 100% effective solution to the problem of detecting if the keyboard is showing or not
|
||||
// FIXME: A more effective solution would be to assume our Layout to be RelativeLayout or LinearLayout
|
||||
// FIXME: And determine the keyboard presence doing this: http://stackoverflow.com/questions/2150078/how-to-check-visibility-of-software-keyboard-in-android
|
||||
// FIXME: An even more effective way would be if Android provided this out of the box, but where would the fun be in that :)
|
||||
if (event.getAction()==KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
if (SDLActivity.mTextEdit != null && SDLActivity.mTextEdit.getVisibility() == View.VISIBLE) {
|
||||
SDLActivity.onNativeKeyboardFocusLost();
|
||||
}
|
||||
}
|
||||
return super.onKeyPreIme(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
|
||||
ic = new SDLInputConnection(this, true);
|
||||
|
||||
outAttrs.inputType = InputType.TYPE_CLASS_TEXT |
|
||||
InputType.TYPE_TEXT_FLAG_MULTI_LINE;
|
||||
outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI |
|
||||
EditorInfo.IME_FLAG_NO_FULLSCREEN /* API 11 */;
|
||||
|
||||
return ic;
|
||||
}
|
||||
}
|
||||
|
136
external/sdl/SDL/android-project/app/src/main/java/org/libsdl/app/SDLInputConnection.java
vendored
Normal file
136
external/sdl/SDL/android-project/app/src/main/java/org/libsdl/app/SDLInputConnection.java
vendored
Normal file
@ -0,0 +1,136 @@
|
||||
package org.libsdl.app;
|
||||
|
||||
import android.content.*;
|
||||
import android.os.Build;
|
||||
import android.text.Editable;
|
||||
import android.view.*;
|
||||
import android.view.inputmethod.BaseInputConnection;
|
||||
import android.widget.EditText;
|
||||
|
||||
public class SDLInputConnection extends BaseInputConnection
|
||||
{
|
||||
protected EditText mEditText;
|
||||
protected String mCommittedText = "";
|
||||
|
||||
public SDLInputConnection(View targetView, boolean fullEditor) {
|
||||
super(targetView, fullEditor);
|
||||
mEditText = new EditText(SDL.getContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Editable getEditable() {
|
||||
return mEditText.getEditableText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendKeyEvent(KeyEvent event) {
|
||||
/*
|
||||
* This used to handle the keycodes from soft keyboard (and IME-translated input from hardkeyboard)
|
||||
* However, as of Ice Cream Sandwich and later, almost all soft keyboard doesn't generate key presses
|
||||
* and so we need to generate them ourselves in commitText. To avoid duplicates on the handful of keys
|
||||
* that still do, we empty this out.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Return DOES still generate a key event, however. So rather than using it as the 'click a button' key
|
||||
* as we do with physical keyboards, let's just use it to hide the keyboard.
|
||||
*/
|
||||
|
||||
if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
|
||||
if (SDLActivity.onNativeSoftReturnKey()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return super.sendKeyEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean commitText(CharSequence text, int newCursorPosition) {
|
||||
if (!super.commitText(text, newCursorPosition)) {
|
||||
return false;
|
||||
}
|
||||
updateText();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setComposingText(CharSequence text, int newCursorPosition) {
|
||||
if (!super.setComposingText(text, newCursorPosition)) {
|
||||
return false;
|
||||
}
|
||||
updateText();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
|
||||
if (Build.VERSION.SDK_INT <= 29 /* Android 10.0 (Q) */) {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (!super.deleteSurroundingText(beforeLength, afterLength)) {
|
||||
return false;
|
||||
}
|
||||
updateText();
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void updateText() {
|
||||
final Editable content = getEditable();
|
||||
if (content == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String text = content.toString();
|
||||
int compareLength = Math.min(text.length(), mCommittedText.length());
|
||||
int matchLength, offset;
|
||||
|
||||
/* Backspace over characters that are no longer in the string */
|
||||
for (matchLength = 0; matchLength < compareLength; ) {
|
||||
int codePoint = mCommittedText.codePointAt(matchLength);
|
||||
if (codePoint != text.codePointAt(matchLength)) {
|
||||
break;
|
||||
}
|
||||
matchLength += Character.charCount(codePoint);
|
||||
}
|
||||
/* FIXME: This doesn't handle graphemes, like '🌬️' */
|
||||
for (offset = matchLength; offset < mCommittedText.length(); ) {
|
||||
int codePoint = mCommittedText.codePointAt(offset);
|
||||
nativeGenerateScancodeForUnichar('\b');
|
||||
offset += Character.charCount(codePoint);
|
||||
}
|
||||
|
||||
if (matchLength < text.length()) {
|
||||
String pendingText = text.subSequence(matchLength, text.length()).toString();
|
||||
for (offset = 0; offset < pendingText.length(); ) {
|
||||
int codePoint = pendingText.codePointAt(offset);
|
||||
if (codePoint == '\n') {
|
||||
if (SDLActivity.onNativeSoftReturnKey()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Higher code points don't generate simulated scancodes */
|
||||
if (codePoint < 128) {
|
||||
nativeGenerateScancodeForUnichar((char)codePoint);
|
||||
}
|
||||
offset += Character.charCount(codePoint);
|
||||
}
|
||||
SDLInputConnection.nativeCommitText(pendingText, 0);
|
||||
}
|
||||
mCommittedText = text;
|
||||
}
|
||||
|
||||
public static native void nativeCommitText(String text, int newCursorPosition);
|
||||
|
||||
public static native void nativeGenerateScancodeForUnichar(char c);
|
||||
}
|
||||
|
@ -164,13 +164,10 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
||||
}
|
||||
}
|
||||
|
||||
// Don't skip in MultiWindow.
|
||||
// Don't skip if we might be multi-window or have popup dialogs
|
||||
if (skip) {
|
||||
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
|
||||
if (SDLActivity.mSingleton.isInMultiWindowMode()) {
|
||||
Log.v("SDL", "Don't skip in Multi-Window");
|
||||
skip = false;
|
||||
}
|
||||
skip = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,6 +193,24 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
||||
return SDLActivity.handleKeyEvent(v, keyCode, event, null);
|
||||
}
|
||||
|
||||
private float getNormalizedX(float x)
|
||||
{
|
||||
if (mWidth <= 1) {
|
||||
return 0.5f;
|
||||
} else {
|
||||
return (x / (mWidth - 1));
|
||||
}
|
||||
}
|
||||
|
||||
private float getNormalizedY(float y)
|
||||
{
|
||||
if (mHeight <= 1) {
|
||||
return 0.5f;
|
||||
} else {
|
||||
return (y / (mHeight - 1));
|
||||
}
|
||||
}
|
||||
|
||||
// Touch events
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
@ -242,8 +257,8 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
for (i = 0; i < pointerCount; i++) {
|
||||
pointerFingerId = event.getPointerId(i);
|
||||
x = event.getX(i) / mWidth;
|
||||
y = event.getY(i) / mHeight;
|
||||
x = getNormalizedX(event.getX(i));
|
||||
y = getNormalizedY(event.getY(i));
|
||||
p = event.getPressure(i);
|
||||
if (p > 1.0f) {
|
||||
// may be larger than 1.0f on some devices
|
||||
@ -267,8 +282,8 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
||||
}
|
||||
|
||||
pointerFingerId = event.getPointerId(i);
|
||||
x = event.getX(i) / mWidth;
|
||||
y = event.getY(i) / mHeight;
|
||||
x = getNormalizedX(event.getX(i));
|
||||
y = getNormalizedY(event.getY(i));
|
||||
p = event.getPressure(i);
|
||||
if (p > 1.0f) {
|
||||
// may be larger than 1.0f on some devices
|
||||
@ -281,8 +296,8 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
for (i = 0; i < pointerCount; i++) {
|
||||
pointerFingerId = event.getPointerId(i);
|
||||
x = event.getX(i) / mWidth;
|
||||
y = event.getY(i) / mHeight;
|
||||
x = getNormalizedX(event.getX(i));
|
||||
y = getNormalizedY(event.getY(i));
|
||||
p = event.getPressure(i);
|
||||
if (p > 1.0f) {
|
||||
// may be larger than 1.0f on some devices
|
||||
|
Reference in New Issue
Block a user