Android Bluetooth HID Device模拟蓝牙键盘鼠标

自Android 9开放BluetoothHidDevice功能后,Android平台可以很简单的通过BluetoothHidDevice模拟键盘鼠标等蓝牙hid device角色。

Step 1:获取BluetoothHidDevice实例

mBluetoothAdapter.getProfileProxy(ctx, mProfileServiceListener, BluetoothProfile.HID_DEVICE); 

Step 2:注册/解除注册HID实例

    public BluetoothProfile.ServiceListener mProfileServiceListener = new BluetoothProfile.ServiceListener() {
        @Override
        public void onServiceDisconnected(int profile) {
            if (profile == BluetoothProfile.HID_DEVICE) {
                //解除hid device注册
                mHidDevice.unregisterApp();
            }
        }

        @Override
        public void onServiceConnected(int profile, BluetoothProfile proxy) {
            if (profile == BluetoothProfile.HID_DEVICE) {
                mHidDevice = (BluetoothHidDevice) proxy;
                //注册hid device
                BluetoothHidDeviceAppSdpSettings sdp = new BluetoothHidDeviceAppSdpSettings(HidConfig.NAME, HidConfig.DESCRIPTION, HidConfig.PROVIDER, BluetoothHidDevice.SUBCLASS1_COMBO, HidConfig.KEYBOARD_DESCRIPTOR);
                mHidDevice.registerApp(sdp, null, null, Executors.newCachedThreadPool(), mCallback);
            }
        }
    };



    public final BluetoothHidDevice.Callback mCallback = new BluetoothHidDevice.Callback() {
        @Override
        public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) {
            IsRegisted = registered;
        }

        @Override
        public void onConnectionStateChanged(BluetoothDevice device, int state) {
            if (state == BluetoothProfile.STATE_DISCONNECTED) {
                connected = false;
                Log.d(TAG, "hid state is disconnected");
            } else if (state == BluetoothProfile.STATE_CONNECTED) {
                connected = true;
                Log.d(TAG, "hid state is connected");
            } else if (state == BluetoothProfile.STATE_CONNECTING) {
                Log.d(TAG, "hid state is connecting");
            }
        }
    };

在获取到BluetoothHidDevice实例后通过registerApp注册hid device,此时hid host角色会被禁用,因此在不需要hid device功能时要及时解除hid device的注册。

registerApp函数中最重要的一个参数BluetoothHidDeviceAppSdpSettings,主要是给对端host提供hid device角色的名称,描述信息,供应商信息,以及Hid device的Reports Descriptor

Hid report description描述符生成工具:USB官网HID报告描述符生成工具 - USB中文网

public class HidConfig {
    
    public final static String NAME = "My Keyboard";
 
    public final static String DESCRIPTION = "Lgd's Keyboard";
 
    public final static String PROVIDER = "Lgd";

