Hello,
I'm trying to understand how the ble_app_hids_keyboard example works. So far, I have hooked up a few more buttons to the board and can type hello.
Now, I would like to have it function more like a real keyboard - including being able to hold down buttons, multiple buttons, etc. I've been going through the example code, and the keys_send() function seems to send both the press notification as well as the release notification via the send_key_scan_press_release() function, but I'm having a hard time understanding how the release notifications are generated and sent.
Thanks! Have pasted the functions in question below. They are unmodified from the original SDK download.
/**@brief Function for sending sample key presses to the peer.
*
* @param[in] key_pattern_len Pattern length.
* @param[in] p_key_pattern Pattern to be sent.
*/
static void keys_send(uint8_t key_pattern_len, uint8_t * p_key_pattern)
{
uint32_t err_code;
uint16_t actual_len;
err_code = send_key_scan_press_release(&m_hids,
p_key_pattern,
key_pattern_len,
0,
&actual_len);
// An additional notification is needed for release of all keys, therefore check
// is for actual_len <= key_pattern_len and not actual_len < key_pattern_len.
if ((err_code == BLE_ERROR_NO_TX_BUFFERS) && (actual_len <= key_pattern_len))
{
// Buffer enqueue routine return value is not intentionally checked.
// Rationale: Its better to have a a few keys missing than have a system
// reset. Recommendation is to work out most optimal value for
// MAX_BUFFER_ENTRIES to minimize chances of buffer queue full condition
(void) buffer_enqueue(&m_hids, p_key_pattern, key_pattern_len, actual_len);
}
if ((err_code != NRF_SUCCESS) &&
(err_code != NRF_ERROR_INVALID_STATE) &&
(err_code != BLE_ERROR_NO_TX_BUFFERS) &&
(err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING)
)
{
APP_ERROR_HANDLER(err_code);
}
}
/**@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, BLE_ERROR_NO_TX_BUFFERS 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 BLE_ERROR_NO_TX_BUFFERS, 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)
{
uint32_t err_code;
uint16_t offset;
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));
offset = pattern_offset;
data_len = pattern_len;
do
{
// Reset the data buffer.
memset(data, 0, sizeof(data));
// Copy the scan code.
memcpy(data + SCAN_CODE_POS + offset, p_key_pattern + offset, data_len - offset);
if (is_shift_key_pressed())
{
data[MODIFIER_KEY_POS] |= SHIFT_KEY_CODE;
}
if (!m_in_boot_mode)
{
err_code = ble_hids_inp_rep_send(p_hids,
INPUT_REPORT_KEYS_INDEX,
INPUT_REPORT_KEYS_MAX_LEN,
data);
}
else
{
err_code = ble_hids_boot_kb_inp_rep_send(p_hids,
INPUT_REPORT_KEYS_MAX_LEN,
data);
}
if (err_code != NRF_SUCCESS)
{
break;
}
offset++;
} while (offset <= data_len);
*p_actual_len = offset;
return err_code;
}
Thanks!