13

I know this/similar question has been asked before but the solution given is not working for me so I'm asking again. I tried the solution given in that answer but still my OnKeyListener is never being invoked on some devices, especially the ones with stock OS. I need to detect pressing of del key of soft keyboard when when there is no character in editText. Here is my code;

EditText et = (EditText) findViewById(R.id.et);
    et.setOnKeyListener(new EditText.OnKeyListener() {

        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            Log.d("OnKeyListener", keyCode + " character(code) to send");
            return false;
        }
    });
Cœur
  • 37,241
  • 25
  • 195
  • 267
Ammar
  • 1,811
  • 5
  • 26
  • 60

5 Answers5

29

Finally solved myself by implementing this feature through TextWatcher. The major hurdle was that, I needed to detect backspace press even when there is no character in EditText or at least the end user perceives that there is no character there. The fist thing couldn't be achieved however I did the later one. Following is the detailed solution.

First of all, I always retained a space ' ' character in my editText.

editText.addTextChangedListener(new TextWatcher() {

    @Override
    public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
        if(cs.toString().length() == 0)
            editText.setText(" ");
    }

    @Override
    public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { }

    @Override
    public void afterTextChanged(Editable arg0) { }

});

Then I customized EditText to notify me for every cursor position change. This purpose is achieved by overriding onSelectionChanged method of EditText. My customized EditText looks like this.

public class SelectionEnabledEditText extends EditText {
    public SelectionEnabledEditText(Context context) {
        super(context);
    }

    public SelectionEnabledEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public SelectionEnabledEditText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onSelectionChanged(int selStart, int selEnd) {
        super.onSelectionChanged(selStart, selEnd);

        if(onSelectionChangeListener != null)
            onSelectionChangeListener.onSelectionChanged(selStart, selEnd);
    }

    public static interface OnSelectionChangeListener{
        public void onSelectionChanged(int selStart, int selEnd);
    }

    private  OnSelectionChangeListener onSelectionChangeListener;

    public void setOnSelectionChangeListener(OnSelectionChangeListener onSelectionChangeListener) {
        this.onSelectionChangeListener = onSelectionChangeListener;
    }
}

Finally, in my activity, I'm listening for cursor position changed event and resetting my cursor position in editText if it's there at the necessary space charatcer start i.e. at 0th index, like this;

editText.setOnSelectionChangeListener(new SelectionEnabledEditText.OnSelectionChangeListener() {
    @Override
    public void onSelectionChanged(int selStart, int selEnd) {
        if (selEnd == 0) {
            if (editText.getText().toString().length() == 0)
                editText.setText(" ");

            editText.setSelection(1);
        }
    }
});

Hope this would be helpful in similar situations. Suggestions are welcomed for improvements/optimizations.

Ammar
  • 1,811
  • 5
  • 26
  • 60
  • 1
    Note that if you're using the design support library you must extend AppCompatEditText and not EditText. The reason for this is that The support library automatically replaces all EditText objects in your layout with the app compat version. It can't detect your custom class and won't replace it; which can lead to all sorts of weirdness. – Chris Jul 27 '15 at 17:29
  • This is an old question but I'd like to suggest you a solution. http://stackoverflow.com/questions/18581636/android-cannot-capture-backspace-delete-press-in-soft-keyboard/19980975#19980975 – Noman Rafique Nov 03 '15 at 06:52
13

The documentation states that the key events will only be propagated for the hardware key strokes, not software.

http://developer.android.com/reference/android/view/View.OnKeyListener.html

The device manufacturers are actually being discouraged to propagate soft keyboard events through key listeners, although it is completely up to the manufacturer to honour that or to actually treat the soft and hard keyboards with equal terms.

Starting from Android 4.2.2, Android system itself will not support key stoke events for the soft keyboards at all, so even the manufacturers will not be able to choose their way.

So the only foolproof option here is to implement your own IME (soft keyboard), and handle the keystrokes yourself.

TextWatcher can be used mostly to replace the key listeners, however editText.setText(...); will also trigger the TextWatcher events, so if one is interested in typed keys only then probably TextWatcher is not a solution either.

Please be cautious when using TextWatcher with AutocomleteTextView or EditText. Do not modify text in the AutocompleteTextView / EditText's content from within TextWatcher events, cause otherwise you'll most probably end up in an infinite event/listening loop.

naveejr
  • 735
  • 1
  • 15
  • 31
Ameer
  • 2,709
  • 1
  • 28
  • 44
  • 'Starting from Android 4.2.2, Android system itself will not support key stoke events for the soft keyboards at all, so even the manufacturers will not be able to choose their way.' I don't think so, because it's working on Xperia Z1 with Android 4.3. – Ammar Jun 26 '14 at 09:33
  • Seems you're right. I got this problem. Can you show an example of implementing "your own IME (soft keyboard), and handle the keystrokes yourself" ? Thnks. – maohieng Dec 04 '15 at 09:49
  • Perfect answer for this question! – Sam Chen Sep 11 '19 at 17:07
4

Based on the documentation of the OnKeyListener it seems that the callback is invoked only for hardware keyboards.

Interface definition for a callback to be invoked when a hardware key event is dispatched to this view. The callback will be invoked before the key event is given to the view. This is only useful for hardware keyboards; a software input method has no obligation to trigger this listener.

Guillaume Barré
  • 4,168
  • 2
  • 27
  • 50
0

There's an attribute for EditText: android:imeOptions

<androidx.appcompat.widget.AppCompatEditText
    android:id="@+id/main_editor"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:imeOptions="actionGo"
    />

I noticed that for values: actionGo, actionNone, normal, actionSearch onKeyListener got called.

P.S. It even worked without specifying that attribute.!

rehman_00001
  • 1,299
  • 1
  • 15
  • 28
-3

Try something like this :

public boolean onKey(View v, int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_DEL) {
        //Log key
        Log.d("OnKeyListener", keyCode + " character(code) to send");
    }       
    return false;
}
David Passmore
  • 6,089
  • 4
  • 46
  • 70
Lockon
  • 1
  • 1
  • As mentioned in other posts, this method is only intended to work for hardware keyboards. As others have also mentioned, you can find cases where it does work on certain model phones for soft keyboards, but it is definitely not a comprehensive solution. – Chris Jul 27 '15 at 17:24