fix: unable to exit input when an external keyboard is connected & cannot input continuously

This commit is contained in:
Tungstend 2024-02-25 20:57:56 +08:00
parent ea39dcb123
commit 16967ab508
4 changed files with 63 additions and 36 deletions

View File

@ -96,12 +96,20 @@ public class FCLInput implements View.OnCapturedPointerListener, View.OnGenericM
} }
} }
private View focusableView;
public View getFocusableView() {
return focusableView;
}
public void initExternalController(View view) { public void initExternalController(View view) {
view.setFocusable(true); view.setFocusable(true);
view.setOnCapturedPointerListener(this); view.setOnCapturedPointerListener(this);
view.setOnGenericMotionListener(this); view.setOnGenericMotionListener(this);
view.requestFocus(); view.requestFocus();
view.requestPointerCapture(); view.requestPointerCapture();
this.focusableView = view;
} }
private boolean handleExternalMouseEvent(MotionEvent event) { private boolean handleExternalMouseEvent(MotionEvent event) {
@ -153,13 +161,14 @@ public class FCLInput implements View.OnCapturedPointerListener, View.OnGenericM
@Override @Override
public boolean onGenericMotion(View v, MotionEvent event) { public boolean onGenericMotion(View v, MotionEvent event) {
if (menu instanceof GameMenu && !((GameMenu) menu).getTouchCharInput().isEnabled()) { if (!((GameMenu) menu).getTouchCharInput().isEnabled()) {
((GameMenu) menu).getBaseLayout().requestFocus(); focusableView.requestFocus();
((GameMenu) menu).getBaseLayout().requestPointerCapture(); focusableView.requestPointerCapture();
} }
return true; return true;
} }
public boolean handleKeyEvent(KeyEvent event) { public boolean handleKeyEvent(KeyEvent event) {
int fclKeycode = AndroidKeycodeMap.convertKeycode(event.getKeyCode()); int fclKeycode = AndroidKeycodeMap.convertKeycode(event.getKeyCode());
if (event.getKeyCode() == KeyEvent.KEYCODE_UNKNOWN) if (event.getKeyCode() == KeyEvent.KEYCODE_UNKNOWN)
@ -168,28 +177,30 @@ public class FCLInput implements View.OnCapturedPointerListener, View.OnGenericM
return false; return false;
if (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP) if (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP)
return false; return false;
if (event.getRepeatCount() != 0)
return true;
if (event.getAction() == KeyEvent.ACTION_MULTIPLE) if (event.getAction() == KeyEvent.ACTION_MULTIPLE)
return true; return true;
if (event.getAction() == KeyEvent.ACTION_UP && (event.getFlags() & KeyEvent.FLAG_CANCELED) != 0)
return true;
if (event.getDevice() != null && ((event.getSource() & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE || (event.getSource() & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE)) { if (event.getDevice() != null && ((event.getSource() & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE || (event.getSource() & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE)) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
sendKeyEvent(MOUSE_RIGHT, event.getAction() == KeyEvent.ACTION_DOWN); sendKeyEvent(MOUSE_RIGHT, event.getAction() == KeyEvent.ACTION_DOWN);
return true; return true;
} }
} }
if (event.getKeyCode() == KeyEvent.KEYCODE_ALT_RIGHT && menu.getCursorMode() == FCLBridge.CursorEnabled) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
((GameMenu) menu).getTouchCharInput().switchKeyboardState();
}
return true;
}
if ((event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) == KeyEvent.FLAG_SOFT_KEYBOARD) { if ((event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) == KeyEvent.FLAG_SOFT_KEYBOARD) {
if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)
return true; return true;
((GameMenu) menu).getTouchCharInput().dispatchKeyEvent(event); ((GameMenu) menu).getTouchCharInput().dispatchKeyEvent(event);
return true; return true;
} }
if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
if (!((GameMenu) menu).getTouchCharInput().isLock() && event.getAction() == KeyEvent.ACTION_UP && !((GameMenu) menu).getTouchCharInput().isEnabled()) {
((GameMenu) menu).getTouchCharInput().switchKeyboardState();
} else if (((GameMenu) menu).getTouchCharInput().isLock()) {
((GameMenu) menu).getTouchCharInput().setLock(false);
}
return true;
}
if (fclKeycode == FCLKeycodes.KEY_UNKNOWN) if (fclKeycode == FCLKeycodes.KEY_UNKNOWN)
return (event.getFlags() & KeyEvent.FLAG_FALLBACK) == KeyEvent.FLAG_FALLBACK; return (event.getFlags() & KeyEvent.FLAG_FALLBACK) == KeyEvent.FLAG_FALLBACK;
sendKeyEvent(fclKeycode, event.getAction() == KeyEvent.ACTION_DOWN); sendKeyEvent(fclKeycode, event.getAction() == KeyEvent.ACTION_DOWN);

View File

@ -448,7 +448,7 @@ public class GameMenu implements MenuCallback, View.OnClickListener {
touchPad.post(() -> gameItemBar.setup(this)); touchPad.post(() -> gameItemBar.setup(this));
} }
touchPad.init(this); touchPad.init(this);
touchCharInput.setCharacterSender(new LwjglCharSender(this)); touchCharInput.setCharacterSender(this, new LwjglCharSender(this));
ViewGroup.LayoutParams layoutParams = cursorView.getLayoutParams(); ViewGroup.LayoutParams layoutParams = cursorView.getLayoutParams();
layoutParams.width = ConvertUtils.dip2px(activity, menuSetting.mouseSizeProperty().get()); layoutParams.width = ConvertUtils.dip2px(activity, menuSetting.mouseSizeProperty().get());
layoutParams.height = ConvertUtils.dip2px(activity, menuSetting.mouseSizeProperty().get()); layoutParams.height = ConvertUtils.dip2px(activity, menuSetting.mouseSizeProperty().get());

