目录
一,背景介绍
二,技术方案
2.1 获取BluetoothHidDevice实例
2.2 注册/解除注册HID实例
2.3 Hid report description描述符生成工具
2.4 键盘映射表
2.5 通过HID发送键盘事件
三,实例
日常生活中,各种物理遥控器和鼠标等设备,需要摆放和携带,便捷性有待考验。根据蓝牙HID特性,可以用蓝牙协议模仿键盘,来实现空中键盘等功能。
自Android 9开放BluetoothHidDevice功能后,Android平台可以很简单的通过BluetoothHidDevice模拟键盘鼠标等蓝牙hid device角色。
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
bluetoothAdapter.setName("KEYBOARD BT");
bluetoothAdapter.getProfileProxy(context,mProfileServiceListener,BluetoothProfile.HID_DEVICE);
public static BluetoothProfile.ServiceListener mProfileServiceListener = new BluetoothProfile.ServiceListener() {
@Override
public void onServiceDisconnected(int profile) {
Log.e(TAG, "hid onServiceDisconnected");
if (profile == BluetoothProfile.HID_DEVICE) {
mHidDevice.unregisterApp();
}
}
@SuppressLint("NewApi")
@Override
public void onServiceConnected(int profile, BluetoothProfile proxy) {
Log.e(TAG, "hid onServiceConnected");
bluetoothProfile = proxy;
if (profile == BluetoothProfile.HID_DEVICE) {
mHidDevice = (BluetoothHidDevice) proxy;
HidConsts.HidDevice = mHidDevice;
BluetoothHidDeviceAppSdpSettings sdp = new BluetoothHidDeviceAppSdpSettings(HidConsts.NAME, HidConsts.DESCRIPTION, HidConsts.PROVIDER, BluetoothHidDevice.SUBCLASS1_COMBO, HidConsts.Descriptor);
mHidDevice.registerApp(sdp, null, null, Executors.newCachedThreadPool(), mCallback);
}
}
};
在获取到BluetoothHidDevice实例后通过registerApp注册hid device,此时hid host角色会被禁用,因此在不需要hid device功能时要及时解除hid device的注册。
registerApp函数中最重要的一个参数BluetoothHidDeviceAppSdpSettings,主要是给对端host提供hid device角色的名称,描述信息,供应商信息,以及Hid device的Reports Descriptor。
参考文章《官网HID描述符工具》
val Descriptor = byteArrayOf(
0x05.toByte(),
0x01.toByte(),
0x09.toByte(),
0x02.toByte(),
0xa1.toByte(),
0x01.toByte(),
0x09.toByte(),
0x01.toByte(),
0xa1.toByte(),
0x00.toByte(),
0x85.toByte(),
0x01.toByte(),
0x05.toByte(),
0x09.toByte(),
0x19.toByte(),
0x01.toByte(),
0x29.toByte(),
0x03.toByte(),
0x15.toByte(),
0x00.toByte(),
0x25.toByte(),
0x01.toByte(),
0x95.toByte(),
0x03.toByte(),
0x75.toByte(),
0x01.toByte(),
0x81.toByte(),
0x02.toByte(),
0x95.toByte(),
0x01.toByte(),
0x75.toByte(),
0x05.toByte(),
0x81.toByte(),
0x03.toByte(),
0x05.toByte(),
0x01.toByte(),
0x09.toByte(),
0x30.toByte(),
0x09.toByte(),
0x31.toByte(),
0x09.toByte(),
0x38.toByte(),
0x15.toByte(),
0x81.toByte(),
0x25.toByte(),
0x7f.toByte(),
0x75.toByte(),
0x08.toByte(),
0x95.toByte(),
0x03.toByte(),
0x81.toByte(),
0x06.toByte(),
0xc0.toByte(),
0xc0.toByte(),
0x05.toByte(),
0x01.toByte(),
0x09.toByte(),
0x06.toByte(),
0xa1.toByte(),
0x01.toByte(),
0x85.toByte(),
0x02.toByte(),
0x05.toByte(),
0x07.toByte(),
0x19.toByte(),
0xE0.toByte(),
0x29.toByte(),
0xE7.toByte(),
0x15.toByte(),
0x00.toByte(),
0x25.toByte(),
0x01.toByte(),
0x75.toByte(),
0x01.toByte(),
0x95.toByte(),
0x08.toByte(),
0x81.toByte(),
0x02.toByte(),
0x95.toByte(),
0x01.toByte(),
0x75.toByte(),
0x08.toByte(),
0x15.toByte(),
0x00.toByte(),
0x25.toByte(),
0x65.toByte(),
0x19.toByte(),
0x00.toByte(),
0x29.toByte(),
0x65.toByte(),
0x81.toByte(),
0x00.toByte(),
0x05.toByte(),
0x08.toByte(),
0x95.toByte(),
0x05.toByte(),
0x75.toByte(),
0x01.toByte(),
0x19.toByte(),
0x01.toByte(),
0x29.toByte(),
0x05.toByte(),
0x91.toByte(),
0x02.toByte(),
0x95.toByte(),
0x01.toByte(),
0x75.toByte(),
0x03.toByte(),
0x91.toByte(),
0x03.toByte(),
0xc0.toByte()
)
Esc
29
F1
3a
F2
3b
F3
3c
F4
3d
F5
3e
F6
3f
F7
40
F8
41
F9
42
F10
43
F11
44
F12
45
` ~
35
1 !
1e
2 @
1f
3 #
20
4 $
21
5 %
22
6 ^
23
7 &
24
8 *
25
9 (
26
0 )
27
- _
2d
= +
2e
Backspace
2a
Tab
2b
Q
14
W
1a
E
08
R
15
T
17
Y
1c
U
18
I
0c
O
12
P
13
[ {
2f
] }
30
\\ |
31
CapsLock
39
A
04
S
16
D
07
F
09
G
0a
H
0b
J
0d
K
0e
L
0f
; :
33
\' \"
34
Enter
28
Shift
02
Z
1d
X
1b
C
06
V
19
B
05
N
11
M
10
, <
36
. >
37
/ ?
38
Shift
20
Ctrl
01
⊞
08
Alt
04
SPACE
2c
Alt
40
Win
80
☰
65
Ctrl
10
Print Screen
46
Scroll Lock
47
PAUSE
48
Insert
49
Home
4a
PgUp
4b
Delete
4c
End
4d
PgDn
4e
▲
52
◀
50
▼
51
▶
4f
通过HID设备,发送report,
HidDevice!!.sendReport(HidUtils.mDevice, report.ReportId.toInt(), report.ReportData)
需要源码,请私信