ANDROID: Handle repeating keys for virtual keyboard

This commit is contained in:
antoniou 2020-10-24 16:03:45 +03:00
parent 3eb363ed7f
commit ddc0e26fbf
3 changed files with 144 additions and 44 deletions

View file

@ -467,6 +467,7 @@ public class CustomKeyboardView extends View implements View.OnClickListener {
float deltaY = me2.getY() - me1.getY(); float deltaY = me2.getY() - me1.getY();
int travelX = getWidth() / 2; // Half the keyboard width int travelX = getWidth() / 2; // Half the keyboard width
int travelY = getHeight() / 2; // Half the keyboard height int travelY = getHeight() / 2; // Half the keyboard height
//Log.d(ScummVM.LOG_TAG, "mSwipeTracker.computeCurrentVelocity()");
mSwipeTracker.computeCurrentVelocity(1000); mSwipeTracker.computeCurrentVelocity(1000);
final float endingVelocityX = mSwipeTracker.getXVelocity(); final float endingVelocityX = mSwipeTracker.getXVelocity();
final float endingVelocityY = mSwipeTracker.getYVelocity(); final float endingVelocityY = mSwipeTracker.getYVelocity();
@ -502,7 +503,8 @@ public class CustomKeyboardView extends View implements View.OnClickListener {
} }
if (sendDownKey) { 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; return false;
} }
@ -889,11 +891,12 @@ public class CustomKeyboardView extends View implements View.OnClickListener {
return primaryIndex; 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) { if (index != NOT_A_KEY && index < mKeys.length) {
final CustomKeyboard.CustomKey key = mKeys[index]; final CustomKeyboard.CustomKey key = mKeys[index];
if (key.text != null) { if (key.text != null) {
mKeyboardActionListener.onText(key.text); mKeyboardActionListener.onText(key.text);
//Log.d(ScummVM.LOG_TAG, "CustomKeyboardView:: detectAndSendKey - (key.text != null)");
mKeyboardActionListener.onRelease(NOT_A_KEY); mKeyboardActionListener.onRelease(NOT_A_KEY);
} else { } else {
int code = key.codes[0]; int code = key.codes[0];
@ -910,9 +913,14 @@ public class CustomKeyboardView extends View implements View.OnClickListener {
} }
code = key.codes[mTapCount]; code = key.codes[mTapCount];
} }
//Log.d(ScummVM.LOG_TAG, "CustomKeyboardView:: detectAndSendKey - (key.text is null) code = " + code + " x: " + x + " y: " + y);
if (!isReleaseKey) {
mKeyboardActionListener.onKey(code, codes); mKeyboardActionListener.onKey(code, codes);
}
if (!isRepeated || isReleaseKey) {
mKeyboardActionListener.onRelease(code); mKeyboardActionListener.onRelease(code);
} }
}
mLastSentIndex = index; mLastSentIndex = index;
mLastTapTime = eventTime; mLastTapTime = eventTime;
} }
@ -1394,6 +1402,19 @@ public class CustomKeyboardView extends View implements View.OnClickListener {
mCurrentKeyTime + eventTime - mLastMoveTime; mCurrentKeyTime + eventTime - mLastMoveTime;
mCurrentKey = keyIndex; mCurrentKey = keyIndex;
mCurrentKeyTime = 0; 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); Arrays.fill(mKeyIndices, NOT_A_KEY);
// If we're not on a repeating key (which sends on a DOWN event) // If we're not on a repeating key (which sends on a DOWN event)
if (mRepeatKeyIndex == NOT_A_KEY && !mMiniKeyboardOnScreen && !mAbortKey) { 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); invalidateKey(keyIndex);
mRepeatKeyIndex = NOT_A_KEY; mRepeatKeyIndex = NOT_A_KEY;
@ -1452,7 +1477,8 @@ public class CustomKeyboardView extends View implements View.OnClickListener {
// @UnsupportedAppUsage // @UnsupportedAppUsage
private boolean repeatKey() { private boolean repeatKey() {
CustomKeyboard.CustomKey key = mKeys[mRepeatKeyIndex]; 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; return true;
} }
@ -1557,6 +1583,7 @@ public class CustomKeyboardView extends View implements View.OnClickListener {
} }
public void addMovement(MotionEvent ev) { public void addMovement(MotionEvent ev) {
//Log.d(ScummVM.LOG_TAG, "SwipeTracker - Add Movement");
long time = ev.getEventTime(); long time = ev.getEventTime();
final int N = ev.getHistorySize(); final int N = ev.getHistorySize();
for (int i=0; i<N; i++) { for (int i=0; i<N; i++) {

View file

@ -164,19 +164,20 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
public boolean shift = false; public boolean shift = false;
public boolean alt = false; public boolean alt = false;
public final TreeSet<Integer> stickyKeys = new TreeSet<>(); public final TreeSet<Integer> stickyKeys = new TreeSet<>();
public long mEventTime = -1; public long mEventPressTime = -1;
public int mKeyRepeatedCount = 0;
public BuiltInKeyboardView(Context context, android.util.AttributeSet attrs) { public BuiltInKeyboardView(Context context, android.util.AttributeSet attrs) {
super(context, attrs); super(context, attrs);
} }
public boolean onKeyDown(int key, final KeyEvent event) { 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; return false;
} }
public boolean onKeyUp(int key, final KeyEvent event) { 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; return false;
} }
@ -265,6 +266,12 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
//ScummVMActivity.this._scummvm.displayMessageOnOSD ("NEW KEYBOARD LAYOUT: QWERTY" //ScummVMActivity.this._scummvm.displayMessageOnOSD ("NEW KEYBOARD LAYOUT: QWERTY"
// + (alt ? " ALT " : "") + (shift? " SHIFT" : "")); // + (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); final BuiltInKeyboardView builtinKeyboard = new BuiltInKeyboardView(ScummVMActivity.this, null);
@ -273,7 +280,9 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
builtinKeyboard.setOnKeyboardActionListener(new CustomKeyboardView.OnKeyboardActionListener() { builtinKeyboard.setOnKeyboardActionListener(new CustomKeyboardView.OnKeyboardActionListener() {
public void onPress(int key) { 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) { if (key == KeyEvent.KEYCODE_BACK) {
return; 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. // 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(). ** // ** 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. // 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. // eventTime (long) - The time (in SystemClock.uptimeMillis()) at which this event happened.
// TODO update repeat and event time? with // TODO update repeat and event time? with
builtinKeyboard.mEventTime = SystemClock.uptimeMillis(); builtinKeyboard.mEventPressTime = SystemClock.uptimeMillis();
KeyEvent compiledKeyEvent = new KeyEvent(builtinKeyboard.mEventTime,
builtinKeyboard.mEventTime,
KeyEvent.ACTION_DOWN,
key,
0,
compiledMetaState);
_main_surface.dispatchKeyEvent(compiledKeyEvent);
} }
public void onRelease(int key) { 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) { if (key == KeyEvent.KEYCODE_BACK) {
builtinKeyboard.setOnKeyboardActionListener(null); builtinKeyboard.setOnKeyboardActionListener(null);
builtinKeyboard.resetEventAndTimestamps();
showScreenKeyboardWithoutTextInputField(0); // Hide keyboard showScreenKeyboardWithoutTextInputField(0); // Hide keyboard
return; return;
} }
@ -327,6 +322,7 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
if (key == CustomKeyboard.KEYCODE_SHIFT) { if (key == CustomKeyboard.KEYCODE_SHIFT) {
builtinKeyboard.shift = !builtinKeyboard.shift; builtinKeyboard.shift = !builtinKeyboard.shift;
builtinKeyboard.ChangeKeyboard(); builtinKeyboard.ChangeKeyboard();
builtinKeyboard.resetEventAndTimestamps();
return; return;
} }
@ -336,10 +332,12 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
builtinKeyboard.shift = false; builtinKeyboard.shift = false;
} }
builtinKeyboard.ChangeKeyboard(); builtinKeyboard.ChangeKeyboard();
builtinKeyboard.resetEventAndTimestamps();
return; return;
} }
if (key <= 0) { if (key <= 0) {
builtinKeyboard.resetEventAndTimestamps();
return; return;
} }
@ -358,6 +356,7 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
builtinKeyboard.stickyKeys.add(key); builtinKeyboard.stickyKeys.add(key);
} }
builtinKeyboard.recheckStickyKeys(); builtinKeyboard.recheckStickyKeys();
builtinKeyboard.resetEventAndTimestamps();
return; return;
} }
} }
@ -371,16 +370,18 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
compiledMetaState |= KeyEvent.META_SHIFT_LEFT_ON; compiledMetaState |= KeyEvent.META_SHIFT_LEFT_ON;
} }
// TODO properly set repeat value? // The repeat argument (int) is:
KeyEvent compiledKeyEvent = new KeyEvent(builtinKeyboard.mEventTime, // 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(), SystemClock.uptimeMillis(),
KeyEvent.ACTION_UP, KeyEvent.ACTION_UP,
key, key,
0, builtinKeyboard.mKeyRepeatedCount,
compiledMetaState); compiledMetaState);
_main_surface.dispatchKeyEvent(compiledKeyEvent); _main_surface.dispatchKeyEvent(compiledKeyEvent);
builtinKeyboard.mEventTime = -1; // reset event time builtinKeyboard.resetEventAndTimestamps();
// Excluding the CAPS LOCK NUM LOCK AND SCROLL LOCK keys, // 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 // 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 onText(CharSequence p1) {}
public void swipeLeft() {}
public void swipeRight() {} public void swipeLeft() {
public void swipeDown() {} //Log.d(ScummVM.LOG_TAG, "SHOW KEYBOARD - 001 - swipeLeft");
public void swipeUp() {} }
public void onKey(int p1, int[] p2) {}
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; _screenKeyboard = builtinKeyboard;
// TODO better to have specific dimensions in dp and not adjusted to parent // 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 // 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.addView(_screenKeyboard, sKeyboardLayout);
_videoLayout.bringChildToFront(_screenKeyboard); _videoLayout.bringChildToFront(_screenKeyboard);
@ -496,6 +535,10 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
return _screenKeyboard; return _screenKeyboard;
} }
// public View getMainSurfaceView() {
// return _main_surface;
// }
// //
// END OF new screenKeyboardCode // END OF new screenKeyboardCode
// --------------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------------

