为了账号安全,请及时绑定邮箱和手机立即绑定

如何在安卓设备上制作 KeyDown 和 KeyUp?

如何在安卓设备上制作 KeyDown 和 KeyUp?

墨色风雨 2022-05-21 20:18:06
我有个问题。我正在Android 设备上制作Keystroke 动态应用程序。现在,我用度量字符串和EditText. 我想在软件键盘上捕捉KeyDown和KeyUp事件。我的问题是,使用 Java 在 Android 上捕获KeyUp和使用的最佳方法是什么?KeyDown如果EditText是一个好的选择?如果它有方法来捕捉任何按键?编辑我想从上面的字符串中检测键并测量按下它的时间,(例如开始测量KeyDown和停止KeyUp)。如果可能的话,我想阻止我的test string(它的9RJhl6aH0n,就像我的屏幕中一样)中未提及的其他键编辑2到目前为止我所取得的成就是这样的,但是default当我编码 line: 时,我的应用程序崩溃了measureText.setText("")。它工作得很好,但它仍然不会触发KeyDown(或KeyPress)。这些方法仅在KeyUp用户刚刚输入字母时运行。顺序很重要!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;        }    });
查看完整描述

3 回答

?
忽然笑

TA贡献1806条经验 获得超5个赞

我会说,那OnKeyUp&OnKeyDown事件不会削减它,因为软键盘几乎不会发出任何这些。这是一个粗略的原型,它根据预期的字符串过滤字符的输入。有很大的改进空间;虽然自定义实现仍然是比尝试使用框架方法更好的方法,框架方法可能只捕获⌫键......在FilteredEditText任何输入出现在屏幕上之前捕获它 - 为了实现击键模式记录器,预期的字符串需要被分成一个ArrayList,它也将保持各个击键之间的持续时间;一旦记录下来,就可以使用收集到的信息进行比较。


/**

 * Filtered {@link AppCompatEditText}

 * @author Martin Zeitler

 */

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);

    }

}

使用示例:


FilteredEditText mTextInput = findViewById(R.id.text_input);

mTextInput.setExpectedString("9RJhl6aH0n");

日志输出:


D/FilteredEditText: input accepted: 9

D/FilteredEditText: input rejected: r - expected: R

D/FilteredEditText: input rejected: 4 - expected: R

D/FilteredEditText: input accepted: R

到目前为止,我已经使用软件键盘对其进行了测试……而我目前无法使用 BT 硬件键盘对其进行测试,因为电池是空的。我假设,InputFilter捕获所有输入。


几乎没有任何事件是由软件键盘触发的OnKeyUp,OnKeyDown因为当知道击键何时被过滤时,这仍然会导致类似的模式——即使无法测量击键的持续时间,也无法测量键盘的攻击速度。击键,由于软件键盘的限制 - 唯一可能的解决方法是强制使用硬件键盘或创建一个为所有键发出这些事件的软件键盘(与默认值相反GBoard,也不是SwiftKey)。我现在只是想知道滑动打字和语音打字......因为这是物理击键动力学几乎没有考虑过的事情。甚至留下了反馈GBoard,因为在某些情况下选择性地发出键码会很有帮助。


该文档还明确指出:


在使用类和相关 API 处理键盘事件时KeyEvent,您应该期望此类键盘事件仅来自硬件键盘。您永远不应依赖接收软输入法(屏幕键盘)上任何键的键事件。


人们仍然可以使用硬件事件,同时拥有发出它们的按钮;例如:


/**

 * Fake Hardware {@link AppCompatButton}

 * @see <a href="https://developer.android.com/reference/android/view/KeyEvent">KeyEvent</a>

 * @author Martin Zeitler

 */

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;

            }

        });

    }

}

问题只是,例如。KeyEvent.KEYCODE_9并且KeyEvent.KEYCODE_NUMPAD_9不一样,因此String在数字键的情况下总是必须比较表示。


查看完整回答
反对 回复 2022-05-21
?
凤凰求蛊

TA贡献1825条经验 获得超4个赞

您只需使用活动的调度事件


像这样:


 @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);

    }

这样,您可以轻松控制 KeyDown 和 KeyUp 事件。


在这里你可以找到所有的 MotionEvents


对于软键,您只能使用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


        }


    });  


查看完整回答
反对 回复 2022-05-21
?
浮云间

TA贡献1829条经验 获得超4个赞

您需要仔细覆盖以下功能:


@Override

public boolean onKeyDown(int keyCode, KeyEvent event) {


    switch (keyCode) {

        case KeyEvent.KEYCODE_A:

        {

            //your Action code

            return true;

        }

    }

    return super.onKeyDown(keyCode, event);

}

对于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) 

    {

    }

);


查看完整回答
反对 回复 2022-05-21
  • 3 回答
  • 0 关注
  • 232 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信