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

How to implement Ctrl-C for HID keyboard

Hi Guys, I try to implements the ctrl-C/V for bluetooth HID keyboard. But from SDK, I can't figure out how to send two keys. Even I do not use buffer_enqueue/dequeue in order to keep 'Ctrl' pressed, not released, still can't work. Does anyone figure out how to work on it?

  • I have no clue how the SDK for HID or HID on bluetooth work, but in case it can help, on a regular keyboard you have "make" and "break" codes. You would send a "Ctrl" make (press) then a "C" make, then C break (release) and Ctrl break.

    From what I remember on USB HID (just checked 5-10 years old code), I'd get reports of X bytes, where X is the maximum amount of key presses keyboard would handle. In your case, let's imagine you support 8 keys, you'd first send a report (sorry, that's USB HID terminology, I don't know if they use the same in Bluetooth HID, take it as "packet" otherwise) with first byte indicating Ctrl, then 7 bytes to 0. Then a report with 1st byte indicating Ctrl, 2nd one indicating "C", then 6 bytes to 0. Then back to Ctrl in 1st byte and 7x 0 bytes, then a report with 8x 0 (not necessary, most OSes will only require C to be released to perform action, but nice to be clean and not have "ghost" keys).

    Hope that helps!

  • Thanks Jonathan. The Bluetooth HID is the same way like USB HID and I just lost in the SDK files. The SDK only support press-release mode, it's hard to implement press-hold-release mode.

  • Hi,

    I just checked what are escape codes for "ctr+c" and "ctr+v". I did it by debugging function: cli_state_collect in nrf_cli module.

    Here are escape codes:

    • ctr+c = 0x03
    • ctr+v = 0x16

    To handle it I would need to update cli_state_collect function with two extra cases in below switch statement:

    switch (data)
    {
        case NRF_CLI_VT100_ASCII_ESC:       /* ESCAPE */
            NRF_CLI_RECIEVE_STATE_NEXT(p_cli, NRF_CLI_RECEIVE_ESC);
            break;
        case '\0':
            break;
        case '\t':                          /* TAB */
            cli_tab_handle(p_cli);
            break;
        case NRF_CLI_VT100_ASCII_BSPACE:    /* BACKSPACE */
            char_backspace(p_cli);
            break;
        case NRF_CLI_VT100_ASCII_DEL:       /* DELETE */
            char_delete(p_cli);
            break;
    
        case 0x03   // ctr+c
            break;
        case 0x16:  // ctr+v
            break;
    
        default:
            if (isprint((int)data))
            {
                char_insert(p_cli, data);
            }
            break;
    }
    
  • The HID Usage tables, page 53, shows the codes for each key:

    www.usb.org/.../Hut1_12v2.pdf

    And the byte ordering is as following:

    Byte 0: Keyboard modifier bits (SHIFT, ALT, CTRL etc)

    Byte 1: reserved

    Byte 2-7: Up to six keyboard usage indexes representing the keys that are currently "pressed".

    On page 59, you can see that Keyboard LeftControl have Usage ID 224 / 0xE0.

    When a key is released, the specific key should be cleared (write 0 to it).

    The modifier byte is normally called "modifier keys". This is standardized as shown here in the mbed USB documentation:

    docs.mbed.com/.../md_doc_HID.html

    Note that when you're holding down one of these buttons, you will also have to release the key afterwards. If not, the PC/phone will not execute the command properly.

Related