Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
995 views
in Technique[技术] by (71.8m points)

view - Android - cannot capture backspace/delete press in soft. keyboard

I am overriding the onKeyDown method of the view (openGL surface view) to capture all of the key presses. The problem is that on several devices the KEYCODE_DEL is not captured. I have tried adding an onKeyListener to the view, and that captured everything except backspace key.

There has to be a way to listen to this key press event, but how?

question from:https://stackoverflow.com/questions/18581636/android-cannot-capture-backspace-delete-press-in-soft-keyboard

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

11/12/2014 UPDATE: Changed scope of fix to not limit to < API level 19, since at a third party keyboard still has the bug beyond 19.

1/9/2014 UPDATE: I've devised an approach, with code, to resolve all Google Keyboard (LatinIME) KEYCODE_DEL problems, specifically issues 42904 and 62306.

The enhancement in Turix's answer has been incorporated, with permission, into my own code here. Turix's improvements removed need to inject garbage characters into the Editable buffer by instead finding an incremental way to ensure that exactly one character was always in that buffer.

I've used (similar) code to this in a deployed app that you're welcome to test:
https://play.google.com/store/apps/details?id=com.goalstate.WordGames.FullBoard.trialsuite]

INTRODUCTION:

The workaround presented below is intended to work for all versions of the Google Keyboard, both past and future, so far as these two bugs are concerned. This workaround does not require that an app remain stuck targeting API level 15 or below, which some apps have restricted themselves to in order to take advantage of compatibility code that gets around issue 42904.

These problems are only present as bugs for a view that has implemented the override for onCreateInputConnection(), and which returns TYPE_NULL to the invoking IME (in the inputType member of the EditorInfo argument passed to that method by the IME). It is only by doing this that a view can reasonably expect that key events (including KEYCODE_DEL) will be returned to it from a soft keyboard. Consequently, the workaround presented here requires the TYPE_NULL InputType.

For apps not using TYPE_NULL, there are various overrides in the BaseInputConnection-derived object returned by a view from its onCreateInputConnection() override, that are invoked by the IME when the user performs edits, instead of the IME generating key events. This (non TYPE_NULL) approach is usually superior, because the soft keyboard's capabilities now extend far beyond the mere tapping of keys, to things like voice input, completion, etc. Key events are an older method, and those implementing LatinIME at Google have said that they would like to see the use of TYPE_NULL (and key events) go away.

If discontinuing the use of TYPE_NULL is an option, then I would urge you to proceed with the recommended approach of using the InputConnection override methods instead of key events (or, more simply, by using a class derived from EditText, which does that for you).

Nonetheless, TYPE_NULL behavior is not being officially discontinued, and thus the failure of LatinIME to generate KEYCODE_DEL events under certain circumstances is indeed a bug. I offer the following workaround to address this problem.

OVERVIEW:

The problems that apps have had in receiving KEYCODE_DEL from LatinIME are due to TWO known bugs, as reported here:

https://code.google.com/p/android/issues/detail?id=42904 (listed as WorkingAsIntended, but the problem is, I maintain, a bug inasmuch as it causes a failure to support KEYCODE_DEL event generation for apps targeting API level 16 and above that have specifically listed an InputType of TYPE_NULL. The problem is fixed in the latest releases of LatinIME, but there are past releases in the wild that still exhibit this bug, and so apps using TYPE_NULL and targeting API Level 16 or above will still need a workaround that can be performed from within the app.

and here:

http://code.google.com/p/android/issues/detail?id=62306 (presently listed as fixed but not yet released - FutureRelease - but even once it is released, we will still need a workaround that can be performed from within the app to deal with the past releases that will persist "in the wild").

Consistent with this thesis (that the problems experienced with KEYCODE_DEL events are due to bugs in LatinIME), I have found that when using an external hardware keyboard, and also when using the third party SwiftKey soft keyboard, these problems do not occur, while they do occur for specific versions of LatinIME.

One or the other (but not both at once) of these problems is present in some LatinIME releases. Consequently, it is difficult for developers to know during testing whether they have worked around all KEYCODE_DEL problems, and sometimes when an Android (or Google Keyboard) update is performed, a problem will no longer be reproducible in testing. Nonetheless, the LatinIME versions that cause the problem will be present on quite a number of devices in use. This has forced me to dig into the AOSP LatinIME git repo to determine the exact scope of each of the two problems (i.e., the specific LatinIME, and Android, versions for which each of the two issues may be present). The workaround code below has been restricted to those specific versions.

The workaround code presented below includes extensive comments which should help you to understand what it is attempting to accomplish. Following the presentation of the code, I will provide some additional discussion, which will include the specific Android Open Source Project (AOSP) commits at which each of the two bugs was introduced, and at which it disappeared, and also the Android versions that might include the affected Google Keyboard releases.

