DispatchKeyEvent侦听正在按下的空格键

Boa*_*rdy 5 android

我正在开发一个Android项目,我需要检查空格键何时被按下sos我可以执行某个功能.

问题是,它正在模拟器上工作,但不在我的实际设备上.我想这可能是因为我的模拟器使用的是物理键盘,而不是屏幕上的虚拟键盘,但在实际设备上进行测试时,它使用的是虚拟键盘.

我正在尝试调度keyevent

@Override
    public boolean dispatchKeyEvent(KeyEvent event)
    {

        if (event.getKeyCode() == KeyEvent.KEYCODE_SPACE
                && event.getAction() == KeyEvent.ACTION_UP)
        {
            QueryEditor queryEditor = (QueryEditor)getSupportFragmentManager().findFragmentById(R.id.fragment_queryEditor);
            queryEditor.formatQueryText();
            return true;
        }
        }
Run Code Online (Sandbox Code Playgroud)

我也试过按键

@Override
    public boolean onKeyDown(int keyCode, KeyEvent event)
    {
        if (keyCode == KeyEvent.KEYCODE_BACK)
        {
            disconnectDatabase();
        }
        else if (keyCode == KeyEvent.KEYCODE_DEL)
        {
            QueryEditor queryEditor = (QueryEditor)getSupportFragmentManager().findFragmentById(R.id.fragment_queryEditor);
            queryEditor.formatQueryText();
        }

        return super.onKeyDown(keyCode, event);
    }
Run Code Online (Sandbox Code Playgroud)

除非按下后退按钮但我需要空格键来触发事件,否则这些都不会被触发.

感谢您的任何帮助,您可以提供.

UPDATE

下面是我如何创建QueryEditor Fragment并创建事件处理程序的代码

@Override
    public void onActivityCreated(Bundle savedInstanceState)
    {
        super.onActivityCreated(savedInstanceState);

        iQueryEditor = (IQueryEditor)this;
        iErrorHandler = (IErrorHandler)this;

        txtQueryEditor = (EditText)getActivity().findViewById(R.id.query_txtQueryEditor);

        btnSubmitQuery = (ImageButton)getActivity().findViewById(R.id.query_btnPerformQuery);
        btnClearQuery = (ImageButton)getActivity().findViewById(R.id.query_btnDeleteQuery);

        txtQueryEditor.addTextChangedListener(new QueryTextChanged(getActivity(), txtQueryEditor, iQueryEditor));
        setDatabaseUsed();
        txtQueryEditor.setOnEditorActionListener(new OnEditorActionListener() {

            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER))
                        || actionId == EditorInfo.IME_ACTION_DONE)
                {
                    executeQuery();
                    return true;
                }
                else if (event.getKeyCode() == KeyEvent.KEYCODE_SPACE && event.getAction() == KeyEvent.ACTION_UP)
                {
                    Toast.makeText(getActivity(), "Space Bar Pressed", Toast.LENGTH_SHORT).show();
                    return true;
                }
                return false;
            }
        });

        btnSubmitQuery.setOnClickListener(mBtnSubmitQueryListener);
        btnClearQuery.setOnClickListener(mBtnDeleteQueryListener);
    }
Run Code Online (Sandbox Code Playgroud)

txtQueryEditor是我试图接收空格键事件的EditText.

Man*_*ani 7

部分答案在于KeyEvent API文档:

由于软输入方法可以使用多种创造性的输入文本方式,因此无法保证软键盘上的任何按键都会产生关键事件:这由IME自行决定,实际上不鼓励发送此类事件.您永远不应该依赖于在软输入方法上接收任何键的KeyEvent.特别是,默认软件键盘永远不会向任何针对Jelly Bean或更高版本的应用程序发送任何键事件,并且只会将删除和返回键的某些按键发送给目标为Ice Cream Sandwich或更早版本的应用程序.请注意,无论版本如何,其他软件输入方法都可能永远不会发送关键事件.如果您需要与软件键盘进行特定交互,请考虑使用IME_ACTION_DONE之类的编辑器操作,因为它可以让用户更清楚地了解应用程序对按键操作的反应.

以下是Google工程师留下的评论:

