How to make KeyDown and KeyUp on android device?

淺唱寂寞╮ 提交于 2019-12-07 12:29:06

问题


I have a question.

I'm making Keystroke dynamics app on android devices.

For now, I make an Activity with measure string and EditText. I want to catch KeyDown and KeyUp events on software keyboard.

My question is, what is the best way to catch KeyUp and KeyDown on Android with Java? If EditText is a good choice? If it have methods to catch any keypresses?

EDIT

I want to detect keys from string above and measure time of pressing it, (start measure on KeyDown and stop on KeyUp for example). If its possible, i want to block other keys that is not mentioned in my test string (its 9RJhl6aH0n, like in my screen)

EDIT2

What i achieve so far is something like this, but my app crashes on default, when I coded line: measureText.setText(""). It works pretty ok, but still it won't trigger on KeyDown (or KeyPress). These methods run only on KeyUp, when user just typed letter. Order is very important!

measureText.addTextChangedListener(new TextWatcher(){
        @Override
        public void afterTextChanged(Editable arg0) {
            switch(measureText.getText().toString()){
                case "9":
                    break;
                case "9R":
                    break;
                case "9RJ":
                    break;
                case "9RJh":
                    break;
                case "9RJhl":
                    break;
                case "9RJhl6":
                    break;
                case "9RJhl6a":
                    break;
                case "9RJhl6a0":
                    break;
                case "9RJhl6a0n":
                    break;
                default:
                    measureText.getText().clear();
                    break;

            }
            return;
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            // TODO Auto-generated method stub
            return;
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

            return;
        }
    });

回答1:


OnKeyUp & OnKeyDown events won't cut it, because soft keyboards barely emit any of these.

here's a rough prototype, which filters the input of characters according to the expected string. there is lots of space for improvement; while a custom implementation is still a better approach than trying to use framework methods, which may only catch the key... the FilteredEditText catches any input before it may appear on screen - in order to realize a keystroke pattern recorder, the expected string would need to be split into an ArrayList, which would also hold the duration in between the individual keystrokes; once recorded one can use the gathered information for comparison.

/**
 * Filtered {@link AppCompatEditText}
 * @author Martin Zeitler
 * @version 1.0.0
**/
public class FilteredEditText extends AppCompatEditText {

    private static final String LOG_TAG = FilteredEditText.class.getSimpleName();

    private String expectedString = null;

    public FilteredEditText(Context context) {
        super(context);
    }

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

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

    public void setExpectedString(@NonNull String value) {
        this.expectedString = value;
        this.setupInputFilter();
    }

    public void setupInputFilter() {
        this.setFilters(new InputFilter[] {
            new InputFilter() {
                public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int destStart, int destEnd) {
                    if (source.length() > 0 && source.charAt(end-1) == expectedString.charAt(destEnd)) {

                        /* valid input received */
                        Log.d(LOG_TAG, "input accepted: " + String.valueOf(source.charAt(end-1)));
                        return source;

                    } else {

                        /* invalid input received */
                        Log.d(LOG_TAG, "input rejected: " + String.valueOf(source.charAt(end-1)) + " - expected: " + String.valueOf(expectedString.charAt(destEnd)));
                        return "";
                    }
                }
            }
        });
    }

    /** hardware event  */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        Log.d(LOG_TAG, "onKeyDown()");
        return super.onKeyDown(keyCode, event);
    }

    /** hardware event  */
    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        Log.d(LOG_TAG, "onKeyUp()");
        return super.onKeyUp(keyCode, event);
    }
}

usage:

FilteredEditText mTextInput = findViewById(R.id.text_input);
mTextInput.setExpectedString("9RJhl6aH0n");

logcat output:

D/FilteredEditText: input accepted: 9
D/FilteredEditText: input rejected: r - expected: R
D/FilteredEditText: input rejected: 4 - expected: R
D/FilteredEditText: input accepted: R

so far I've tested it with a software keyboard ...while I currently cannot test it with a BT hardware keyboard, because the batteries are empty. I'd assume, that the InputFilter catches all input.

