According to the KeyboardView.OnKeyboardActionListener.onRelease()
SDK docs, "For keys that repeat, this is only called once". However, if I set isRepeatable to true for the 'a' key with the Android Softkeyboard example, and log onPress()
, onKey()
and onRelease()
method calls, I get repetition as expected but I observe the following log for a single press/repeat/release sequence:
I/SoftKeyboard(31467): onPress: 97
I/SoftKeyboard(31467): onKey: 97
I/SoftKeyboard(31467): onRelease: 97
I/SoftKeyboard(31467): onKey: 97
I/SoftKeyboard(31467): onRelease: 97
I/SoftKeyboard(31467): onKey: 97
I/SoftKeyboard(31467): onRelease: 97
I/SoftKeyboard(31467): onKey: 97
I/SoftKeyboard(31467): onRelease: 97
I/SoftKeyboard(31467): onKey: 97
I/SoftKeyboard(31467): onRelease: 97
How can I determine exactly when the touch device has been released? Thanks, D.
EDIT (Edit by Paul Boddington 30/07/2015)
Although I am not the OP, I wanted to include a complete example showing the problem.
MyActivity
:
public class MyActivity extends Activity {
private static final String TAG = "MyActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
KeyboardView keyboardView = (KeyboardView) findViewById(R.id.keyboard_view);
keyboardView.setKeyboard(new Keyboard(this, R.xml.keyboard));
keyboardView.setOnKeyboardActionListener(new KeyboardView.OnKeyboardActionListener() {
@Override
public void onPress(int i) {
Log.i(TAG, "onPress: " + i);
}
@Override
public void onKey(int i, int[] ints) {
Log.i(TAG, "onKey: " + i);
}
@Override
public void onRelease(int i) {
Log.i(TAG, "onRelease: " + i);
}
@Override public void onText(CharSequence charSequence) {}
@Override public void swipeLeft() {}
@Override public void swipeRight() {}
@Override public void swipeDown() {}
@Override public void swipeUp() {}
});
}
}
keyboard.xml
:
<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android">
android:layout_height="wrap_content"
android:layout_width="match_parent"
>
<Row
android:keyWidth="25%p"
android:keyHeight="60dp">
<Key android:codes="0" android:keyLabel="0" android:isRepeatable="true"/>
<Key android:codes="1" android:keyLabel="1" />
<Key android:codes="2" android:keyLabel="2" />
<Key android:codes="3" android:keyLabel="3" />
</Row>
</Keyboard>
activity_my.xml
:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.inputmethodservice.KeyboardView
android:id="@+id/keyboard_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:focusableInTouchMode="true"
/>
</LinearLayout>
I couldn't figure out how to fix KeyboardView
to properly emit the onRelease()
for repeatable keys. So instead I came up with a workaround that recognizes the release by looking at the MotionEvent.ACTION_UP
. You do this for repeatable keys only and ignore the onRelease()
events for these keys as well.
private List<Integer> mRepeatableKeys = new ArrayList<Integer>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final KeyboardView keyboardView = (KeyboardView) findViewById(R.id.keyboard_view);
keyboardView.post(new Runnable() {
@Override
public void run() {
for( Keyboard.Key key : keyboardView.getKeyboard().getKeys() )
{
if(key.repeatable) mRepeatableKeys.add(key.codes[0]);
}
}
});
keyboardView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
if(mTrackingRepeatableKey != -1)
{
Log.i(TAG, "Repeatable key released: " + mTrackingRepeatableKey);
mTrackingRepeatableKey = -1;
}
}
return false;
}
});
keyboardView.setKeyboard(new Keyboard(this, R.xml.keyboard));
keyboardView.setOnKeyboardActionListener(mKeyboardActionListener);
}
private int mTrackingRepeatableKey = -1;
KeyboardView.OnKeyboardActionListener mKeyboardActionListener = new KeyboardView.OnKeyboardActionListener() {
@Override
public void onPress(int i) {
Log.i(TAG, "onPress: " + i);
if( mRepeatableKeys.contains(i))
{
mTrackingRepeatableKey = i;
}
}
@Override
public void onKey(int i, int[] ints) {
if( mRepeatableKeys.contains(i))
{
Log.i(TAG, "onKey Repeat: " + i);
return;
}
Log.i(TAG, "onKey: " + i);
}
@Override
public void onRelease(int i) {
// Ignore release for repeatable keys
if( mRepeatableKeys.contains(i)) return;
Log.i(TAG, "onRelease: " + i);
}
@Override
public void onText(CharSequence text) {
}
@Override
public void swipeLeft() {
}
@Override
public void swipeRight() {
}
@Override
public void swipeDown() {
}
@Override
public void swipeUp() {
}
};
Tested on Android 5.1. Logs now read:
I/MainActivity﹕ onPress: 1
I/MainActivity﹕ onKey Repeat: 1
I/MainActivity﹕ onKey Repeat: 1
I/MainActivity﹕ onKey Repeat: 1
I/MainActivity﹕ onKey Repeat: 1
I/MainActivity﹕ onKey Repeat: 1
I/MainActivity﹕ onKey Repeat: 1
I/MainActivity﹕ onKey Repeat: 1
I/MainActivity﹕ onKey Repeat: 1
I/MainActivity﹕ Repeatable key released: 1
If you want you could extend KeyboardView and contain all of this ugly logic inside of it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With