2014-05-12 87 views
5

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

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

我试图调度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); 
    } 

这些都不被解雇,虽然除非后退按钮被按下,但我需要的空格键来触发事件。

感谢您提供的任何帮助。

UPDATE

下面是我对如何创建QueryEditor片段和事件处理程序创建

@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代码。

+0

此问题中的信息及其接受的答案可能有所帮助:http://stackoverflow.com/questions/5419766/how-to-capture-soft-keyboard-input-in-a-view –

+0

你能写吗你怎么激活软键盘按空格键?它是EditText视图还是以编程方式完成?按空格键时重点在哪里? –

+0

@Loop它是由用户在弹出键盘的编辑文本内部单击完成的,用户按下软空格键应触发事件。 – Boardy

回答

2

在活动此实现应该工作:

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

你的代码不同的是,我打电话super.dispatchKeyEvent()所有其他键比SPACE_BAR。如果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。对于其他按键,请致电super.onKeyUp();

至少,但最重要的是,如果您有视图(例如EditText)拥有当前焦点并显示该视图的键盘,那么上面的代码根本不会被调用(在活动)。如果是这种情况,您必须实施监听器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键盘事件,你应该预料到这样的键盘事件从硬件键盘仅 来。您绝对不应该依靠软键输入法(屏幕键盘)上的任何按键接收键盘 事件。

但是,我发现如何克服这个问题。我有我的基础上搜索查看成分的研究和发现,下面的代码将做的工作:

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

+0

感谢您的帮助我已经尝试过。但它似乎并没有为我工作。我想我忘了提及,不知道它的原因,但EditText是在一个活动所托管的片段内。我已经尝试通过片段和活动设置事件侦听器,但都没有触发事件 – Boardy

+0

您可以粘贴更多代码吗?特别是在EditText被设置和使用该EditText的XML文件的情况下。 TextView.OnEditorActionListener绝对是正确的选择,你必须做其他事情阻止它。 –

+0

我已经发布了更多的代码作为请求 – Boardy

-1

我尝试了dispatchkeyevents和onkeydown两种方法,对于软键盘他们都没有工作。至少不是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(); 
      } 
     } 

    }); 
} 

} 
+0

你的答案是非常错误的。关键代码和操作是完全不同的事情,它们不单独提供。而且,比较keyCode值和ACTION_UP是没有意义的。 –

6

部分在于KeyEvent API documentation

软输入法都可以使用输入 多个文本和创造性的方式,也不能保证任何按键在软键盘上 会产生一个关键事件:这由IME自行决定,并且在 事实上,不鼓励发送这样的事件。您绝对不应该依赖于 接收KeyEvents用于软输入方法上的任何键。特别是, 默认的软件键盘将永远不会发送任何关键事件到任何针对Jelly Bean或更高版本的 应用程序,并且只会发送事件 ,用于删除和返回键的应用程序 针对冰淇淋三明治或更早版本。请注意,其他软件 输入法可能永远不会发送关键事件,而不考虑版本。 如果您需要 与软件键盘的特定交互,请考虑使用编辑器操作(如IME_ACTION_DONE),因为它会向用户提供更多 关于您的应用程序如何响应按键 的可见性。

这是由谷歌工程师留下了comment

的答案很简单。应用程序应该从来没有依靠密钥 事件来管理用户输入。原因是,它会导致很差的用户体验。

首先,太多情况下,它不起作用。它 不适用于CJK语言。它无法正确使用手势输入,语音输入或切换 输入,或任何新的创造性输入法开发人员未来可能会提出 。实际上,唯一适用的情况是只有 最差输入体验的受限情况:传统的 类似硬件键盘的输入方法,这对于移动时代来说并不合适。

这就是为什么Android定义了一个丰富的API,IME通过它将 传递给应用程序。它是方法不可知和语言不可知的,并且所有的软件输入方法都在实现它。应用程序是 应该使用此API,并使用EditText是最简单的 这样做(下面更多)。

请停止依靠遗留键事件进行文本输入 - AT ALL。它 是很好的支持他们,但要求他们是不利于每个人。它 打破了一致性,它将一些语言锁定在你的应用之外,而它 强迫用户进行比他们期望的更糟糕的体验,比如Android上的 。并且如评论#14所述,输入方法明确地是 ,根本没有义务发送关键事件,尽管有些可以选择 来完成它。

有两种实现富文本输入API的简单方法。 这两个都将需要一些在Java土地上完成。第一个是 只是使用EditText。如果您的应用需要进行自己的渲染,那么 可以根据您的要求进行子类化处理,或者在您对文本进行任何更改时将其隐藏。你也可以使用DynamicLayout和 Editable来达到同样的效果。另一种可能性是 通过延长 BaseInputConnection实现直接InputConnection API,但是这是努力工作的LOT,应该 一般只需要通过有非常具体的 需求,至于文字版,喜欢的应用程序来完成IDE或文字处理器。