Galzai / MK32

Keyboard firmware for ESP32 microcontrollers
676 stars 118 forks source link

Format of key_state and how to simulate key strokes #5

Closed bilogic closed 5 years ago

bilogic commented 5 years ago

Hi,

I'm trying to test the code and simulate key strokes without having to build an actual keyboard first.

https://github.com/Galzai/MK32/blob/37fb87100272915e3a93eb6e8c0dcbcecef880fe/components/r_encoder/r_encoder.c#L92-L98

https://github.com/Galzai/MK32/blob/37fb87100272915e3a93eb6e8c0dcbcecef880fe/components/r_encoder/r_encoder.c#L37

key_state is declared to be the length of REPORT_LEN which is 53 Any example of the format/values of key_state? It seems awfully long to send just 1 key or is it for nKRO?

It is my understanding that xQueueSend() will trigger xQueueReceive() in halBLETask_keyboard() => hid_dev_send_report() =>esp_ble_gatts_send_indicate(), but that is where I get lost, I cannot find much info about sending key strokes using esp_ble_gatts_send_indicate().

Thank you.

Galzai commented 5 years ago

Hey, The report is indeed the length of the key state for nKRO . Here's an explanation on how the descriptors and report work: https://eleccelerator.com/tutorial-about-usb-hid-report-descriptors/

Have a look at keypress_handles.c to understand how the reports work better in my implementation, but basically for key presses the value in index 0 of the report is for modifier keys (shift, ctrl etc) , index 1 is for led status keys (caps lock, num lock , etc) and the rest are for general key presses. Keep in mind the if you are sending reports directly to the queues you need to make sure you are sending the right type of report (Consumer, mouse or keyboard) to the right queue, they all have different lengths and data for each index (take a look at hal_ble.c to see the different queues) .

The easiest way to just send key strokes would basically be to edit the key_reports function in mk32_main.cpp. Instead of scanning the matrix. edit the report state according to the keys you would like to send and send them to thekeyboard_q.

If you would like to change the size of the reports without changing the size of the pads you can edit the report map (REPORT_COUNT_BYTES in 'keyboard_config.h') in hid_device_le_prf.c and split the report_state to smaller chunks sent consecutively (just make sure the size of the report you are sending to the queuecorresponds to the REPORT_COUNT_BYTES you have modified, REPORT_COUNT_BYTES correspond to the "general" keystrokes, so the report size will be always be larger by 2 indexes for modifier and led status keys). do not change REPORT_LEN though, just add another buffer to split the reports before sending them to the keyboard queue).

EDIT:I just noticed The code you quoted is for sending key reports via the encoder. the encoder has the option to send keystrokes as well, but because we already have a report dedicated for the keyboard the easiest way to send a keyboard report via the encoder is to simply use the queue we already have enabled.

bilogic commented 5 years ago

Hi,

Thanks for all the info, I will try and follow through.

Earlier, I managed to take inputs from the serial monitor and tried to send out as keystrokes

typedef enum
{
    PRESS = 0,
    RELEASE,
    PRESS_RELEASE,
    RELEASE_ALL
} keyboard_action;

typedef struct keyboard_command
{
    /** @brief type of this keyboard action */
    keyboard_action type;
    /** list of keycodes+modfiers to be pressed/released.
   * @note Low byte contains the keycode, high byte any modifiers
   * */
    uint16_t keycode;
} keyboard_command_t;

...

case '3':
    keycode = KC_AUDIO_VOL_DOWN;
    if ((keycode >= KC_MEDIA_NEXT_TRACK) && (keycode <= KC_AUDIO_VOL_DOWN))
    {
        media_control_send(keycode);
        media_control_release(keycode);
        ESP_LOGI(CONSOLE_UART_TAG, "media: vol-");
    }
    break;