that barely any OnKeyUp and OnKeyDown event is being triggered by software keyboards can be compensated, because when knowing when a keystroke is being filtered, this still leads to a comparable pattern - even if the duration of the keystroke cannot be measured, nor the attack velocity of the keystroke, due to the limitations of a software keyboard - the only possible workarounds would be enforcing hardware keyboards or creating a software keyboard which emits these events for all the keys (contrary to the default GBoard, nor SwiftKey). I'd just wonder about swipe-typing and voice-typing now ... because this is something barely considered by physical keystroke dynamics. even left a feedback for GBoard, because optionally emitting key-codes would be helpful in some cases.

the documentation also clearly states it:

When handling keyboard events with the KeyEvent class and related APIs, you should expect that such keyboard events come only from a hardware keyboard. You should never rely on receiving key events for any key on a soft input method (an on-screen keyboard).

one can still use hardware events, while having buttons, which emit them; for example:

/**
 * Fake Hardware {@link AppCompatButton}
 * @see <a href="https://developer.android.com/reference/android/view/KeyEvent">KeyEvent</a>
 * @author Martin Zeitler
 * @version 1.0.0
**/
public class FakeHardwareButton extends AppCompatButton {

    private BaseInputConnection  mInputConnection;

    private int keyCode = KeyEvent.KEYCODE_9;
    private KeyEvent keyDown;
    private KeyEvent keyUp;

    public FakeHardwareButton(Context context) {
        this(context, null);
    }

    public FakeHardwareButton(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public FakeHardwareButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @SuppressLint("ClickableViewAccessibility")
    private void setupInputConnection(View targetView) {

       this.mInputConnection = new BaseInputConnection(targetView, true);
       this.keyDown = new KeyEvent(KeyEvent.ACTION_DOWN, this.keyCode);
       this.keyUp = new KeyEvent(KeyEvent.ACTION_UP, this.keyCode);

       this.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch(event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        mInputConnection.sendKeyEvent(keyDown);
                        return true;

                    case MotionEvent.ACTION_UP:
                        mInputConnection.sendKeyEvent(keyUp);
                        return true;
                }
                return false;
            }
        });
    }
}

the issue is just, that KeyEvent.KEYCODE_9 and KeyEvent.KEYCODE_NUMPAD_9 are not the same, therefore one always has to compare the String representation in case of numeric keys.




回答2:


You just use dispatch event of activity

Like this:

 @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_POINTER_DOWN:
                break;
            case MotionEvent.ACTION_POINTER_UP:
                break;
            case MotionEvent.ACTION_UP:
                break;
            case MotionEvent.ACTION_DOWN:
                break;
        }
            return super.dispatchTouchEvent(ev);
    }

By this, you can easily control the KeyDown and KeyUp event.

Here is you can find all MotionEvents

In the case of Softkeys, you can only use TextChangeListener

    editText.addTextChangedListener(new TextWatcher(){

        @Override
        public void afterTextChanged(Editable arg0) {
            // TODO Auto-generated method stub
  switch (arg0.toString()) {
                    case "9":
                        break;
                    case "9R":
                        break;
                    case "9RJ":
                        break;
                    case "9RJh":
                        break;
                    case "9RJhl":
                        break;
                    case "9RJhl6":
                        break;
                    case "9RJhl6a":
                        break;
                    case "9RJhl6a0":
                        break;
                    case "9RJhl6a0n":
                        break;
                    default:
                        arg0.clear();
                        break;

                }
                return;

        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            // here right logic for getting last char and show it on toast

        }

    });  



回答3:


You need to carefully override the following function:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {

    switch (keyCode) {
        case KeyEvent.KEYCODE_A:
        {
            //your Action code
            return true;
        }
    }
    return super.onKeyDown(keyCode, event);
}

and for the edittext :

mMyEditText.addTextChangedListener(new TextWatcher(){

    public void afterTextChanged(Editable s) 
    {
    }
    public void beforeTextChanged(CharSequence s, int start, int count, int after) 
    {

    }
    public void onTextChanged(CharSequence s, int start, int before, int count) 
    {
    }
);



回答4:


You can use the dispatchKeyEvent(KeyEvent event) in your Activity

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
    Log.i("key pressed", String.valueOf(event.getKeyCode()));
    return super.dispatchKeyEvent(event);
}

To detect the key pressed



来源:https://stackoverflow.com/questions/54364316/how-to-make-keydown-and-keyup-on-android-device

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!