This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

BLE hid Keyboard key press/release [Clarifications needed]

Hi,

We're working on a ble hid keyboard project, and we need some clarifications on how the keyboard keys press/release is done !

We've started with the example in the sdk v16.0.0, the example uses the keys_send() function to send a press followed by a release of that key. 

In this function there is  send_key_scan_press_release() , and i think this is the responsible for sending a press followed by a release of the key.

In our use case, we need to send just a press when the button is pushed, and a release when the button is released. in this case a hold on the button will output a successive key presses , and when released it will output just one release . this is achieved with the USB keyboard version using the app_usbd_hid_kbd_key_control() function.

 static void button_event_handler(uint8_t pin_no, uint8_t button_action)
    {
      ret_code_t err_code;
      switch(pin_no)
      {
       case BUTTON_1:
         if(button_action == APP_BUTTON_PUSH) {
            UNUSED_RETURN_VALUE(app_usbd_hid_kbd_key_control(&m_app_hid_kbd, CONFIG_KBD_KEY[0] , true));
            //NRF_LOG_INFO("button1 pressed");
         }
         else if(button_action == APP_BUTTON_RELEASE) {
            UNUSED_RETURN_VALUE(app_usbd_hid_kbd_key_control(&m_app_hid_kbd, CONFIG_KBD_KEY[0] , false));
            //NRF_LOG_INFO("button1 release");
         }
         break;
         
         }
    }     

the BLE  hid keyboard output on the host, should be as in the picture bellow (same as with the USB version) : 

USB hid keyboard log

Any help, clarifications, recommendations on how to achieve that is highly appreciated !

Best Regards,

Abdelali

  • Feel free to modify this as you see fit, also check out the api description:

    /**@brief   Function for transmitting a key scan Press & Release Notification.
     *
     * @warning This handler is an example only. You need to analyze how you wish to send the key
     *          release.
     *
     * @param[in]  p_instance     Identifies the service for which Key Notifications are requested.
     * @param[in]  p_key_pattern  Pointer to key pattern.
     * @param[in]  pattern_len    Length of key pattern. 0 < pattern_len < 7.
     * @param[in]  pattern_offset Offset applied to Key Pattern for transmission.
     * @param[out] actual_len     Provides actual length of Key Pattern transmitted, making buffering of
     *                            rest possible if needed.
     * @return     NRF_SUCCESS on success, NRF_ERROR_RESOURCES in case transmission could not be
     *             completed due to lack of transmission buffer or other error codes indicating reason
     *             for failure.
     *
     * @note       In case of NRF_ERROR_RESOURCES, remaining pattern that could not be transmitted
     *             can be enqueued \ref buffer_enqueue function.
     *             In case a pattern of 'cofFEe' is the p_key_pattern, with pattern_len as 6 and
     *             pattern_offset as 0, the notifications as observed on the peer side would be
     *             1>    'c', 'o', 'f', 'F', 'E', 'e'
     *             2>    -  , 'o', 'f', 'F', 'E', 'e'
     *             3>    -  ,   -, 'f', 'F', 'E', 'e'
     *             4>    -  ,   -,   -, 'F', 'E', 'e'
     *             5>    -  ,   -,   -,   -, 'E', 'e'
     *             6>    -  ,   -,   -,   -,   -, 'e'
     *             7>    -  ,   -,   -,   -,   -,  -
     *             Here, '-' refers to release, 'c' refers to the key character being transmitted.
     *             Therefore 7 notifications will be sent.
     *             In case an offset of 4 was provided, the pattern notifications sent will be from 5-7
     *             will be transmitted.
     */
    static uint32_t send_key_scan_press_release(ble_hids_t * p_hids,
                                                uint8_t    * p_key_pattern,
                                                uint16_t     pattern_len,
                                                uint16_t     pattern_offset,
                                                uint16_t   * p_actual_len)

    If you wait more than 500ms between key press and release, then at least for Windows it will treat this as a key repeat automatically until release it received.

  • Hi,

    Ok, but i see the code snippet in your response looks like corrupted, i see just the function declaration ?! is it the same one in the ble hid keyboard example in the sdk ?

    Best regards,

  • It's the same as the HID keyboard example yes, I only shared the description here.

  • Hi,

    I have experimented with the send_key_scan_press_release() function, just sending a one key, and not even using the buffering feature.  

    For the press i just fill the data array with the scan code (1 key_pattern). and for the release i clear the data array.

    The BLE HID output seems to output a KEY PRESS followed by KEY RELEASE, a hold on the button will keep outputting a PRESS followed with a RELEASE.

    I even tried to only send a PRESS (by not clearing the data array); but that also sends a RELEASE after.

    I'm not quite sure how the RELEASE event is sent right after the PRESS, even without clearing the data[] variable!

    I Really appreciate any hints/guidance/documentation on how to implement it. 

    Best Regards,

    Abdelali

    static uint32_t send_key_scan_press_release(ble_hids_t * p_hids,
                                                uint8_t    * p_key_pattern,
                                                uint16_t     pattern_len,
                                                uint8_t      action )
    {
        ret_code_t err_code;
        uint16_t data_len;
        uint8_t  data[INPUT_REPORT_KEYS_MAX_LEN];
    
        // HID Report Descriptor enumerates an array of size 6, the pattern hence shall not be any
        // longer than this.
        STATIC_ASSERT((INPUT_REPORT_KEYS_MAX_LEN - 2) == 6);
    
        ASSERT(pattern_len <= (INPUT_REPORT_KEYS_MAX_LEN - 2));
    
        data_len = pattern_len;   // 1
    
      if(action == 1){ // press
    
            // Reset the data buffer.
            memset(data, 0, sizeof(data));
            // Copy the scan code.
            memcpy(data + SCAN_CODE_POS , p_key_pattern , data_len );
    
            if (modifier_status)
            {
               data[MODIFIER_KEY_POS] |= ble_hid_config[11];//
            }
    
        }
    
      else { // release 
      
              // Reset the data buffer.
              memset(data, 0, sizeof(data));
        }
    
            if (!m_in_boot_mode)
            {
                err_code = ble_hids_inp_rep_send(p_hids,
                                                 INPUT_REPORT_KEYS_INDEX,
                                                 INPUT_REPORT_KEYS_MAX_LEN,
                                                 data,
                                                 m_conn_handle);
            }
            else
            {
                err_code = ble_hids_boot_kb_inp_rep_send(p_hids,
                                                         INPUT_REPORT_KEYS_MAX_LEN,
                                                         data,
                                                         m_conn_handle);
            }
    
            if (err_code != NRF_SUCCESS)
            {
    
             APP_ERROR_CHECK(err_code);
    
             }
    
        return err_code;
    }
    

  • Have you tried to call ble_hids_inp_rep_send() when pressing, and then ble_hids_inp_rep_send() when releasing directly?

    Just make sure that the data buffer is 8 bytes, where the first 2 bytes (data[0] and data[1]) are key modifier (e.g. shift, num lock etc), so the actual key that is pressed is 3rd byte (data[2]) in the array. The remaining data bytes (data[3]-data[7]) can be 0.

    Kenneth

Related