From ddc0e26fbff23340413d812a3d92aaa5d7e23c4e Mon Sep 17 00:00:00 2001 From: antoniou Date: Sat, 24 Oct 2020 16:03:45 +0300 Subject: [PATCH] ANDROID: Handle repeating keys for virtual keyboard --- .../scummvm/scummvm/CustomKeyboardView.java | 39 ++++++- .../org/scummvm/scummvm/ScummVMActivity.java | 107 ++++++++++++------ .../scummvm/scummvm/ScummVMEventsBase.java | 42 ++++++- 3 files changed, 144 insertions(+), 44 deletions(-) diff --git a/backends/platform/android/org/scummvm/scummvm/CustomKeyboardView.java b/backends/platform/android/org/scummvm/scummvm/CustomKeyboardView.java index 6b1c95d337e..8b52a4da125 100755 --- a/backends/platform/android/org/scummvm/scummvm/CustomKeyboardView.java +++ b/backends/platform/android/org/scummvm/scummvm/CustomKeyboardView.java @@ -467,6 +467,7 @@ public class CustomKeyboardView extends View implements View.OnClickListener { float deltaY = me2.getY() - me1.getY(); int travelX = getWidth() / 2; // Half the keyboard width int travelY = getHeight() / 2; // Half the keyboard height + //Log.d(ScummVM.LOG_TAG, "mSwipeTracker.computeCurrentVelocity()"); mSwipeTracker.computeCurrentVelocity(1000); final float endingVelocityX = mSwipeTracker.getXVelocity(); final float endingVelocityY = mSwipeTracker.getYVelocity(); @@ -502,7 +503,8 @@ public class CustomKeyboardView extends View implements View.OnClickListener { } if (sendDownKey) { - detectAndSendKey(mDownKey, mStartX, mStartY, me1.getEventTime()); + //Log.d(ScummVM.LOG_TAG, "CustomKeyboardView:: initGestureDetector() - sendDownKey"); + detectAndSendKey(mDownKey, mStartX, mStartY, me1.getEventTime(), false, false); } return false; } @@ -889,11 +891,12 @@ public class CustomKeyboardView extends View implements View.OnClickListener { return primaryIndex; } - private void detectAndSendKey(int index, int x, int y, long eventTime) { + private void detectAndSendKey(int index, int x, int y, long eventTime, boolean isRepeated, boolean isReleaseKey) { if (index != NOT_A_KEY && index < mKeys.length) { final CustomKeyboard.CustomKey key = mKeys[index]; if (key.text != null) { mKeyboardActionListener.onText(key.text); + //Log.d(ScummVM.LOG_TAG, "CustomKeyboardView:: detectAndSendKey - (key.text != null)"); mKeyboardActionListener.onRelease(NOT_A_KEY); } else { int code = key.codes[0]; @@ -910,8 +913,13 @@ public class CustomKeyboardView extends View implements View.OnClickListener { } code = key.codes[mTapCount]; } - mKeyboardActionListener.onKey(code, codes); - mKeyboardActionListener.onRelease(code); + //Log.d(ScummVM.LOG_TAG, "CustomKeyboardView:: detectAndSendKey - (key.text is null) code = " + code + " x: " + x + " y: " + y); + if (!isReleaseKey) { + mKeyboardActionListener.onKey(code, codes); + } + if (!isRepeated || isReleaseKey) { + mKeyboardActionListener.onRelease(code); + } } mLastSentIndex = index; mLastTapTime = eventTime; @@ -1394,6 +1402,19 @@ public class CustomKeyboardView extends View implements View.OnClickListener { mCurrentKeyTime + eventTime - mLastMoveTime; mCurrentKey = keyIndex; mCurrentKeyTime = 0; + } else { + // if (mRepeatKeyIndex != NOT_A_KEY) + // New - handle the case where the user holds their finger and moves out of the key button + // Unfortunately, we will also get a "release" event on MotionEvent.ACTION_UP but that is safe since it is ignored + removeMessages(); + if (mRepeatKeyIndex >= 0 && !mMiniKeyboardOnScreen && !mAbortKey) { + //Log.d(ScummVM.LOG_TAG, "CustomKeyboardView:: onModifiedTouchEvent - MotionEvent.ACTION_MOVE Final Rep"); + detectAndSendKey(mCurrentKey, touchX, touchY, eventTime, true, true); + } + showPreview(NOT_A_KEY); + Arrays.fill(mKeyIndices, NOT_A_KEY); + invalidateKey(keyIndex); + mRepeatKeyIndex = NOT_A_KEY; } } } @@ -1431,7 +1452,11 @@ public class CustomKeyboardView extends View implements View.OnClickListener { Arrays.fill(mKeyIndices, NOT_A_KEY); // If we're not on a repeating key (which sends on a DOWN event) if (mRepeatKeyIndex == NOT_A_KEY && !mMiniKeyboardOnScreen && !mAbortKey) { - detectAndSendKey(mCurrentKey, touchX, touchY, eventTime); + //Log.d(ScummVM.LOG_TAG, "CustomKeyboardView:: onModifiedTouchEvent - MotionEvent.ACTION_UP No Rep"); + detectAndSendKey(mCurrentKey, touchX, touchY, eventTime, false, true); + } else if (mRepeatKeyIndex >= 0 && mRepeatKeyIndex != NOT_A_KEY && !mMiniKeyboardOnScreen && !mAbortKey) { + //Log.d(ScummVM.LOG_TAG, "CustomKeyboardView:: onModifiedTouchEvent - MotionEvent.ACTION_UP Final Rep"); + detectAndSendKey(mCurrentKey, touchX, touchY, eventTime, true, true); } invalidateKey(keyIndex); mRepeatKeyIndex = NOT_A_KEY; @@ -1452,7 +1477,8 @@ public class CustomKeyboardView extends View implements View.OnClickListener { // @UnsupportedAppUsage private boolean repeatKey() { CustomKeyboard.CustomKey key = mKeys[mRepeatKeyIndex]; - detectAndSendKey(mCurrentKey, key.x, key.y, mLastTapTime); + //Log.d(ScummVM.LOG_TAG, "CustomKeyboardView:: repeatKey"); + detectAndSendKey(mCurrentKey, key.x, key.y, mLastTapTime, true, false); return true; } @@ -1557,6 +1583,7 @@ public class CustomKeyboardView extends View implements View.OnClickListener { } public void addMovement(MotionEvent ev) { + //Log.d(ScummVM.LOG_TAG, "SwipeTracker - Add Movement"); long time = ev.getEventTime(); final int N = ev.getHistorySize(); for (int i=0; i stickyKeys = new TreeSet<>(); - public long mEventTime = -1; + public long mEventPressTime = -1; + public int mKeyRepeatedCount = 0; public BuiltInKeyboardView(Context context, android.util.AttributeSet attrs) { super(context, attrs); } public boolean onKeyDown(int key, final KeyEvent event) { - Log.d(ScummVM.LOG_TAG, "SHOW KEYBOARD - 001 - onKeyDown()" ); + //Log.d(ScummVM.LOG_TAG, "BuiltInKeyboardView- 001 - onKeyDown()" ); return false; } public boolean onKeyUp(int key, final KeyEvent event) { - Log.d(ScummVM.LOG_TAG, "SHOW KEYBOARD - 001 - onKeyUp()" ); + //Log.d(ScummVM.LOG_TAG, "BuiltInKeyboardView - 001 - onKeyUp()" ); return false; } @@ -265,6 +266,12 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis //ScummVMActivity.this._scummvm.displayMessageOnOSD ("NEW KEYBOARD LAYOUT: QWERTY" // + (alt ? " ALT " : "") + (shift? " SHIFT" : "")); } + + public void resetEventAndTimestamps() { + // clear event timestamps and repetition counts + mEventPressTime = -1; + mKeyRepeatedCount = -1; + } } final BuiltInKeyboardView builtinKeyboard = new BuiltInKeyboardView(ScummVMActivity.this, null); @@ -273,7 +280,9 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis builtinKeyboard.setOnKeyboardActionListener(new CustomKeyboardView.OnKeyboardActionListener() { public void onPress(int key) { - //Log.d(ScummVM.LOG_TAG, "SHOW KEYBOARD - 001 - onPress key: " + key ); // CALLED + builtinKeyboard.resetEventAndTimestamps(); + +// Log.d(ScummVM.LOG_TAG, "SHOW KEYBOARD - 001 - onPress key: " + key ); if (key == KeyEvent.KEYCODE_BACK) { return; } @@ -288,35 +297,21 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis } } - int compiledMetaState = builtinKeyboard.getCompiledMetaState(); - - // keys with keyCode greater than 100000, should be submitted with a LEFT_SHIFT_ modifier (and decreased by 100000 to get their proper code) - if (key > 100000) { - key -= 100000; - compiledMetaState |= KeyEvent.META_SHIFT_LEFT_ON; - } - // // downTime (long) - The time (in SystemClock.uptimeMillis()) at which this key code originally went down. // ** Since this is a down event, this will be the same as getEventTime(). ** // Note that when chording keys, this value is the down time of the most recently pressed key, which may not be the same physical key of this event. // eventTime (long) - The time (in SystemClock.uptimeMillis()) at which this event happened. // TODO update repeat and event time? with - builtinKeyboard.mEventTime = SystemClock.uptimeMillis(); - KeyEvent compiledKeyEvent = new KeyEvent(builtinKeyboard.mEventTime, - builtinKeyboard.mEventTime, - KeyEvent.ACTION_DOWN, - key, - 0, - compiledMetaState); + builtinKeyboard.mEventPressTime = SystemClock.uptimeMillis(); - _main_surface.dispatchKeyEvent(compiledKeyEvent); } public void onRelease(int key) { - //Log.d(ScummVM.LOG_TAG, "SHOW KEYBOARD - 001 - onRelease key: " + key ); +// Log.d(ScummVM.LOG_TAG, "SHOW KEYBOARD - 001 - onRelease key: " + key ); if (key == KeyEvent.KEYCODE_BACK) { builtinKeyboard.setOnKeyboardActionListener(null); + builtinKeyboard.resetEventAndTimestamps(); showScreenKeyboardWithoutTextInputField(0); // Hide keyboard return; } @@ -327,6 +322,7 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis if (key == CustomKeyboard.KEYCODE_SHIFT) { builtinKeyboard.shift = !builtinKeyboard.shift; builtinKeyboard.ChangeKeyboard(); + builtinKeyboard.resetEventAndTimestamps(); return; } @@ -336,10 +332,12 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis builtinKeyboard.shift = false; } builtinKeyboard.ChangeKeyboard(); + builtinKeyboard.resetEventAndTimestamps(); return; } if (key <= 0) { + builtinKeyboard.resetEventAndTimestamps(); return; } @@ -358,6 +356,7 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis builtinKeyboard.stickyKeys.add(key); } builtinKeyboard.recheckStickyKeys(); + builtinKeyboard.resetEventAndTimestamps(); return; } } @@ -371,16 +370,18 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis compiledMetaState |= KeyEvent.META_SHIFT_LEFT_ON; } - // TODO properly set repeat value? - KeyEvent compiledKeyEvent = new KeyEvent(builtinKeyboard.mEventTime, + // The repeat argument (int) is: + // A repeat count for down events (> 0 if this is after the initial down) + // or event count for multiple events. + KeyEvent compiledKeyEvent = new KeyEvent(builtinKeyboard.mEventPressTime, SystemClock.uptimeMillis(), KeyEvent.ACTION_UP, key, - 0, + builtinKeyboard.mKeyRepeatedCount, compiledMetaState); _main_surface.dispatchKeyEvent(compiledKeyEvent); - builtinKeyboard.mEventTime = -1; // reset event time + builtinKeyboard.resetEventAndTimestamps(); // Excluding the CAPS LOCK NUM LOCK AND SCROLL LOCK keys, // clear the state of all other sticky keys that are used in a key combo @@ -402,17 +403,55 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis } public void onText(CharSequence p1) {} - public void swipeLeft() {} - public void swipeRight() {} - public void swipeDown() {} - public void swipeUp() {} - public void onKey(int p1, int[] p2) {} + + public void swipeLeft() { + //Log.d(ScummVM.LOG_TAG, "SHOW KEYBOARD - 001 - swipeLeft"); + } + + public void swipeRight() { + //Log.d(ScummVM.LOG_TAG, "SHOW KEYBOARD - 001 - swipeRight" ); + } + + public void swipeDown() { + //Log.d(ScummVM.LOG_TAG, "SHOW KEYBOARD - 001 - swipeDown" ); + } + + public void swipeUp() { + //Log.d(ScummVM.LOG_TAG, "SHOW KEYBOARD - 001 - swipeUp "); + } + public void onKey(int key, int[] keysAround) { +// Log.d(ScummVM.LOG_TAG, "SHOW KEYBOARD - 001 - onKey key: " + key ); + if (builtinKeyboard.mEventPressTime == -1) { + return; + } + + if (builtinKeyboard.mKeyRepeatedCount < Integer.MAX_VALUE) { + ++builtinKeyboard.mKeyRepeatedCount; + } + int compiledMetaState = builtinKeyboard.getCompiledMetaState(); + + // keys with keyCode greater than 100000, should be submitted with a LEFT_SHIFT_ modifier (and decreased by 100000 to get their proper code) + if (key > 100000) { + key -= 100000; + compiledMetaState |= KeyEvent.META_SHIFT_LEFT_ON; + } + + // update the eventTime after the above check for first time "hit" + KeyEvent compiledKeyEvent = new KeyEvent(builtinKeyboard.mEventPressTime, + SystemClock.uptimeMillis(), + KeyEvent.ACTION_DOWN, + key, + builtinKeyboard.mKeyRepeatedCount, + compiledMetaState); + + _main_surface.dispatchKeyEvent(compiledKeyEvent); + } }); _screenKeyboard = builtinKeyboard; // TODO better to have specific dimensions in dp and not adjusted to parent // it may resolve the issue of resizing the keyboard wrongly (smaller) when returning to the suspended Activity in low resolution - FrameLayout.LayoutParams sKeyboardLayout = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL); + FrameLayout.LayoutParams sKeyboardLayout = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL | Gravity.FILL_HORIZONTAL); _videoLayout.addView(_screenKeyboard, sKeyboardLayout); _videoLayout.bringChildToFront(_screenKeyboard); @@ -492,10 +531,14 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis return _screenKeyboard != null; } - public View getScreenKeyboard () { + public View getScreenKeyboard() { return _screenKeyboard; } +// public View getMainSurfaceView() { +// return _main_surface; +// } + // // END OF new screenKeyboardCode // --------------------------------------------------------------------------------------------------------------------------- diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVMEventsBase.java b/backends/platform/android/org/scummvm/scummvm/ScummVMEventsBase.java index 70bacadc9c3..9080829ff47 100644 --- a/backends/platform/android/org/scummvm/scummvm/ScummVMEventsBase.java +++ b/backends/platform/android/org/scummvm/scummvm/ScummVMEventsBase.java @@ -156,7 +156,23 @@ public class ScummVMEventsBase implements // OnKeyListener @Override final public boolean onKey(View v, int keyCode, KeyEvent e) { -// Log.d(ScummVM.LOG_TAG, "SCUMMV-EVENTS-BASE - onKEY:::" + keyCode); // Called + +// String actionStr = ""; +// switch (e.getAction()) { +// case KeyEvent.ACTION_UP: +// actionStr = "KeyEvent.ACTION_UP"; +// break; +// case KeyEvent.ACTION_DOWN: +// actionStr = "KeyEvent.ACTION_DOWN"; +// break; +// case KeyEvent.ACTION_MULTIPLE: +// actionStr = "KeyEvent.ACTION_MULTIPLE"; +// break; +// default: +// actionStr = e.toString(); +// } +// Log.d(ScummVM.LOG_TAG, "SCUMMV-EVENTS-BASE - onKEY:::" + keyCode + " Action::" + actionStr + " View:: " + actionView); // Called + final int action = e.getAction(); int eventUnicodeChar = e.getUnicodeChar(); @@ -191,8 +207,10 @@ public class ScummVMEventsBase implements if (action == KeyEvent.ACTION_DOWN) { return true; } else if (action == KeyEvent.ACTION_UP) { - // Hide keyboard (the argument here (0) does not matter) - ((ScummVMActivity) _context).showScreenKeyboardWithoutTextInputField(0); + // Hide keyboard + if (((ScummVMActivity) _context).isScreenKeyboardShown()) { + ((ScummVMActivity) _context).hideScreenKeyboard(); + } return true; } } @@ -200,8 +218,9 @@ public class ScummVMEventsBase implements if (e.isSystem()) { // no repeats for system keys - if (e.getRepeatCount() > 0) + if (e.getRepeatCount() > 0) { return false; + } // Have to reimplement hold-down-menu-brings-up-softkeybd // ourselves, since we are otherwise hijacking the menu key :( @@ -335,7 +354,18 @@ public class ScummVMEventsBase implements // OnTouchListener @Override final public boolean onTouch(View v, final MotionEvent event) { - //Log.d(ScummVM.LOG_TAG, "SCUMMV-EVENTS-BASE - onTOUCH"); +// String actionStr = ""; +// switch (event.getAction()) { +// case MotionEvent.ACTION_UP: +// actionStr = "MotionEvent.ACTION_UP"; +// break; +// case MotionEvent.ACTION_DOWN: +// actionStr = "MotionEvent.ACTION_DOWN"; +// break; +// default: +// actionStr = event.toString(); +// } +// Log.d(ScummVM.LOG_TAG, "SCUMMV-EVENTS-BASE - onTOUCH event" + actionStr); if (ScummVMActivity.keyboardWithoutTextInputShown && ((ScummVMActivity) _context).isScreenKeyboardShown() @@ -383,7 +413,7 @@ public class ScummVMEventsBase implements // OnGestureListener @Override final public boolean onDown(MotionEvent e) { - //Log.d(ScummVM.LOG_TAG, "SCUMMV-EVENTS-BASE - onDONW"); + //Log.d(ScummVM.LOG_TAG, "SCUMMV-EVENTS-BASE - onDOWN MotionEvent"); _scummvm.pushEvent(JE_DOWN, (int)e.getX(), (int)e.getY(), 0, 0, 0, 0); return true; }