Android 4.4 获取硬件密钥ID(在设备上实际可用)

Android 4.4 get hardware key ids (which are actually available on the device)

我正在开发一个 Xposed 模块,它使用硬件按钮(如电源、提高音量等)来启动一些操作。我想添加一个 "Settings" UI 以便用户可以选择他想要使用的按钮。

到目前为止,我找到了几种可能的解决方案,但其中 none 符合我的要求。例如,以下所有 return 为真:

boolean hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey();
boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
boolean hasVolumeUpKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_VOLUME_UP);

然而,该设备实际上根本没有任何音量键。通过记录硬件密钥,我发现 "volume" 密钥实际上是 KEYCODE_F1。所以检查 deviceHasKey() 是不可靠的,我不能指望它。

是否有另一种解决方案可用于检查哪些硬件密钥可用且实际工作方式与您预期的一样?或者更好的是,有没有办法获得所有可用按钮的完整列表?

也有人可以解释为什么 deviceHasKey() return 对于音量键(_UP、_DOWN、_MUTE)是正确的,而根本没有一个音量按钮?我认为这一定与设备的KeyCharacterMap有关,由于该设备是廉价的中国设备,因此可能实现不佳。

我的第三个问题是:有没有办法区分设备休眠时有效的按钮(电源、音量、F1 在我的例子中)和无效的按钮(如菜单、返回、主页,哪个所有触摸按钮都在显示屏下方(不是显示屏中的软件按钮)而不是可按下的按钮)?

非常感谢任何提示:)

提前致谢

-----更新------

根据 Burak Day 的建议,这是 adb shell getevent -lp 的结果:

add device 1: /dev/input/event0
  name:     "mtk-kpd"
  events:
    KEY (0001): KEY_HOME              KEY_END               KEY_VOLUMEDOWN        KEY_VOLUMEUP         
                KEY_POWER             KEY_MENU              KEY_BACK              KEY_HP               
                KEY_CAMERA            KEY_SEND             
  input props:
    <none>
add device 2: /dev/input/event4
  name:     "mtk-tpd-kpd"
  events:
    KEY (0001): KEY_MENU              KEY_BACK              KEY_HOMEPAGE         
  input props:
    <none>
could not get driver version for /dev/input/mouse0, Not a typewriter
add device 3: /dev/input/event3
  name:     "mtk-tpd"
  events:
    KEY (0001): KEY_MENU              KEY_BACK              KEY_HOMEPAGE          BTN_TOUCH            
    ABS (0003): ABS_X                 : value 0, min 0, max 240, fuzz 0, flat 0, resolution 240
                ABS_Y                 : value 0, min 0, max 240, fuzz 0, flat 0, resolution 240
                ABS_PRESSURE          : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                ABS_MT_TOUCH_MAJOR    : value 0, min 0, max 100, fuzz 0, flat 0, resolution 0
                ABS_MT_TOUCH_MINOR    : value 0, min 0, max 100, fuzz 0, flat 0, resolution 0
                ABS_MT_POSITION_X     : value 0, min 0, max 240, fuzz 0, flat 0, resolution 0
                ABS_MT_POSITION_Y     : value 0, min 0, max 240, fuzz 0, flat 0, resolution 0
                ABS_MT_TRACKING_ID    : value 0, min 0, max 0, fuzz 0, flat 0, resolution 0
  input props:
    INPUT_PROP_DIRECT
add device 4: /dev/input/event2
  name:     "hwmdata"
  events:
    REL (0002): REL_Y                
  input props:
    <none>
add device 5: /dev/input/event1
  name:     "ACCDET"
  events:
    KEY (0001): KEY_VOLUMEDOWN        KEY_VOLUMEUP          KEY_HANGEUL           KEY_NEXTSONG         
                KEY_PLAYPAUSE         KEY_PREVIOUSSONG      KEY_STOPCD            KEY_SEND             
  input props:
    <none>
could not get driver version for /dev/input/mice, Not a typewriter

如您所见,设备认为有按钮可用,在与制造商交谈后,我们发现它们可以 向设备添加更多按钮(如果我们订购一定数量并额外支付几千美元)。但是,在当前版本中,按钮仍然不存在。

我的猜测是,该设备使用模块化 board/processor/driver,您可以在其中焊接按钮或将它们留空,但软件不知道按钮是否焊接在电路板上。

我怎么知道按钮是否可用?我想让我的模块尽可能通用,以便将来它可以 运行 在其他设备上使用而无需显式更改代码。另外我不想向用户显示可能的按钮,如果它们实际上不存在的话。

另一件事是我仍然需要一种方法来区分设备处于睡眠状态时可用的按钮(电源、音量)和不可用的按钮(菜单、主页、返回,它们都是触摸按钮如果显示器关闭,它们也会关闭)。

----更新 2----

我检查了 event0 设备键的原始十六进制值。然后我使用 "mtk-kpd.kl" 字符映射来翻译它们。然后我使用各自的 KeyEvent id 来检查设备 return 是否对所有这些都为真:

Log.d(Constants.LOG_TAG, "Home:" + KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_HOME));
Log.d(Constants.LOG_TAG, "END:" + KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_ENDCALL));
Log.d(Constants.LOG_TAG, "Volume Up:" + KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_VOLUME_UP));
Log.d(Constants.LOG_TAG, "Volume Down:" + KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_VOLUME_DOWN));

Log.d(Constants.LOG_TAG, "POWER:" + KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER));
Log.d(Constants.LOG_TAG, "Menu:" + KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_MENU));
Log.d(Constants.LOG_TAG, "Back:" + KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK));
Log.d(Constants.LOG_TAG, "HP:" + KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_FOCUS));

Log.d(Constants.LOG_TAG, "CAMERA:" + KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_CAMERA));
Log.d(Constants.LOG_TAG, "Send:" + KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_CALL));

是的,他们都是 return 正确的...

您可以使用 adb shell getevent -lp 检查设备上的硬件密钥。

它会 return 为您提供 /dev/input/ 文件夹中 linux 级别的可能事件的实际设备。

您可以通过查找KEY_POWERKEY_VOLUMEUPKEY_VOLUMEDOWN事件来选择其中的按键输入设备,并查看哪个被接受为硬键。

设备休眠时只能使用硬键。

或者,如果您需要在设备休眠时保持处理器处于唤醒状态,您可以使用 PowerManager PARTIAL_WAKE_LOCK

抱歉,我知道这不是最佳答案,但为了清楚说明,我可以更新我的答案。由于信誉不佳,无法对您的问题发表评论。

我得出的结论是,如果设备制造商做得不好,则没有可靠的方法可以找出哪些硬件按钮可用。

在我的例子中,hardware/software 可以有多个按钮。然而,该设备实际上只有几个按钮焊接在逻辑板上。

无法确定按钮是否实际焊接到应用程序级别的电路板上。