【Framworks】增加对USB键盘组合键的判断


最近来了一个需求,需要识别安卓外接键盘的组合键,简单看了下,写了一个比较粗糙的解决方案,放这里曝光下,万一,有人可以优化优化?好吧,其实只是我自己想记录下来。

正文:

先分析下安卓的input事件,参阅:https://blog.csdn.net/u011913612/article/details/53064324

通过上面大佬的详细分析,就可以定位到添加的位置了,底层部分不管,java层主要在 frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java$interceptKeyBeforeQueueing方法中

找到了代码位置,自然就好加了,写个接口:

public interface IMultKeyTrigger {

/**
* 检查输入的按键是否是对应组合键某个位置
*
* @param keycode
* @param eventTime
*/
void checkKey(int keycode, long eventTime);

/**
* 清除所有记录的键
*/
void clearKeys();

}

实现一下:

public class MultKeyTrigger implements IMultKeyTrigger {

private static final String TAG = MultKeyTrigger.class.getSimpleName();

private Context mContext;

/**
* 自定义组合键值
*/
private static final int KEY_CTRL_SHIFT_O =401;
private static final int KEY_CTRL_SHIFT_P =402;
private static final int KEY_CTRL_SHIFT_N =403;
private static final int KEY_CTRL_SHIFT_M =404;


/**
* 单独发送按键:
* pageUp:92
* pageDown:93
* F5:135
* ESC:4
*/
private int pageUp = 92;
private int pageDown = 93;
private int F5 = 135;
private int ESC = 4;

/**
* 组合按键:
* ctrl:113
* shift:59
* +
* o:43
* p:44
* n:42
* m:41
* <p>
* 模拟home键:
* win:117
* d:32
*/
private ArrayList<Integer> winD = new ArrayList<>(2);
private ArrayList<Integer> ctrlShiftO = new ArrayList<>(3);
private ArrayList<Integer> ctrlShiftP = new ArrayList<>(3);
private ArrayList<Integer> ctrlShiftN = new ArrayList<>(3);
private ArrayList<Integer> ctrlShiftM = new ArrayList<>(3);

/**
* 存放用于判断的键值
*/
private ArrayList<Key> mKeyEvents = new ArrayList<>();

public MultKeyTrigger(Context context) {
this.mContext = context;
initKeyCode();
}

/**
* 键值手动去获取吧,万一系统层给改了呢?
*/
private void initKeyCode() {
winD.clear();
//WIN+D
winD.add(32);
winD.add(117);
//ctrl+Shift+O
ctrlShiftO.clear();
ctrlShiftO.add(113);
ctrlShiftO.add(59);
ctrlShiftO.add(43);
//ctrl+Shift+P
ctrlShiftP.clear();
ctrlShiftP.add(113);
ctrlShiftP.add(59);
ctrlShiftP.add(44);
//ctrl+Shift+N
ctrlShiftN.clear();
ctrlShiftN.add(113);
ctrlShiftN.add(59);
ctrlShiftN.add(42);
//ctrl+Shift+M
ctrlShiftM.clear();
ctrlShiftM.add(113);
ctrlShiftM.add(59);
ctrlShiftM.add(41);
}

@Override
public void checkKey(int keycode, long eventTime) {
//这里可以拿键值
Log.i(TAG, "startTrigger: extra [input] = " + keycode);
if (checkSingleKey(keycode)) {
//如果匹配单个按键 则直接返回
return;
}
//组合键
Key key = new Key(keycode, eventTime);
if (mKeyEvents.isEmpty()) {
//为空 没有装过按键
mKeyEvents.add(key);
} else {
Key lastKey = mKeyEvents.get(mKeyEvents.size() - 1);
//一般按键事件抬起时间相差为200毫秒
if (key.eventTime - lastKey.eventTime > 200) {
//大于200毫秒 则不是组合键
mKeyEvents.clear();
}
//可能为组合键
mKeyEvents.add(key);
//检测事件
switch (mKeyEvents.size()) {
case 2:
checkDoubleKey(mKeyEvents.get(0).keyCode, mKeyEvents.get(1).keyCode);
break;
case 3:
checkThreeKey(mKeyEvents.get(0).keyCode, mKeyEvents.get(1).keyCode, mKeyEvents.get(2).keyCode);
break;
default:
break;

}
}
}

private boolean checkSingleKey(int keycode) {
if (keycode == pageUp || keycode == pageDown || keycode == ESC || keycode == F5) {
sendMutlKey(keycode);
return true;
} else {
return false;
}
}

private void checkDoubleKey(int key1, int key2) {
if (winD.contains(key1) && winD.contains(key2)) {
//TO HOME
Log.d(TAG, "checkDoubleKey: home");
}
}

private void checkThreeKey(int key1, int key2, int key3) {
if (ctrlShiftO.contains(key1) && ctrlShiftO.contains(key2) && ctrlShiftO.contains(key3)) {
//ctrlShiftO TODO
Log.d(TAG, "checkThreeKey:ctrlShiftO ");
return;
}
if (ctrlShiftM.contains(key1) && ctrlShiftM.contains(key2) && ctrlShiftM.contains(key3)) {
//ctrlShiftM TODO
Log.d(TAG, "checkThreeKey: ctrlShiftM");
return;
}
if (ctrlShiftN.contains(key1) && ctrlShiftN.contains(key2) && ctrlShiftN.contains(key3)) {
//ctrlShiftN TODO
Log.d(TAG, "checkThreeKey: ctrlShiftN");
return;
}
if (ctrlShiftP.contains(key1) && ctrlShiftP.contains(key2) && ctrlShiftP.contains(key3)) {
//ctrlShiftP TODO
Log.d(TAG, "checkThreeKey: ctrlShiftP");
return;
}
}

@Override
public void clearKeys() {
mKeyEvents.clear();
}

private class Key {
int keyCode;
long eventTime;

Key(int keyCode, long eventTime) {
this.keyCode = keyCode;
this.eventTime = eventTime;
}
}

}

那么主要的代码就写完了,上面的200ms是找了几个人试了下他们按组合键的时间,这个键值是在抬起按键时才从底层抛上来的,所以用抛上来的时间差去判断是否是组合键。

用法就很简单了, 在PhoneWindowManager的构造方法里去初始化这个类, 在 interceptKeyBeforeQueueing 里找个坑位,分发下事件:

if (multKeyTrigger != null) {
Log.d(TAG, "hadleMultKey: keyCode = " + keyCode);
multKeyTrigger.checkKey(keyCode, event.getEventTime());
}

So~ 其实还是挺简单的,只是代码比较粗糙,但是貌似也没啥其他办法了,给我一种土土的感觉

声明:学习路上的小脚印|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA[ZH]协议进行授权

转载:转载请注明原文链接 - 【Framworks】增加对USB键盘组合键的判断


Life is very interesting. In the end, some of your greatest pains become your greatest strengths.