case '4':
    keycode = KC_AUDIO_VOL_UP;
    if ((keycode >= KC_MEDIA_NEXT_TRACK) && (keycode <= KC_AUDIO_VOL_DOWN))
    {
        media_control_send(keycode);
        media_control_release(keycode);
        ESP_LOGI(CONSOLE_UART_TAG, "media: vol+");
    }
    break;
default:
    ESP_LOGI(CONSOLE_UART_TAG, "received: %d/'%c'", character, character);
    keyboardCmd.type = PRESS; // 0 aka no modifiers
    keyboardCmd.keycode = character;
    xQueueSend(keyboard_q, (void *)&keyboardCmd, (TickType_t)0);
    keyboardCmd.type = PRESS; // 0 aka no modifiers
    keyboardCmd.keycode = 0;
    xQueueSend(keyboard_q, (void *)&keyboardCmd, (TickType_t)0);
    break;
  1. For 'default', some keys had no effect or generated gibberish
  2. '4' had no effect
  3. '3' brought up the volume slider, but did not adjust volume up or down. Any idea why? (The code was copied from keypress_handles.c)
Galzai commented 5 years ago

Hey, In the default case you are sending a KeyboardCmd struct which is not what the queue expects, you need to send a uint8_t array with lengthREPORT_LEN and assign the keycode you would like to send to one of the indexes (except index 0 or 1 which are reserved as I stated before). for example:

uint8_t current_report[REPORT_LEN] = {0};   
current_report[2] = KC_Q;   
xQueueSend(keyboard_q, (void *)&current_report, (TickType_t)0);

regarding the media control functions on keypress, thank you for noticing, I need to alter them because of the updated Bluetooth components, though I did update them for the encoders, so for example for volume up (for volume up set bit 7 instead of 6:

uint8_t media_state[2]={0};   
SET_BIT(media_state[0],6);   
xQueueSend(media_q,(void*)&media_state, (TickType_t) 0);  

Hope this helps

bilogic commented 5 years ago

Hi,

This works now:

case '3':
    SET_BIT(media_state[0], 7);
    xQueueSend(media_q, (void *)&media_state, (TickType_t)0);
    media_state[0] = 0;
    xQueueSend(media_q, (void *)&media_state, (TickType_t)0);
    ESP_LOGI(CONSOLE_UART_TAG, "media: vol-");
    break;

case '4':
    SET_BIT(media_state[0], 6);
    xQueueSend(media_q, (void *)&media_state, (TickType_t)0);
    // vTaskDelay(5 / portTICK_PERIOD_MS);
    media_state[0] = 0;
    xQueueSend(media_q, (void *)&media_state, (TickType_t)0);
    ESP_LOGI(CONSOLE_UART_TAG, "media: vol+");
    break;

default:
    uint8_t current_report[REPORT_LEN] = {0};
    current_report[2] = KC_Q;
    xQueueSend(keyboard_q, (void *)&current_report, (TickType_t)0);
    current_report[2] = 0;
    xQueueSend(keyboard_q, (void *)&current_report, (TickType_t)0);

    ESP_LOGI(CONSOLE_UART_TAG, "normal: %d/'%c'", character, character);
    break;
  1. Volume down is bit 7, up is bit 6
  2. Is vTaskDelay(5 / portTICK_PERIOD_MS); required for key depressing? (I saw this in media_control_send() of keypress_handles.c)
  3. Is there any function to translate a character to keycode? (keycode_conv.c has a char_to_keycode() but it does nothing) I can write the code if you can help me understand where to read the correct keymap etc.
  4. I see GPIO 27, 32 and 33 defined for the encoder inside keyboard_config.h, what about the pins for the matrix/keys themselves?

Thank you!

bilogic commented 5 years ago
  1. Found the matrix GPIOs here https://github.com/Galzai/MK32/wiki/Customizable-layouts
  2. Hardware rotary encoder works but it seems to be skipping a beat, i.e. in Windows 10, volume goes up and down in even numbers only, 50, 52, 54 etc, any idea?