Mike Mike - 24 days ago 12
iOS Question

Bluetooth LE HID Eject Key Code?

I am implementing a dongle based on the TI Bluetooth LE HID sample that needs to restore or disable keyboard functionality. When using an Apple keyboard with an iOS device, pressing the eject button will enable/disable the device, hiding/showing the keyboard.

Most references say there is no key code for the eject button, although one lists it as 161; this does not work when used from a Bluetooth LE device. What are the key codes sent to the device from the keyboard to accomplish this?

I am assuming, of course, that a Bluetooth LE device will send the same key codes as a Bluetooth device, and that Apple's implementation of the Bluetooth LE HID includes the functionality for hiding and restoring the keyboard. If one of these assumptions is incorrect, that would help, too.

Answer

I've successfully gotten this working with an Nordic Semiconductor's nRF51822 and S110, using the following report map:

static uint8_t report_map_data[] =
{
    0x05, 0x01,                 // Usage Page (Generic Desktop)
    0x09, 0x06,                 // Usage (Keyboard)
    0xA1, 0x01,                 // Collection (Application)
    0x85, 0x01,                 //     Report Id (1)
    0x05, 0x07,                 //     Usage Page (Key Codes)
    0x19, 0xe0,                 //     Usage Minimum (224)
    0x29, 0xe7,                 //     Usage Maximum (231)
    0x15, 0x00,                 //     Logical Minimum (0)
    0x25, 0x01,                 //     Logical Maximum (1)
    0x75, 0x01,                 //     Report Size (1)
    0x95, 0x08,                 //     Report Count (8)
    0x81, 0x02,                 //     Input (Data, Variable, Absolute)

    0x95, 0x01,                 //     Report Count (1)
    0x75, 0x08,                 //     Report Size (8)
    0x81, 0x01,                 //     Input (Constant) reserved byte(1)

    0x95, 0x05,                 //     Report Count (5)
    0x75, 0x01,                 //     Report Size (1)
    0x05, 0x08,                 //     Usage Page (Page# for LEDs)
    0x19, 0x01,                 //     Usage Minimum (1)
    0x29, 0x05,                 //     Usage Maximum (5)
    0x91, 0x02,                 //     Output (Data, Variable, Absolute), Led report
    0x95, 0x01,                 //     Report Count (1)
    0x75, 0x03,                 //     Report Size (3)
    0x91, 0x01,                 //     Output (Data, Variable, Absolute), Led report padding

    0x95, 0x06,                 //     Report Count (6)
    0x75, 0x08,                 //     Report Size (8)
    0x15, 0x00,                 //     Logical Minimum (0)
    0x25, 0x65,                 //     Logical Maximum (101)
    0x05, 0x07,                 //     Usage Page (Key codes)
    0x19, 0x00,                 //     Usage Minimum (0)
    0x29, 0x65,                 //     Usage Maximum (101)
    0x81, 0x00,                 //     Input (Data, Array) Key array(6 bytes)

    0x09, 0x05,                 //     Usage (Vendor Defined)
    0x15, 0x00,                 //     Logical Minimum (0)
    0x26, 0xFF, 0x00,           //     Logical Maximum (255)
    0x75, 0x08,                 //     Report Count (2)
    0x95, 0x02,                 //     Report Size (8 bit)
    0xB1, 0x02,                 //     Feature (Data, Variable, Absolute)

    0xC0,                        // End Collection (Application)
    // Report ID 2: Advanced buttons
    0x05, 0x0C,                     // Usage Page (Consumer)
    0x09, 0x01,                     // Usage (Consumer Control)
    0xA1, 0x01,                     // Collection (Application)
    0x85, 0x02,                     //     Report Id (2)
    0x15, 0x00,                     //     Logical minimum (0)
    0x25, 0x01,                     //     Logical maximum (1)
    0x75, 0x01,                     //     Report Size (1)
    0x95, 0x01,                     //     Report Count (1)

    0x0A, 0xAE, 0x01,               //     Usage (AL Keyboard Layout)
    0x81, 0x06,                     //     Input (Data,Value,Relative,Bit Field)
    0xC0                            // End Collection
};

Having this report map enables me to send a toggle with this:

static void toggle_send(void)
{
    uint32_t err_code;

    uint8_t release = 0;
    uint8_t keyboard_toggle = 0x01;

    // 1 designates the report index, not report ID. 
    err_code = ble_hids_inp_rep_send(&m_hids, 1, sizeof(keyboard_toggle), &keyboard_toggle);
    APP_ERROR_CHECK(err_code);

    err_code = ble_hids_inp_rep_send(&m_hids, 1, sizeof(release), release);
    APP_ERROR_CHECK(err_code);
} 

I don't know the TI APIs in detail, but I hope this can be useful to refer to nevertheless. The above modifications should be easy to add to the ble_app_hids_keyboard in the regular nRF51 SDK, if you also have access to that chip.