mirror of
https://github.com/espruino/Espruino.git
synced 2025-12-08 19:06:15 +00:00
tidying HID, allowing repeated sends easily
This commit is contained in:
parent
99c1ec4900
commit
026ee93402
@ -924,23 +924,66 @@ void jswrap_nrf_nfcURL(JsVar *url) {
|
||||
/*JSON{
|
||||
"type" : "staticmethod",
|
||||
"class" : "NRF",
|
||||
"name" : "hid",
|
||||
"generate" : "jswrap_nrf_hid",
|
||||
"name" : "sendHIDReport",
|
||||
"generate" : "jswrap_nrf_sendHIDReport",
|
||||
"params" : [
|
||||
["url","int","The URL string to expose on NFC, or `undefined` to disable NFC"]
|
||||
["data","JsVar","Input report data, see below"],
|
||||
["callback","JsVar","A callback function to be called when the data is sent"]
|
||||
]
|
||||
}
|
||||
Enables NFC and starts advertising the given URL. For example:
|
||||
Send a USB HID report. HID must first be enabled with `NRF.setServices({}, {hid:true})`
|
||||
|
||||
Data must be an array of the form:
|
||||
|
||||
```
|
||||
NRF.nrfURL("http://espruino.com");
|
||||
[modifier, reserved, key1, key2, key3, key4, key5, key6 ]
|
||||
```
|
||||
|
||||
**Note:** This is only available on nRF52-based devices
|
||||
You can easily look up keyboard key codes, but for example
|
||||
to send the 'a' key, send `[0,0,4,0,0,0,0,0]`. To release
|
||||
it, send `[0,0,4,0,0,0,0,0]`
|
||||
|
||||
The modifiers are as follows:
|
||||
|
||||
```
|
||||
1 : left control
|
||||
2 : left shift
|
||||
4 : left alt
|
||||
8 : left GUI
|
||||
16 : right control
|
||||
32 : right shift
|
||||
64 : right alt
|
||||
128 : right GUI
|
||||
```
|
||||
|
||||
So to send capital `A`, send `[2,0,4,0,0,0,0,0]` followed by `[0,0,0,0,0,0,0,0]`.
|
||||
|
||||
```
|
||||
NRF.sendHIDReport([2,0,4], function() {
|
||||
NRF.sendHIDReport([0,0,0])
|
||||
})
|
||||
```
|
||||
|
||||
You can find key codes at http://www.usb.org/developers/hidpage/Hut1_12v2.pdf
|
||||
under 'Keyboard/Keypad page', but for quick
|
||||
reference:
|
||||
|
||||
* `a`...`z` are 4..26
|
||||
* `1`..`9` are 30..38
|
||||
* `0` is 39
|
||||
* Return is 40
|
||||
* Space is 44
|
||||
|
||||
*/
|
||||
void jswrap_nrf_hid(int key) {
|
||||
uint8_t k = key;
|
||||
send_key_scan_press_release(&k, 1);
|
||||
void jswrap_nrf_sendHIDReport(JsVar *data, JsVar *callback) {
|
||||
JSV_GET_AS_CHAR_ARRAY(vPtr, vLen, data)
|
||||
if (vPtr && vLen) {
|
||||
if (jsvIsFunction(callback))
|
||||
jsvObjectSetChild(execInfo.root, BLE_HID_SENT_EVENT, callback);
|
||||
jsble_send_hid_input_report(vPtr, vLen);
|
||||
} else {
|
||||
jsExceptionHere(JSET_ERROR, "Expecting array, got %t", data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@ void jswrap_nrf_bleservice_discoverCharacteristics(JsVar *service);
|
||||
void jswrap_nrf_blecharacteristic_write(JsVar *characteristic, JsVar *data);
|
||||
|
||||
void jswrap_nrf_nfcURL(JsVar *url);
|
||||
void jswrap_nrf_hid(int key);
|
||||
void jswrap_nrf_sendHIDReport(JsVar *data, JsVar *callback);
|
||||
|
||||
bool jswrap_nrf_idle();
|
||||
void jswrap_nrf_kill();
|
||||
|
||||
@ -65,18 +65,13 @@
|
||||
#define NEXT_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(30000, APP_TIMER_PRESCALER) /**< Time between each call to sd_ble_gap_conn_param_update after the first call (30 seconds). */
|
||||
#define MAX_CONN_PARAMS_UPDATE_COUNT 3 /**< Number of attempts before giving up the connection parameter negotiation. */
|
||||
|
||||
#define OUTPUT_REPORT_INDEX 0 /**< Index of Output Report. */
|
||||
#define OUTPUT_REPORT_MAX_LEN 1 /**< Maximum length of Output Report. */
|
||||
#define INPUT_REPORT_KEYS_INDEX 0 /**< Index of Input Report. */
|
||||
#define OUTPUT_REPORT_BIT_MASK_CAPS_LOCK 0x02 /**< CAPS LOCK bit in Output Report (based on 'LED Page (0x08)' of the Universal Serial Bus HID Usage Tables). */
|
||||
#define INPUT_REP_REF_ID 0 /**< Id of reference to Keyboard Input Report. */
|
||||
#define OUTPUT_REP_REF_ID 0 /**< Id of reference to Keyboard Output Report. */
|
||||
#define INPUT_REPORT_KEYS_MAX_LEN 8 /**< Maximum length of the Input Report characteristic. */
|
||||
// BLE HID stuff
|
||||
#define BASE_USB_HID_SPEC_VERSION 0x0101 /**< Version number of base USB HID Specification implemented by this application. */
|
||||
#define MODIFIER_KEY_POS 0 /**< Position of the modifier byte in the Input Report. */
|
||||
#define SCAN_CODE_POS 2 /**< This macro indicates the start position of the key scan code in a HID Report. As per the document titled 'Device Class Definition for Human Interface Devices (HID) V1.11, each report shall have one modifier byte followed by a reserved constant byte and then the key scan code. */
|
||||
#define SHIFT_KEY_CODE 0x02 /**< Key code indicating the press of the Shift Key. */
|
||||
|
||||
#define HID_OUTPUT_REPORT_INDEX 0 /**< Index of Output Report. */
|
||||
#define HID_OUTPUT_REPORT_MAX_LEN 1 /**< Maximum length of Output Report. */
|
||||
#define HID_INPUT_REPORT_KEYS_INDEX 0 /**< Index of Input Report. */
|
||||
#define HID_INPUT_REP_REF_ID 0 /**< Id of reference to Keyboard Input Report. */
|
||||
#define HID_OUTPUT_REP_REF_ID 0 /**< Id of reference to Keyboard Output Report. */
|
||||
|
||||
#define APP_FEATURE_NOT_SUPPORTED BLE_GATT_STATUS_ATTERR_APP_BEGIN + 2 /**< Reply when unsupported features are requested. */
|
||||
|
||||
@ -344,6 +339,12 @@ static void on_ble_evt(ble_evt_t * p_ble_evt)
|
||||
case BLE_EVT_TX_COMPLETE:
|
||||
// UART Transmit finished - we can try and send more data
|
||||
bleStatus &= ~BLE_IS_SENDING;
|
||||
if (bleStatus & BLE_IS_SENDING_HID) {
|
||||
bleStatus &= ~BLE_IS_SENDING_HID;
|
||||
jsiQueueObjectCallbacks(execInfo.root, BLE_HID_SENT_EVENT, 0, 0);
|
||||
jsvObjectSetChild(execInfo.root, BLE_HID_SENT_EVENT, 0); // fire only once
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_ADV_REPORT: {
|
||||
@ -501,27 +502,19 @@ static void on_hid_rep_char_write(ble_hids_evt_t * p_evt) {
|
||||
uint8_t report_val;
|
||||
uint8_t report_index = p_evt->params.char_write.char_id.rep_index;
|
||||
|
||||
if (report_index == OUTPUT_REPORT_INDEX) {
|
||||
if (report_index == HID_OUTPUT_REPORT_INDEX) {
|
||||
// This code assumes that the outptu report is one byte long. Hence the following
|
||||
// static assert is made.
|
||||
STATIC_ASSERT(OUTPUT_REPORT_MAX_LEN == 1);
|
||||
STATIC_ASSERT(HID_OUTPUT_REPORT_MAX_LEN == 1);
|
||||
|
||||
err_code = ble_hids_outp_rep_get(&m_hids,
|
||||
report_index,
|
||||
OUTPUT_REPORT_MAX_LEN,
|
||||
HID_OUTPUT_REPORT_MAX_LEN,
|
||||
0,
|
||||
&report_val);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
if ((report_val & OUTPUT_REPORT_BIT_MASK_CAPS_LOCK) != 0) {
|
||||
// Caps Lock is turned On.
|
||||
jsiConsolePrintf("Caps Lock is turned On!\n");
|
||||
} else if ((report_val & OUTPUT_REPORT_BIT_MASK_CAPS_LOCK) == 0) {
|
||||
// Caps Lock is turned Off .
|
||||
jsiConsolePrintf("Caps Lock is turned Off!\n");
|
||||
} else {
|
||||
// The report received is not supported by this application. Do nothing.
|
||||
}
|
||||
// (report_val & 2) is caps lock
|
||||
// FIXME: Create an event for each HID output report
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -635,8 +628,7 @@ static void hids_init(void)
|
||||
memset((void *)input_report_array, 0, sizeof(ble_hids_inp_rep_init_t));
|
||||
memset((void *)output_report_array, 0, sizeof(ble_hids_outp_rep_init_t));
|
||||
|
||||
static uint8_t report_map_data[] =
|
||||
{
|
||||
static uint8_t report_map_data[] = {
|
||||
0x05, 0x01, // Usage Page (Generic Desktop)
|
||||
0x09, 0x06, // Usage (Keyboard)
|
||||
0xA1, 0x01, // Collection (Application)
|
||||
@ -683,18 +675,18 @@ static void hids_init(void)
|
||||
};
|
||||
|
||||
// Initialize HID Service
|
||||
p_input_report = &input_report_array[INPUT_REPORT_KEYS_INDEX];
|
||||
p_input_report->max_len = INPUT_REPORT_KEYS_MAX_LEN;
|
||||
p_input_report->rep_ref.report_id = INPUT_REP_REF_ID;
|
||||
p_input_report = &input_report_array[HID_INPUT_REPORT_KEYS_INDEX];
|
||||
p_input_report->max_len = HID_KEYS_MAX_LEN;
|
||||
p_input_report->rep_ref.report_id = HID_INPUT_REP_REF_ID;
|
||||
p_input_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_INPUT;
|
||||
|
||||
BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.cccd_write_perm);
|
||||
BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.read_perm);
|
||||
BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.write_perm);
|
||||
|
||||
p_output_report = &output_report_array[OUTPUT_REPORT_INDEX];
|
||||
p_output_report->max_len = OUTPUT_REPORT_MAX_LEN;
|
||||
p_output_report->rep_ref.report_id = OUTPUT_REP_REF_ID;
|
||||
p_output_report = &output_report_array[HID_OUTPUT_REPORT_INDEX];
|
||||
p_output_report->max_len = HID_OUTPUT_REPORT_MAX_LEN;
|
||||
p_output_report->rep_ref.report_id = HID_OUTPUT_REP_REF_ID;
|
||||
p_output_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_OUTPUT;
|
||||
|
||||
BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_output_report->security_mode.read_perm);
|
||||
@ -864,7 +856,6 @@ static void advertising_init() {
|
||||
adv_uuid_count++;
|
||||
}
|
||||
|
||||
jsiConsolePrintf("advertising_init 0x%x\n", bleStatus);
|
||||
memset(&scanrsp, 0, sizeof(scanrsp));
|
||||
scanrsp.uuids_complete.uuid_cnt = adv_uuid_count;
|
||||
scanrsp.uuids_complete.p_uuids = &adv_uuids[0];
|
||||
@ -1133,72 +1124,28 @@ void jsble_set_services(JsVar *data) {
|
||||
}
|
||||
}
|
||||
|
||||
/**@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_PACKETS 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_PACKETS, 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.
|
||||
*/
|
||||
uint32_t send_key_scan_press_release(uint8_t * p_key_pattern, uint16_t pattern_len) {
|
||||
void jsble_send_hid_input_report(uint8_t *data, int length) {
|
||||
if (!(bleStatus & BLE_HID_INITED)) {
|
||||
jsExceptionHere(JSET_ERROR, "BLE HID not enabled");
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
if (length > HID_KEYS_MAX_LEN) {
|
||||
jsExceptionHere(JSET_ERROR, "BLE HID report too long - max length = %d\n", HID_KEYS_MAX_LEN);
|
||||
return;
|
||||
}
|
||||
|
||||
bleStatus |= BLE_IS_SENDING_HID;
|
||||
uint32_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;
|
||||
|
||||
// Reset the data buffer.
|
||||
memset(data, 0, sizeof(data));
|
||||
|
||||
// Copy the scan code.
|
||||
memcpy(data + SCAN_CODE_POS, p_key_pattern, data_len);
|
||||
|
||||
//data[MODIFIER_KEY_POS] |= SHIFT_KEY_CODE;
|
||||
|
||||
if (!m_in_boot_mode) {
|
||||
err_code = ble_hids_inp_rep_send(&m_hids,
|
||||
INPUT_REPORT_KEYS_INDEX,
|
||||
INPUT_REPORT_KEYS_MAX_LEN,
|
||||
HID_INPUT_REPORT_KEYS_INDEX,
|
||||
length,
|
||||
data);
|
||||
} else {
|
||||
err_code = ble_hids_boot_kb_inp_rep_send(&m_hids,
|
||||
INPUT_REPORT_KEYS_MAX_LEN,
|
||||
length,
|
||||
data);
|
||||
}
|
||||
|
||||
return err_code;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -18,6 +18,12 @@
|
||||
#define APP_TIMER_OP_QUEUE_SIZE 1 /**< Size of timer operation queues. */
|
||||
#define APP_TIMER_PRESCALER 0 /**< Value of the RTC1 PRESCALER register. */
|
||||
|
||||
// BLE HID stuff
|
||||
#define HID_KEYS_MAX_LEN 8 /**< Maximum length of the Input Report characteristic. */
|
||||
#define HID_MODIFIER_KEY_POS 0 /**< Position of the modifier byte in the Input Report. */
|
||||
#define HID_SCAN_CODE_POS 2 /**< This macro indicates the start position of the key scan code in a HID Report. As per the document titled 'Device Class Definition for Human Interface Devices (HID) V1.11, each report shall have one modifier byte followed by a reserved constant byte and then the key scan code. */
|
||||
|
||||
|
||||
|
||||
typedef enum {
|
||||
BLE_NONE = 0,
|
||||
@ -29,8 +35,9 @@ typedef enum {
|
||||
|
||||
BLE_USING_NUS = 32, // Do we want to use the Nordic UART service?
|
||||
BLE_NUS_INITED = 64, // Has the Nordic UART service been initialised?
|
||||
BLE_USING_HID = 128,
|
||||
BLE_HID_INITED = 256
|
||||
BLE_USING_HID = 128, // Do we want to use the BLE HID service?
|
||||
BLE_HID_INITED = 256, // Has the BLE HID service been initialised?
|
||||
BLE_IS_SENDING_HID = 512, // Are we waiting to send data for USB HID?
|
||||
} BLEStatus;
|
||||
|
||||
|
||||
@ -72,8 +79,8 @@ uint32_t jsble_set_scanning(bool enabled);
|
||||
* then call this again */
|
||||
void jsble_set_services(JsVar *data);
|
||||
|
||||
uint32_t send_key_scan_press_release(uint8_t * p_key_pattern,
|
||||
uint16_t pattern_len);
|
||||
/// For BLE HID, send an input report to the receiver. Must be <= HID_KEYS_MAX_LEN
|
||||
void jsble_send_hid_input_report(uint8_t *data, int length);
|
||||
|
||||
// ------------------------------------------------- lower-level utility fns
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
#define BLE_SCAN_EVENT JS_EVENT_PREFIX"blescan"
|
||||
#define BLE_WRITE_EVENT JS_EVENT_PREFIX"blew"
|
||||
#define BLE_HID_SENT_EVENT JS_EVENT_PREFIX"blehid"
|
||||
/// Names for objects that get defined in the 'hidden root'
|
||||
#define BLE_NAME_SERVICE_DATA "BLE_SVC_D"
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user