2014-05-12 86 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或文字處理器。