I would warn anyone thinking of using this approach to perform their own testing to verify that it works for their particular app. I think that it will work in general, and have tested it on a number of devices and LatinIME versions, but the reasoning is complicated, so proceed with caution. If you find any problems, please post a comment below.

CODE:

Here, then, is my workaround for both of the two problems, with an explanation included in the comments to the code:

First, include the following class (edited to taste) in your app, in its own source file InputConnectionAccomodatingLatinIMETypeNullIssues.java:

import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.BaseInputConnection;

/**
 * 
 * @author Carl Gunther
 * There are bugs with the LatinIME keyboard's generation of KEYCODE_DEL events 
 * that this class addresses in various ways.  These bugs appear when the app 
 * specifies TYPE_NULL, which is the only circumstance under which the app 
 * can reasonably expect to receive key events for KEYCODE_DEL.
 * 
 * This class is intended for use by a view that overrides 
 * onCreateInputConnection() and specifies to the invoking IME that it wishes 
 * to use the TYPE_NULL InputType.  This should cause key events to be returned 
 * to the view.
 * 
 */
public class InputConnectionAccomodatingLatinIMETypeNullIssues extends BaseInputConnection {

    //This holds the Editable text buffer that the LatinIME mistakenly *thinks* 
    // that it is editing, even though the views that employ this class are 
    // completely driven by key events.
    Editable myEditable = null;

    //Basic constructor
    public InputConnectionAccomodatingLatinIMETypeNullIssues(View targetView, boolean fullEditor) {
        super(targetView, fullEditor);
    }

    //This method is called by the IME whenever the view that returned an 
    // instance of this class to the IME from its onCreateInputConnection() 
    // gains focus.
    @Override
    public Editable getEditable() {
      //Some versions of the Google Keyboard (LatinIME) were delivered with a 
      // bug that causes KEYCODE_DEL to no longer be generated once the number 
      // of KEYCODE_DEL taps equals the number of other characters that have 
      // been typed.  This bug was reported here as issue 62306.
      //
      // As of this writing (1/7/2014), it is fixed in the AOSP code, but that 
      // fix has not yet been released.  Even when it is released, there will 
      // be many devices having versions of the Google Keyboard that include the bug
      // in the wild for the indefinite future.  Therefore, a workaround is required.
      // 
      //This is a workaround for that bug which just jams a single garbage character 
      // into the internal buffer that the keyboard THINKS it is editing even 
      // though we have specified TYPE_NULL which *should* cause LatinIME to 
      // generate key events regardless of what is in that buffer.  We have other
      // code that attempts to ensure as the user edites that there is always 
      // one character remaining.
      // 
      // The problem arises because when this unseen buffer becomes empty, the IME
      // thinks that there is nothing left to delete, and therefore stops 
      // generating KEYCODE_DEL events, even though the app may still be very 
      // interested in receiving them.
      //
      //So, for example, if the user taps in ABCDE and then positions the 
      // (app-based) cursor to the left of A and taps the backspace key three 
      // times without any evident effect on the letters (because the app's own 
      // UI code knows that there are no letters to the left of the 
      // app-implemented cursor), and then moves the cursor to the right of the 
      // E and hits backspace five times, then, after E and D have been deleted, 
      // no more KEYCODE_DEL events will be generated by the IME because the 
      // unseen buffer will have become empty from five letter key taps followed 
      // by five backspace key taps (as the IME is unaware of the app-based cursor 
      // movements performed by the user).  
      //
      // In other words, if your app is processing KEYDOWN events itself, and 
      // maintaining its own cursor and so on, and not telling the IME anything 
      // about the user's cursor position, this buggy processing of the hidden 
      // buffer will stop KEYCODE_DEL events when your app actually needs them - 
      // in whatever Android releases incorporate this LatinIME bug.
      //
      // By creating this garbage characters in the Editable that is initially
      // returned to the IME here, we make the IME think that it still has 
      // something to delete, which causes it to keep generating KEYCODE_DEL 
      // events in response to backspace key presses.
      //
      // A specific keyboard version that I tested this on which HAS this 
      // problem but does NOT have the "KEYCODE_DEL completely gone" (issue 42904)
      // problem that is addressed by the deleteSurroundingText() override below 
      // (the two problems are not both present in a single version) is 
      // 2.0.19123.914326a, tested running on a Nexus7 2012 tablet.  
      // There may be other versions that have issue 62306.
      // 
      // A specific keyboard version that I tested this on which does NOT have 
      // this problem but DOES have the "KEYCODE_DEL completely gone" (issue 
      // 42904) problem that is addressed by the deleteSurroundingText() 
      // override below is 1.0.1800.776638, tested running on the Nexus10 
      // tablet.  There may be other versions that also have issue 42904.
      // 
      // The bug that this addresses was first introduced as of AOSP commit tag 
      // 4.4_r0.9, and the next RELEASED Android version after that was 
      // android-4.4_r1, which is the 

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...