From 16967ab508bd3abe75699bd04d907cbe675850d0 Mon Sep 17 00:00:00 2001 From: Tungstend Date: Sun, 25 Feb 2024 20:57:56 +0800 Subject: [PATCH] fix: unable to exit input when an external keyboard is connected & cannot input continuously --- .../com/tungsten/fcl/control/FCLInput.java | 33 ++++++---- .../com/tungsten/fcl/control/GameMenu.java | 2 +- .../tungsten/fcl/control/JarExecutorMenu.java | 2 +- .../fcl/control/keyboard/TouchCharInput.java | 62 ++++++++++++------- 4 files changed, 63 insertions(+), 36 deletions(-) diff --git a/FCL/src/main/java/com/tungsten/fcl/control/FCLInput.java b/FCL/src/main/java/com/tungsten/fcl/control/FCLInput.java index 602874cc..b1cc946e 100644 --- a/FCL/src/main/java/com/tungsten/fcl/control/FCLInput.java +++ b/FCL/src/main/java/com/tungsten/fcl/control/FCLInput.java @@ -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) { view.setFocusable(true); view.setOnCapturedPointerListener(this); view.setOnGenericMotionListener(this); view.requestFocus(); view.requestPointerCapture(); + + this.focusableView = view; } private boolean handleExternalMouseEvent(MotionEvent event) { @@ -153,13 +161,14 @@ public class FCLInput implements View.OnCapturedPointerListener, View.OnGenericM @Override public boolean onGenericMotion(View v, MotionEvent event) { - if (menu instanceof GameMenu && !((GameMenu) menu).getTouchCharInput().isEnabled()) { - ((GameMenu) menu).getBaseLayout().requestFocus(); - ((GameMenu) menu).getBaseLayout().requestPointerCapture(); + if (!((GameMenu) menu).getTouchCharInput().isEnabled()) { + focusableView.requestFocus(); + focusableView.requestPointerCapture(); } return true; } + public boolean handleKeyEvent(KeyEvent event) { int fclKeycode = AndroidKeycodeMap.convertKeycode(event.getKeyCode()); if (event.getKeyCode() == KeyEvent.KEYCODE_UNKNOWN) @@ -168,28 +177,30 @@ public class FCLInput implements View.OnCapturedPointerListener, View.OnGenericM return false; if (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP) return false; - if (event.getRepeatCount() != 0) - return true; if (event.getAction() == KeyEvent.ACTION_MULTIPLE) 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.getKeyCode() == KeyEvent.KEYCODE_BACK) { sendKeyEvent(MOUSE_RIGHT, event.getAction() == KeyEvent.ACTION_DOWN); 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.getKeyCode() == KeyEvent.KEYCODE_ENTER) return true; ((GameMenu) menu).getTouchCharInput().dispatchKeyEvent(event); 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) return (event.getFlags() & KeyEvent.FLAG_FALLBACK) == KeyEvent.FLAG_FALLBACK; sendKeyEvent(fclKeycode, event.getAction() == KeyEvent.ACTION_DOWN); diff --git a/FCL/src/main/java/com/tungsten/fcl/control/GameMenu.java b/FCL/src/main/java/com/tungsten/fcl/control/GameMenu.java index dba176d5..43835f01 100644 --- a/FCL/src/main/java/com/tungsten/fcl/control/GameMenu.java +++ b/FCL/src/main/java/com/tungsten/fcl/control/GameMenu.java @@ -448,7 +448,7 @@ public class GameMenu implements MenuCallback, View.OnClickListener { touchPad.post(() -> gameItemBar.setup(this)); } touchPad.init(this); - touchCharInput.setCharacterSender(new LwjglCharSender(this)); + touchCharInput.setCharacterSender(this, new LwjglCharSender(this)); ViewGroup.LayoutParams layoutParams = cursorView.getLayoutParams(); layoutParams.width = ConvertUtils.dip2px(activity, menuSetting.mouseSizeProperty().get()); layoutParams.height = ConvertUtils.dip2px(activity, menuSetting.mouseSizeProperty().get()); diff --git a/FCL/src/main/java/com/tungsten/fcl/control/JarExecutorMenu.java b/FCL/src/main/java/com/tungsten/fcl/control/JarExecutorMenu.java index 5504d1a6..37619b4b 100644 --- a/FCL/src/main/java/com/tungsten/fcl/control/JarExecutorMenu.java +++ b/FCL/src/main/java/com/tungsten/fcl/control/JarExecutorMenu.java @@ -74,7 +74,7 @@ public class JarExecutorMenu implements MenuCallback, View.OnClickListener, View touchCharInput = findViewById(R.id.input_scanner); touchPad.setOnTouchListener(this); logWindow.setVisibilityValue(true); - touchCharInput.setCharacterSender(new AwtCharSender(awtInput)); + touchCharInput.setCharacterSender(null, new AwtCharSender(awtInput)); forceExit = findViewById(R.id.force_exit); showLog = findViewById(R.id.show_log); diff --git a/FCL/src/main/java/com/tungsten/fcl/control/keyboard/TouchCharInput.java b/FCL/src/main/java/com/tungsten/fcl/control/keyboard/TouchCharInput.java index 392fe474..42e3a3ec 100644 --- a/FCL/src/main/java/com/tungsten/fcl/control/keyboard/TouchCharInput.java +++ b/FCL/src/main/java/com/tungsten/fcl/control/keyboard/TouchCharInput.java @@ -4,16 +4,14 @@ import static android.content.Context.INPUT_METHOD_SERVICE; import android.annotation.SuppressLint; import android.content.Context; -import android.content.res.Configuration; import android.util.AttributeSet; -import android.util.Log; import android.view.KeyEvent; import android.view.inputmethod.InputMethodManager; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import java.util.Objects; +import com.tungsten.fcl.control.GameMenu; /** * From PojavLauncher @@ -21,6 +19,8 @@ import java.util.Objects; */ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText { + public static final String TEXT_FILLER = " "; + public TouchCharInput(@NonNull Context context) { this(context, null); } @@ -34,9 +34,19 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText setup(); } + private GameMenu menu; + private boolean lock = false; private boolean isDoingInternalChanges = false; 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. * If less chars are present, remove some. @@ -58,8 +68,8 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText } } - //Reset the keyboard state - if(text.length() < 1) + // Reset the keyboard state + if (text.length() < 1) clear(); } @@ -87,26 +97,28 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText /** * 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); - // If an hard keyboard is present, never trigger the soft one - if (hasFocus() - || (getResources().getConfiguration().keyboard == Configuration.KEYBOARD_QWERTY - && getResources().getConfiguration().hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES)) { + if (hasFocus()) { inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0); clear(); disable(); - return false; - } else { + if (menu != null && menu.getInput().getFocusableView() != null) { + menu.getInput().getFocusableView().requestFocus(); + menu.getInput().getFocusableView().requestPointerCapture(); + } + } else{ + if (menu != null && menu.getInput().getFocusableView() != null) { + menu.getInput().getFocusableView().releasePointerCapture(); + menu.getInput().getFocusableView().clearFocus(); + } enable(); inputMethodManager.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT); - return true; } } + /** * Clear the EditText from any leftover inputs * It does not affect the in-game input @@ -114,10 +126,8 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText @SuppressLint("SetTextI18n") public void clear() { isDoingInternalChanges = true; - //Braille space, doesn't trigger keyboard auto-complete - //replacing directly the text without though setText avoids notifying changes - setText(" "); - setSelection(Objects.requireNonNull(getText()).length()); + setText(TEXT_FILLER); + setSelection(TEXT_FILLER.length()); isDoingInternalChanges = false; } @@ -135,8 +145,6 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText setVisibility(GONE); clearFocus(); setEnabled(false); - InputMethodManager inputMethodManager = (InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE); - inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0); } /** Send the enter key. */ @@ -146,20 +154,28 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText } /** 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 function deals with anything that has to be executed when the constructor is called */ private void setup() { setOnEditorActionListener((textView, i, keyEvent) -> { + setLock(true); + InputMethodManager imm = (InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(getWindowToken(), 0); sendEnter(); clear(); disable(); + if (menu != null && menu.getInput().getFocusableView() != null) { + menu.getInput().getFocusableView().requestFocus(); + menu.getInput().getFocusableView().requestPointerCapture(); + } return false; }); clear(); disable(); } -} +} \ No newline at end of file