View File

@ -74,7 +74,7 @@ public class JarExecutorMenu implements MenuCallback, View.OnClickListener, View
touchCharInput = findViewById(R.id.input_scanner); touchCharInput = findViewById(R.id.input_scanner);
touchPad.setOnTouchListener(this); touchPad.setOnTouchListener(this);
logWindow.setVisibilityValue(true); logWindow.setVisibilityValue(true);
touchCharInput.setCharacterSender(new AwtCharSender(awtInput)); touchCharInput.setCharacterSender(null, new AwtCharSender(awtInput));
forceExit = findViewById(R.id.force_exit); forceExit = findViewById(R.id.force_exit);
showLog = findViewById(R.id.show_log); showLog = findViewById(R.id.show_log);

View File

@ -4,16 +4,14 @@ import static android.content.Context.INPUT_METHOD_SERVICE;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.res.Configuration;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import java.util.Objects; import com.tungsten.fcl.control.GameMenu;
/** /**
* From PojavLauncher * From PojavLauncher
@ -21,6 +19,8 @@ import java.util.Objects;
*/ */
public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText { public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText {
public static final String TEXT_FILLER = " ";
public TouchCharInput(@NonNull Context context) { public TouchCharInput(@NonNull Context context) {
this(context, null); this(context, null);
} }
@ -34,9 +34,19 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText
setup(); setup();
} }
private GameMenu menu;
private boolean lock = false;
private boolean isDoingInternalChanges = false; private boolean isDoingInternalChanges = false;
private CharacterSenderStrategy characterSender; private CharacterSenderStrategy characterSender;
public void setLock(boolean lock) {
this.lock = lock;
}
public boolean isLock() {
return lock;
}
/** /**
* We take the new chars, and send them to the game. * We take the new chars, and send them to the game.
* If less chars are present, remove some. * If less chars are present, remove some.
@ -87,26 +97,28 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText
/** /**
* Toggle on and off the soft keyboard, depending of the state * Toggle on and off the soft keyboard, depending of the state
*
* @return if the keyboard is set to be shown.
*/ */
public boolean switchKeyboardState() { public void switchKeyboardState() {
InputMethodManager inputMethodManager = (InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE); InputMethodManager inputMethodManager = (InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE);
// If an hard keyboard is present, never trigger the soft one if (hasFocus()) {
if (hasFocus()
|| (getResources().getConfiguration().keyboard == Configuration.KEYBOARD_QWERTY
&& getResources().getConfiguration().hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES)) {
inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0); inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
clear(); clear();
disable(); disable();
return false; if (menu != null && menu.getInput().getFocusableView() != null) {
menu.getInput().getFocusableView().requestFocus();
menu.getInput().getFocusableView().requestPointerCapture();
}
} else{ } else{
if (menu != null && menu.getInput().getFocusableView() != null) {
menu.getInput().getFocusableView().releasePointerCapture();
menu.getInput().getFocusableView().clearFocus();
}
enable(); enable();
inputMethodManager.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT); inputMethodManager.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT);
return true;
} }
} }
/** /**
* Clear the EditText from any leftover inputs * Clear the EditText from any leftover inputs
* It does not affect the in-game input * It does not affect the in-game input
@ -114,10 +126,8 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
public void clear() { public void clear() {
isDoingInternalChanges = true; isDoingInternalChanges = true;
//Braille space, doesn't trigger keyboard auto-complete setText(TEXT_FILLER);
//replacing directly the text without though setText avoids notifying changes setSelection(TEXT_FILLER.length());
setText(" ");
setSelection(Objects.requireNonNull(getText()).length());
isDoingInternalChanges = false; isDoingInternalChanges = false;
} }
@ -135,8 +145,6 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText
setVisibility(GONE); setVisibility(GONE);
clearFocus(); clearFocus();
setEnabled(false); setEnabled(false);
InputMethodManager inputMethodManager = (InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
} }
/** Send the enter key. */ /** Send the enter key. */
@ -146,16 +154,24 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText
} }
/** Just sets the char sender that should be used. */ /** Just sets the char sender that should be used. */
public void setCharacterSender(CharacterSenderStrategy characterSender) { public void setCharacterSender(GameMenu gameMenu, CharacterSenderStrategy characterSender) {
this.menu = gameMenu;
this.characterSender = characterSender; this.characterSender = characterSender;
} }
/** This function deals with anything that has to be executed when the constructor is called */ /** This function deals with anything that has to be executed when the constructor is called */
private void setup() { private void setup() {
setOnEditorActionListener((textView, i, keyEvent) -> { setOnEditorActionListener((textView, i, keyEvent) -> {
setLock(true);
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getWindowToken(), 0);
sendEnter(); sendEnter();
clear(); clear();
disable(); disable();
if (menu != null && menu.getInput().getFocusableView() != null) {
menu.getInput().getFocusableView().requestFocus();
menu.getInput().getFocusableView().requestPointerCapture();
}
return false; return false;
}); });
clear(); clear();