您好,登錄后才能下訂單哦!
外圍輸入設備,例如:藍牙鍵盤,usb鍵盤,barcode掃碼槍...
由于平時都是在做純軟件程序的開發,博主在需求遇到android設備與外圍設備交互時有點不知所措。我最初的思路是這樣:既然是藍牙連接,那不就是socket嗎,那么截獲他的I/O流然后解析里面的內容...那不就ok啦?
然而事情并沒有那么簡單,首先解析數據流是一個難點,再一個萬一我藍牙連接換成usb連接,或者wifi,那不就得再改了?
參考了網上的方案后發現,外圍設備是通過KeyEvent事件機制android交互的,既然是這樣那我就不用再關心外設是通過什么方式連接的,直接截獲外設發送的事件,并且還可直接獲取到輸入內容!
以下就是我寫的的藍牙掃碼槍的類庫,已上傳至github
https://github.com/sally519/BarCode-android
我們直接來看看是怎么用的
public class MainActivity extends AppCompatActivity implements BarCodeIpml.OnScanSuccessListener {
//activity實現了BarCodeIpml.OnScanSuccessListener借口,即回調成功時的借口
private BarCodeIpml barCodeIpml = new BarCodeIpml();
private TextView textView;
private TextView mTv;
private static final String TAG="MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//設置掃碼成功的回調監聽
barCodeIpml.setOnGunKeyPressListener(this);
mTv = (TextView) findViewById(R.id.mTv);
}
//重寫事件分發的方法
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (barCodeIpml.isEventFromBarCode(event)) {
barCodeIpml.analysisKeyEvent(event);
return true;
}
Log.e("keycode",event.getKeyCode()+"");
return super.dispatchKeyEvent(event);
}
//在activity獲得焦點時
@Override
protected void onResume() {
super.onResume();
try {
barCodeIpml.hasConnectBarcode();
} catch (DevicePairedNotFoundException e) {
e.printStackTrace();
Log.e(TAG, "badcode槍未連接!");
}
}
//借口的實現,掃碼成功后的回調,寫你自己的實現
@Override
public void onScanSuccess(String barcode) {
Log.e("mcallback", barcode);
mTv.setText(barcode);
}
//與activity生命周期綁定,防止內存泄漏
@Override
protected void onDestroy() {
super.onDestroy();
barCodeIpml.onComplete();
}
}
從注釋和方法的名稱我們大概可以判斷出各個方法的作用,我們來看其中最關鍵的一個方法
大家首先需要知道,這個方法返回一個boolean
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (barCodeIpml.isEventFromBarCode(event)) {
barCodeIpml.analysisKeyEvent(event);
return true;
}
Log.e("keycode",event.getKeyCode()+"");
return super.dispatchKeyEvent(event);
}
當我返回一個true的時候,這個事件就會被我們消費(類庫里的主要操作就是獲取KeyCode,即外圍設備輸入的內容),不會再交給系統處理。在以上的代碼中我拿到這個事件后我調用類庫的方法判斷他是否來自外圍設備,如果是的話我們自己將其截獲處理,不再交給系統,否則的話我們交由系統處理。這個方法大家應該比較熟悉,我們常常用來重寫back鍵或者home鍵。
之后我們進去dispatchKeyEvent里面看一下,系統是如何處理這個事件的,直接在activity中查看源碼
/**
* Called to process key events. You can override this to intercept all
* key events before they are dispatched to the window. Be sure to call
* this implementation for key events that should be handled normally.
*
* @param event The key event.
*
* @return boolean Return true if this event was consumed.
*/
public boolean dispatchKeyEvent(KeyEvent event) {
onUserInteraction();
// Let action bars open menus in response to the menu key prioritized over
// the window handling it
final int keyCode = event.getKeyCode();
if (keyCode == KeyEvent.KEYCODE_MENU &&
mActionBar != null && mActionBar.onMenuKeyEvent(event)) {
return true;
} else if (event.isCtrlPressed() &&
event.getUnicodeChar(event.getMetaState() & ~KeyEvent.META_CTRL_MASK) == '<') {
// Capture the Control-< and send focus to the ActionBar
final int action = event.getAction();
if (action == KeyEvent.ACTION_DOWN) {
final ActionBar actionBar = getActionBar();
if (actionBar != null && actionBar.isShowing() && actionBar.requestFocus()) {
mEatKeyUpEvent = true;
return true;
}
} else if (action == KeyEvent.ACTION_UP && mEatKeyUpEvent) {
mEatKeyUpEvent = false;
return true;
}
}
源碼不算復雜,注釋說你可以在事件發送到窗口前攔截此事件,但要對關鍵事件執行,這里說的關鍵事件可能是back鍵或者home鍵。
我們一步一步來做下分析,先來看看onUserInteraction()
/**
* Called whenever a key, touch, or trackball event is dispatched to the
* activity. Implement this method if you wish to know that the user has
* interacted with the device in some way while your activity is running.
* This callback and {@link #onUserLeaveHint} are intended to help
* activities manage status bar notifications intelligently; specifically,
* for helping activities determine the proper time to cancel a notfication.
*
* <p>All calls to your activity's {@link #onUserLeaveHint} callback will
* be accompanied by calls to {@link #onUserInteraction}. This
* ensures that your activity will be told of relevant user activity such
* as pulling down the notification pane and touching an item there.
*
* <p>Note that this callback will be invoked for the touch down action
* that begins a touch gesture, but may not be invoked for the touch-moved
* and touch-up actions that follow.
*
* @see #onUserLeaveHint()
*/
public void onUserInteraction() {
}
實現居然是空的,注釋上說當事件分發到activity的時候調用,你可以實現這個方法來獲知用戶是否在和當前activity交互。onUserInteraction()和onUserLeaveHint()是本意是幫助activity更好的管理推送消息,后者將會跟隨前者一起調用,上面還說onUserInteraction()可能不會跟隨著手指的移動而調用。
由此,我們也知道onUserInteraction()會在事件分發最初的時候調用,我們可以用這和方法監聽用戶于activity的交互。
我們接著往下看
// Let action bars open menus in response to the menu key prioritized over
// the window handling it
final int keyCode = event.getKeyCode();
if (keyCode == KeyEvent.KEYCODE_MENU &&
mActionBar != null && mActionBar.onMenuKeyEvent(event)) {
return true;
}
首先獲取用戶的輸入內容keyCode ,之后的意圖很明顯,如果用戶點擊的是ToolBar或者ActionBar的菜單那直接return了一個true,我們剛剛說過return一個true的意思就是事件不再交給系統處理,return一個false則依舊需要交給系統處理,這里的目的想必就是把我們的事件拋給ToolBar或者ActionBar來處理。
接著往下看
else if (event.isCtrlPressed() &&
event.getUnicodeChar(event.getMetaState() & ~KeyEvent.META_CTRL_MASK) == '<') {
// Capture the Control-< and send focus to the ActionBar
final int action = event.getAction();
if (action == KeyEvent.ACTION_DOWN) {
final ActionBar actionBar = getActionBar();
if (actionBar != null && actionBar.isShowing() && actionBar.requestFocus()) {
mEatKeyUpEvent = true;
return true;
}
} else if (action == KeyEvent.ACTION_UP && mEatKeyUpEvent) {
mEatKeyUpEvent = false;
return true;
}
第一個判斷條件event.isCtrlPressed() &&event.getUnicodeChar(event.getMetaState() & ~KeyEvent.META_CTRL_MASK) == '<'或許有點抽象,但下面的注釋告訴我們這段代碼的意圖是捕獲“<”鍵,之后判斷ActionBar是否在請求焦點,如果是的話強行將ACTION_UP的事件(也就是按壓屏幕后抬起那一下)消費,不再由系統處理,并且強行讓ActionBar獲得焦點,交由ActionBar處理。否則告訴activityACTION_UP的事件還未被消費。
搞懂了以上的內容我們就可以隨意截獲事件,并通過KeyCode獲知是否點擊了虛擬鍵盤,具體點擊的是哪一個鍵?如果是回車鍵,那就將其內容通過回調發送給activity,由此來獲取外圍輸入設備的內容。具體可查看 https://github.com/sally519/BarCode-android 中的使用詳情。
#小結
好了,我們來總結幾個需要特別注意的點
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。