    public static final byte[] KEYBOARD_DESCRIPTOR =
            {
                    (byte) 0x05, (byte) 0x01,                    // USAGE_PAGE (Generic Desktop)
                    (byte) 0x09, (byte) 0x06,                    // USAGE (Keyboard)
                    (byte) 0xa1, (byte) 0x01,                    // COLLECTION (Application)
                    (byte) 0x85, (byte) 0x02,                    //REPORT_ID (2)
                    (byte) 0x05, (byte) 0x07,                    //   USAGE_PAGE (Keyboard)
                    (byte) 0x19, (byte) 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)
                    (byte) 0x29, (byte) 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
                    (byte) 0x15, (byte) 0x00,                    //   LOGICAL_MINIMUM (0)
                    (byte) 0x25, (byte) 0x01,                    //   LOGICAL_MAXIMUM (1)
                    (byte) 0x75, (byte) 0x01,                    //   REPORT_SIZE (1)
                    (byte) 0x95, (byte) 0x08,                    //   REPORT_COUNT (8)
                    (byte) 0x81, (byte) 0x02,                    //   INPUT (Data,Var,Abs)
                    (byte) 0x95, (byte) 0x01,                    //   REPORT_COUNT (1)
                    (byte) 0x75, (byte) 0x08,                    //   REPORT_SIZE (8)
                    (byte) 0x81, (byte) 0x03,                    //   INPUT (Cnst,Var,Abs)
                    (byte) 0x95, (byte) 0x05,                    //   REPORT_COUNT (5)
                    (byte) 0x75, (byte) 0x01,                    //   REPORT_SIZE (1)
                    (byte) 0x05, (byte) 0x08,                    //   USAGE_PAGE (LEDs)
                    (byte) 0x19, (byte) 0x01,                    //   USAGE_MINIMUM (Num Lock)
                    (byte) 0x29, (byte) 0x05,                    //   USAGE_MAXIMUM (Kana)
                    (byte) 0x91, (byte) 0x02,                    //   OUTPUT (Data,Var,Abs)
                    (byte) 0x95, (byte) 0x01,                    //   REPORT_COUNT (1)
                    (byte) 0x75, (byte) 0x03,                    //   REPORT_SIZE (3)
                    (byte) 0x91, (byte) 0x03,                    //   OUTPUT (Cnst,Var,Abs)
                    (byte) 0x95, (byte) 0x06,                    //   REPORT_COUNT (6)
                    (byte) 0x75, (byte) 0x08,                    //   REPORT_SIZE (8)
                    (byte) 0x15, (byte) 0x00,                    //   LOGICAL_MINIMUM (0)
                    (byte) 0x25, (byte) 0x65,                    //   LOGICAL_MAXIMUM (101)
                    (byte) 0x05, (byte) 0x07,                    //   USAGE_PAGE (Keyboard)
                    (byte) 0x19, (byte) 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))
                    (byte) 0x29, (byte) 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)
                    (byte) 0x81, (byte) 0x00,                    //   INPUT (Data,Ary,Abs)
                    (byte) 0xc0                           // END_COLLECTION
            };
 }

上面的描述符只是适配键盘,可以不定义report id,如果是多个hid功能复合的设备,例如复合键盘鼠标,就需要再添加鼠标的报告描述符,同时每个功能都需要有对应的report id。

  1. 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
  2. 0x09, 0x02, // USAGE (Mouse)
  3. 0xa1, 0x01, // COLLECTION (Application)
  4. 0x85, 0x01, // REPORT_ID (1)
  5. 0x75, 0x10, // REPORT_SIZE (16)
  6. 0x95, 0x01, // REPORT_COUNT (1)
  7. 0x15, 0x0b, // LOGICAL_MINIMUM (11)
  8. 0x25, 0x1c, // LOGICAL_MAXIMUM (28)
  9. 0x09, 0x30, // USAGE (X)
  10. 0x81, 0x22, // INPUT (Data,Var,Abs,NPrf)
  11. 0xc0, // END_COLLECTION
  12. 0x09, 0x06, // USAGE (Keyboard)
  13. 0xa1, 0x01, // COLLECTION (Application)
  14. 0x85, 0x02, // REPORT_ID (2)
  15. 0x75, 0x08, // REPORT_SIZE (8)
  16. 0x95, 0x01, // REPORT_COUNT (1)
  17. 0x15, 0x00, // LOGICAL_MINIMUM (0)
  18. 0x25, 0x40, // LOGICAL_MAXIMUM (64)
  19. 0x09, 0x31, // USAGE (Y)
  20. 0x81, 0x02, // INPUT (Data,Var,Abs)
  21. 0xc0

Setp 4:通过sendReport想host发送按键信息

第二个参数是report description中定义的report id,如果没有定义传入0。

第三个参数是按键数据,根据report description,总共有8字节,前2字节是功能键,后6字节是对应的键值信息

        mHidDevice.sendReport(device, 2, new byte[]{0, 0, (byte) code, 0, 0, 0, 0, 0});

Hid相关资料请参考:HID 简介 - USB中文网

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值