DispatchKeyEvent监听正在按下的空格键

时间:2014-05-12 20:48:15

标签: 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;
        }
        }

我也试过了按键

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

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

感谢您提供的任何帮助。

更新

下面是关于如何创建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);
    }

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

3 个答案:

答案 0 :(得分:7)

部分答案在于KeyEvent API documentation

  

由于软输入法可以使用多种创造性的输入方式   文字,无法保证软键盘上的任何按键都会   生成一个关键事件:这由IME自行决定,并且在   不鼓励发送此类事件的事实。你永远不应该依赖   接收软输入法上任何键的KeyEvents。特别是,   默认软件键盘永远不会向任何键事件发送任何键事件   应用程序目标是Jelly Bean或更高版本,并且只会发送事件   对于一些按下删除键和返回键到应用程序   目标冰淇淋三明治或更早。请注意其他软件   无论版本如何,输入方法都不会发送关键事件。   如果需要,请考虑使用IME_ACTION_DONE之类的编辑器操作   与软件键盘的特定交互,因为它提供了更多   用户对应用程序如何对密钥作出反应的可见性   印刷机。

以下是Google工程师留下的comment

  

答案很简单。应用程序永远依赖于密钥   用于管理用户输入的事件。原因是,它导致了   用户体验很差。

     

首先,有太多的情况不起作用。它   对CJK语言不适用。这是行不通的   正确的手势输入,或语音输入,或切换   输入,或开发人员可能提出的任何新的创造性输入方法   在将来。事实上,唯一可行的情况是   最差投入经验的限制性案例:遗产   硬件键盘式输入法,这是一个不合适的   移动时代。

     

这就是Android定义IME通信的丰富API的原因   到应用程序。它与方法无关,与语言无关,并且   所有软件输入方法都在实现它。应用程序是   应该使用这个API,使用EditText是最简单的   这样做的方式(更多内容见下文)。

     

请停止依赖旧密钥事件进行文字输入 - 全部。它   很好地支持他们,但要求他们对每个人都不好。它   打破一致性,它会锁定你的应用程序中的一些语言   迫使用户进入比他们预期的更糟糕的体验   Android系统。正如注释#14所述,输入方法是明确的   虽然有些人可能会选择,但根本没有义务发送关键事件   这样做。

     

实现富文本输入API有两种简单的方法。   两者都需要一些在Java领域完成的。第一个是   简单地使用EditText。如果您的应用需要自己进行渲染,那么您   如果适合您,可以将其子类化,或者在您使用时隐藏它   呈现文本的任何更改。你也可以使用DynamicLayout和   可编辑达到同样的效果。另一种可能性是   通过扩展直接实现InputConnection API   BaseInputConnection,但这是一个辛苦工作的 LOT 应该   通常只需要具有非常具体的应用程序来完成   关于文本编辑的需求,如IDE或文字处理器。

答案 1 :(得分:3)

您的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);
}

您的代码的不同之处在于我为除SPACE_BAR之外的所有其他键调用super.dispatchKeyEvent()。如果dispatchKeyEvent返回true onKeyUp()则不会被触发。因此,如果您只想监视空格键事件,只需注释行//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);
}

这里我使用类似的方法。如果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;
    }
});

作为替代方案,您可以覆盖此视图并像上面一样实施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) {
    }
});

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

答案 2 :(得分:-1)

我尝试了dispatchkeyevents和onkeydown两种方法,而对于软键盘,它们都没有用。 Atleast不在nexus 7.唯一有效的解决方案是在edittext中添加一个textwatcher。以下是代码:

public class MainActivity extends ActionBarActivity {
EditText editText1;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    editText1 = (EditText) findViewById(R.id.editText1);
    editText1.addTextChangedListener(new TextWatcher() {

        @Override
        public void afterTextChanged(Editable arg0) {
            // TODO Auto-generated method stub

        }

        @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) {
            // TODO Auto-generated method stub
            String lastChar = s.toString().substring(s.length() - 1);
            if (lastChar.equals(" ")) {
                Toast.makeText(MainActivity.this, "space bar pressed",
                        Toast.LENGTH_SHORT).show();
            }
        }

    });
}

}