答案很简单.应用程序永远不应该依赖关键事件来管理用户输入.原因是,它会导致非常糟糕的用户体验.

首先,有太多的情况不起作用.它对CJK语言不起作用.它无法通过手势输入,语音输入或切换输入正常工作,或者开发人员未来可能提出的任何新的创造性输入方法.实际上,唯一可行的情况是仅针对最差输入体验的受限情况:传统的硬件键盘式输入方法,这种方式不适合移动时代.

这就是为什么Android定义了一个丰富的API,IME通过它与应用程序进行通信.它与方法无关,与语言无关,所有软件输入方法都在实现它.应用程序应该使用这个API,使用EditText是最简单的方法(下面将详细介绍).

请停止依赖传统的关键事件进行文本输入 - 全部.支持他们很好,但要求他们对每个人都不好.它打破了一致性,它将一些语言锁定在您的应用程序之外,并且它迫使用户进入比他们在Android上预期的更差的体验.正如评论#14所述,输入方法明显没有义务发送关键事件,尽管有些人可能会选择这样做.

有两种简单的方法来实现富文本输入API.两者都需要一些在Java领域完成的.第一个是简单地使用EditText.如果您的应用需要自己进行渲染,则可以将其子类化(如果适合您),或者在对文本进行任何更改时将其隐藏.您还可以使用DynamicLayout和Editable来实现相同的效果.另一种可能是直接通过扩展BaseInputConnection实现InputConnection API,但是这是一个LOT的辛勤工作,一般只需要由有关于文本编辑,像一个IDE或文字处理非常特殊的需求的应用程序来完成.


Dam*_*tla 4

您的 Activity 中的此实现应该有效:

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
    if (event.getKeyCode() == KeyEvent.KEYCODE_SPACE && event.getAction() == KeyEvent.ACTION_UP) {
        Log.d("test", "[Dispatch] Space bar pressed! " + event);
        return true;
    }
    return super.dispatchKeyEvent(event);
}
Run Code Online (Sandbox Code Playgroud)

与您的代码的区别在于,我正在调用super.dispatchKeyEvent()除 SPACE_BAR 之外的所有其他键。如果dispatchKeyEvent返回trueonKeyUp()则不会被触发。因此,如果您只想监视空格键事件,只需注释行//return true;

如果你使用方法,它也会很好地工作onKeyUp()。不要使用onKeyDown(),如果用户手指握得太久,可能会被调用几次。

@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_SPACE) {
        Log.d("test", "Space bar pressed!");
        return true;
    }
    return super.onKeyUp(keyCode, event);
}
Run Code Online (Sandbox Code Playgroud)

这里我使用类似的方法。如果您的 if 语句为 true,则处理事件并返回 true。对于其余的钥匙,请致电super.onKeyUp();

至少,但最重要的是,如果您有拥有当前焦点的视图(例如 EditText)并且为该视图显示键盘,则根本不会调用上面的代码(在 Activity 中)。如果是这种情况,您必须实现侦听器TextView.OnEditorActionListener并注册该视图调用setOnEditorActionListener(TextView.OnEditorActionListener l)

viewWithFocus.setOnEditorActionListener(new TextView.OnEditorActionListener() {
    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        if (event.getKeyCode() == KeyEvent.KEYCODE_SPACE && event.getAction() == KeyEvent.ACTION_UP) {
            Log.d("test", "[Editor] Space bar pressed! " + event);
            //TODO implement your action here
            return true;//remove this line if you want edit text to create space
        }
        return false;
    }
});
Run Code Online (Sandbox Code Playgroud)

作为替代方案,您可以覆盖此视图并onKepUp()像上面一样实现。

更新

上述解决方案适用于硬件键盘。抱歉没有更仔细地检查这一点。

来自 Android 文档

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

然而,我找到了如何克服这个问题。我基于 SearchView 组件进行了研究,发现以下代码可以完成这项工作:

editText.addTextChangedListener(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        char last = s.charAt(s.length()-1);
        if (' ' == last) {
            Log.i("test", "space pressed");
        }
    }

    @Override
    public void afterTextChanged(Editable s) {
    }
});
Run Code Online (Sandbox Code Playgroud)

对于 IME 操作,请继续使用TextView.OnEditorActionListener.