View file

@ -156,7 +156,23 @@ public class ScummVMEventsBase implements
// OnKeyListener // OnKeyListener
@Override @Override
final public boolean onKey(View v, int keyCode, KeyEvent e) { 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(); final int action = e.getAction();
int eventUnicodeChar = e.getUnicodeChar(); int eventUnicodeChar = e.getUnicodeChar();
@ -191,8 +207,10 @@ public class ScummVMEventsBase implements
if (action == KeyEvent.ACTION_DOWN) { if (action == KeyEvent.ACTION_DOWN) {
return true; return true;
} else if (action == KeyEvent.ACTION_UP) { } else if (action == KeyEvent.ACTION_UP) {
// Hide keyboard (the argument here (0) does not matter) // Hide keyboard
((ScummVMActivity) _context).showScreenKeyboardWithoutTextInputField(0); if (((ScummVMActivity) _context).isScreenKeyboardShown()) {
((ScummVMActivity) _context).hideScreenKeyboard();
}
return true; return true;
} }
} }
@ -200,8 +218,9 @@ public class ScummVMEventsBase implements
if (e.isSystem()) { if (e.isSystem()) {
// no repeats for system keys // no repeats for system keys
if (e.getRepeatCount() > 0) if (e.getRepeatCount() > 0) {
return false; return false;
}
// Have to reimplement hold-down-menu-brings-up-softkeybd // Have to reimplement hold-down-menu-brings-up-softkeybd
// ourselves, since we are otherwise hijacking the menu key :( // ourselves, since we are otherwise hijacking the menu key :(
@ -335,7 +354,18 @@ public class ScummVMEventsBase implements
// OnTouchListener // OnTouchListener
@Override @Override
final public boolean onTouch(View v, final MotionEvent event) { 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 if (ScummVMActivity.keyboardWithoutTextInputShown
&& ((ScummVMActivity) _context).isScreenKeyboardShown() && ((ScummVMActivity) _context).isScreenKeyboardShown()
@ -383,7 +413,7 @@ public class ScummVMEventsBase implements
// OnGestureListener // OnGestureListener
@Override @Override
final public boolean onDown(MotionEvent e) { 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); _scummvm.pushEvent(JE_DOWN, (int)e.getX(), (int)e.getY(), 0, 0, 0, 0);
return true; return true;
} }