Android SoftKeyboard onKeyDown/Up not detecting 'alternative' keys

前端 未结 3 673
忘了有多久
忘了有多久 2020-12-19 15:50

I have a view which handles input for me, I pop up a keyboard and set the view focusable. Now I can get certain key presses...

@Override
public boolean onKey         


        
相关标签:
3条回答
  • 2020-12-19 16:25

    Edit:

    I'm not sure what is causing the onKeyDown not to be called at all. Perhaps it's an issue with your view? There may be a better answer than my solution because of this. Either way, this might work:

    Instead of using the onKeyDown from the view, override dispatchKeyEvent at the activity level. This will handle your key event before it gets to the window manager, so make sure to call super on any key events you do not explicitly handle.

    Example using the ACTION_DOWN (as every event has both ACTION_UP and ACTION_DOWN) since your example used onKeyDown:

    @Override
    public boolean dispatchKeyEvent(KeyEvent event){
        if(event.getAction() == KeyEvent.ACTION_UP) {
            return super.dispatchKeyEvent(event);
        }
    
        if (keyCode == KeyEvent.KEYCODE_DEL) {
        } else if (keyCode == KeyEvent.KEYCODE_BACK) {
        } else if (keyCode == KeyEvent.KEYCODE_ENTER) {
        } else {
            return super.dispatchKeyEvent(event);
        }
    }
    

    NOW (sorry about that)

    You can try:

    char key = (char)event.getUnicodeChar();
    

    Instead of

    char key = event.getDisplayLabel();
    

    getDisplayLabel() will only give you the key that is displayed on the keyboard, which as you point out, is not necessarily the character the user has selected.

    0 讨论(0)
  • 2020-12-19 16:28

    When the keyboard is open, onKeyDown() and onKeyUp() methods don't work properly because Android considers on-screen keyboard as a separate activity.

    The easiest way to achieve what you want is to override onKeyPreIme() method on your view. For example, if you're trying to capture onKeyDown from an EditText, create a new Class which extends EditText, and override the onKeyPreIme() method:

    public class LoseFocusEditText extends EditText {
    
        private Context mContext;
    
        protected final String TAG = getClass().getName();
    
        public LoseFocusEditText(Context context) {
            super(context);
            mContext = context;
        }
    
        public LoseFocusEditText(Context context, AttributeSet attrs) {
            super(context, attrs);
            mContext = context;
        }
    
        public LoseFocusEditText(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            mContext = context;
        }
    
        @Override
        public boolean onKeyPreIme(int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_BACK) {
    
                //hide keyboard
                InputMethodManager mgr = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
                mgr.hideSoftInputFromWindow(this.getWindowToken(), 0);
    
                //lose focus
                this.clearFocus();
    
                return true;
            }
            return false;
        }
    }
    

    This was tested on kitkat / htc one.

    0 讨论(0)
  • 2020-12-19 16:29

    Got it :)

    public boolean onKey(View v, int keyCode, KeyEvent event) {
        if(event.getAction()==KeyEvent.ACTION_DOWN) return true;
        if(keyCode==KeyEvent.KEYCODE_ALT_LEFT || keyCode==KeyEvent.KEYCODE_ALT_RIGHT || keyCode==KeyEvent.KEYCODE_SHIFT_LEFT || keyCode==KeyEvent.KEYCODE_SHIFT_RIGHT) return true;
    
        if (keyCode == KeyEvent.KEYCODE_DEL) {
            doBackspace();
            return true;
        } else if (keyCode == KeyEvent.KEYCODE_BACK) {
            if(this.avl!=null) this.avl.onInputCancelled(this);
            return false;
        } else if (keyCode == KeyEvent.KEYCODE_ENTER) {
            inputstarted=false;
            if(this.avl!=null) this.avl.onInputFinished(this,this.text,celldata);
            return true;
        }   
    
        String key = "";
        if (event.getAction()==KeyEvent.ACTION_UP) key = String.valueOf((char)event.getUnicodeChar()).toUpperCase();
        else if (event.getAction()==KeyEvent.ACTION_MULTIPLE) key = String.valueOf(event.getCharacters()).toUpperCase();
        return process(key);
    }
    

    The important part is blocking the ALT_LEFT/SHIFT_LEFT/etc keycodes and differentiate between ACTION_UP/ACTION_MULTIPLE and either use event.getUnicodeChar() or event.getCharacters().

    It works now, I can get all of the chars and even KEYCODE_DEL works on the mobile. But on the tablet I still get no callback for the delete key. Seems like a bad bug, as today in the morning it worked fine even on tablet.

    0 讨论(0)
提交回复
热议问题