From 8f5c95c7906dd84dadc66cb5dca56ce4aee690b1 Mon Sep 17 00:00:00 2001 From: Cutch Date: Fri, 17 Jun 2022 13:13:42 -0400 Subject: [PATCH 01/12] Update the HID Keycodes to pull from the library --- applications/bad_usb/bad_usb_script.c | 146 +++---- .../targets/f7/furi_hal/furi_hal_usb_hid.c | 5 - .../furi_hal_include/furi_hal_usb_hid.h | 393 +++++++----------- 3 files changed, 220 insertions(+), 324 deletions(-) diff --git a/applications/bad_usb/bad_usb_script.c b/applications/bad_usb/bad_usb_script.c index 685e5083ac5..637a3422cbc 100644 --- a/applications/bad_usb/bad_usb_script.c +++ b/applications/bad_usb/bad_usb_script.c @@ -45,60 +45,60 @@ typedef struct { } DuckyKey; static const DuckyKey ducky_keys[] = { - {"CTRL-ALT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_ALT}, - {"CTRL-SHIFT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT}, - {"ALT-SHIFT", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_SHIFT}, - {"ALT-GUI", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_GUI}, - - {"CTRL", KEY_MOD_LEFT_CTRL}, - {"CONTROL", KEY_MOD_LEFT_CTRL}, - {"SHIFT", KEY_MOD_LEFT_SHIFT}, - {"ALT", KEY_MOD_LEFT_ALT}, - {"GUI", KEY_MOD_LEFT_GUI}, - {"WINDOWS", KEY_MOD_LEFT_GUI}, - - {"DOWNARROW", KEY_DOWN_ARROW}, - {"DOWN", KEY_DOWN_ARROW}, - {"LEFTARROW", KEY_LEFT_ARROW}, - {"LEFT", KEY_LEFT_ARROW}, - {"RIGHTARROW", KEY_RIGHT_ARROW}, - {"RIGHT", KEY_RIGHT_ARROW}, - {"UPARROW", KEY_UP_ARROW}, - {"UP", KEY_UP_ARROW}, - - {"ENTER", KEY_ENTER}, - {"BREAK", KEY_PAUSE}, - {"PAUSE", KEY_PAUSE}, - {"CAPSLOCK", KEY_CAPS_LOCK}, - {"DELETE", KEY_DELETE}, - {"BACKSPACE", KEY_BACKSPACE}, - {"END", KEY_END}, - {"ESC", KEY_ESC}, - {"ESCAPE", KEY_ESC}, - {"HOME", KEY_HOME}, - {"INSERT", KEY_INSERT}, - {"NUMLOCK", KEY_NUM_LOCK}, - {"PAGEUP", KEY_PAGE_UP}, - {"PAGEDOWN", KEY_PAGE_DOWN}, - {"PRINTSCREEN", KEY_PRINT}, - {"SCROLLOCK", KEY_SCROLL_LOCK}, - {"SPACE", KEY_SPACE}, - {"TAB", KEY_TAB}, - {"MENU", KEY_APPLICATION}, - {"APP", KEY_APPLICATION}, - - {"F1", KEY_F1}, - {"F2", KEY_F2}, - {"F3", KEY_F3}, - {"F4", KEY_F4}, - {"F5", KEY_F5}, - {"F6", KEY_F6}, - {"F7", KEY_F7}, - {"F8", KEY_F8}, - {"F9", KEY_F9}, - {"F10", KEY_F10}, - {"F11", KEY_F11}, - {"F12", KEY_F12}, + {"CTRL-ALT", HID_KEYBOARD_L_CTRL | HID_KEYBOARD_L_ALT}, + {"CTRL-SHIFT", HID_KEYBOARD_L_CTRL | HID_KEYBOARD_L_SHIFT}, + {"ALT-SHIFT", HID_KEYBOARD_L_ALT | HID_KEYBOARD_L_SHIFT}, + {"ALT-GUI", HID_KEYBOARD_L_ALT | HID_KEYBOARD_L_GUI}, + + {"CTRL", HID_KEYBOARD_L_CTRL}, + {"CONTROL", HID_KEYBOARD_L_CTRL}, + {"SHIFT", HID_KEYBOARD_L_SHIFT}, + {"ALT", HID_KEYBOARD_L_ALT}, + {"GUI", HID_KEYBOARD_L_GUI}, + {"WINDOWS", HID_KEYBOARD_L_GUI}, + + {"DOWNARROW", HID_KEYBOARD_DOWN_ARROW}, + {"DOWN", HID_KEYBOARD_DOWN_ARROW}, + {"LEFTARROW", HID_KEYBOARD_LEFT_ARROW}, + {"LEFT", HID_KEYBOARD_LEFT_ARROW}, + {"RIGHTARROW", HID_KEYBOARD_RIGHT_ARROW}, + {"RIGHT", HID_KEYBOARD_RIGHT_ARROW}, + {"UPARROW", HID_KEYBOARD_UP_ARROW}, + {"UP", HID_KEYBOARD_UP_ARROW}, + + {"ENTER", HID_KEYBOARD_RETURN}, + {"BREAK", HID_KEYBOARD_PAUSE}, + {"PAUSE", HID_KEYBOARD_PAUSE}, + {"CAPSLOCK", HID_KEYBOARD_CAPS_LOCK}, + {"DELETE", HID_KEYBOARD_DELETE}, + {"BACKSPACE", HID_KEYPAD_BACKSPACE}, + {"END", HID_KEYBOARD_END}, + {"ESC", HID_KEYBOARD_ESCAPE}, + {"ESCAPE", HID_KEYBOARD_ESCAPE}, + {"HOME", HID_KEYBOARD_HOME}, + {"INSERT", HID_KEYBOARD_INSERT}, + {"NUMLOCK", HID_KEYPAD_NUMLOCK}, + {"PAGEUP", HID_KEYBOARD_PAGE_UP}, + {"PAGEDOWN", HID_KEYBOARD_PAGE_DOWN}, + {"PRINTSCREEN", HID_KEYBOARD_PRINT_SCREEN}, + {"SCROLLOCK", HID_KEYBOARD_SCROLL_LOCK}, + {"SPACE", HID_KEYBOARD_SPACEBAR}, + {"TAB", HID_KEYBOARD_TAB}, + {"MENU", HID_KEYBOARD_APPLICATION}, + {"APP", HID_KEYBOARD_APPLICATION}, + + {"F1", HID_KEYBOARD_F1}, + {"F2", HID_KEYBOARD_F2}, + {"F3", HID_KEYBOARD_F3}, + {"F4", HID_KEYBOARD_F4}, + {"F5", HID_KEYBOARD_F5}, + {"F6", HID_KEYBOARD_F6}, + {"F7", HID_KEYBOARD_F7}, + {"F8", HID_KEYBOARD_F8}, + {"F9", HID_KEYBOARD_F9}, + {"F10", HID_KEYBOARD_F10}, + {"F11", HID_KEYBOARD_F11}, + {"F12", HID_KEYBOARD_F12}, }; static const char ducky_cmd_comment[] = {"REM"}; @@ -114,16 +114,16 @@ static const char ducky_cmd_altstr_1[] = {"ALTSTRING "}; static const char ducky_cmd_altstr_2[] = {"ALTCODE "}; static const uint8_t numpad_keys[10] = { - KEYPAD_0, - KEYPAD_1, - KEYPAD_2, - KEYPAD_3, - KEYPAD_4, - KEYPAD_5, - KEYPAD_6, - KEYPAD_7, - KEYPAD_8, - KEYPAD_9, + HID_KEYPAD_0, + HID_KEYPAD_1, + HID_KEYPAD_2, + HID_KEYPAD_3, + HID_KEYPAD_4, + HID_KEYPAD_5, + HID_KEYPAD_6, + HID_KEYPAD_7, + HID_KEYPAD_8, + HID_KEYPAD_9, }; static bool ducky_get_number(const char* param, uint32_t* val) { @@ -149,8 +149,8 @@ static bool ducky_is_line_end(const char chr) { static void ducky_numlock_on() { if((furi_hal_hid_get_led_state() & HID_KB_LED_NUM) == 0) { - furi_hal_hid_kb_press(KEY_NUM_LOCK); - furi_hal_hid_kb_release(KEY_NUM_LOCK); + furi_hal_hid_kb_press(HID_KEYBOARD_LOCK_NUM_LOCK); + furi_hal_hid_kb_release(HID_KEYBOARD_LOCK_NUM_LOCK); } } @@ -170,7 +170,7 @@ static bool ducky_altchar(const char* charcode) { FURI_LOG_I(WORKER_TAG, "char %s", charcode); - furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT); + furi_hal_hid_kb_press(HID_KEYBOARD_L_ALT); while(!ducky_is_line_end(charcode[i])) { state = ducky_numpad_press(charcode[i]); @@ -178,7 +178,7 @@ static bool ducky_altchar(const char* charcode) { i++; } - furi_hal_hid_kb_release(KEY_MOD_LEFT_ALT); + furi_hal_hid_kb_release(HID_KEYBOARD_L_ALT); return state; } @@ -206,7 +206,7 @@ static bool ducky_string(const char* param) { uint32_t i = 0; while(param[i] != '\0') { uint16_t keycode = HID_ASCII_TO_KEY(param[i]); - if(keycode != KEY_NONE) { + if(keycode != HID_KEYBOARD_NONE) { furi_hal_hid_kb_press(keycode); furi_hal_hid_kb_release(keycode); } @@ -217,9 +217,9 @@ static bool ducky_string(const char* param) { static uint16_t ducky_get_keycode(const char* param, bool accept_chars) { for(uint8_t i = 0; i < (sizeof(ducky_keys) / sizeof(ducky_keys[0])); i++) { - uint8_t key_cmd_len = strlen(ducky_keys[i].name); - if((strncmp(param, ducky_keys[i].name, key_cmd_len) == 0) && - (ducky_is_line_end(param[key_cmd_len]))) { + uint8_t HID_KEYBOARD_cmd_len = strlen(ducky_keys[i].name); + if((strncmp(param, ducky_keys[i].name, HID_KEYBOARD_cmd_len) == 0) && + (ducky_is_line_end(param[HID_KEYBOARD_cmd_len]))) { return ducky_keys[i].keycode; } } @@ -294,7 +294,7 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) { } else { // Special keys + modifiers uint16_t key = ducky_get_keycode(line_tmp, false); - if(key == KEY_NONE) return SCRIPT_STATE_ERROR; + if(key == HID_KEYBOARD_NONE) return SCRIPT_STATE_ERROR; if((key & 0xFF00) != 0) { // It's a modifier key line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c b/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c index aae4dd4fb6b..06f3f231f1a 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c @@ -6,11 +6,6 @@ #include "usb.h" #include "usb_hid.h" -#include "hid_usage_desktop.h" -#include "hid_usage_button.h" -#include "hid_usage_keyboard.h" -#include "hid_usage_consumer.h" -#include "hid_usage_led.h" #define HID_EP_IN 0x81 #define HID_EP_OUT 0x01 diff --git a/firmware/targets/furi_hal_include/furi_hal_usb_hid.h b/firmware/targets/furi_hal_include/furi_hal_usb_hid.h index 20c76223e99..7438e8feb32 100644 --- a/firmware/targets/furi_hal_include/furi_hal_usb_hid.h +++ b/firmware/targets/furi_hal_include/furi_hal_usb_hid.h @@ -1,253 +1,142 @@ #pragma once +#include "hid_usage_desktop.h" +#include "hid_usage_button.h" +#include "hid_usage_keyboard.h" +#include "hid_usage_consumer.h" +#include "hid_usage_led.h" -/** HID keyboard key codes */ -enum HidKeyboardKeys { - KEY_NONE = 0x00, - KEY_ERROR_ROLLOVER = 0x01, - KEY_POST_FAIL = 0x02, - KEY_ERROR_UNDEFINED = 0x03, - KEY_A = 0x04, - KEY_B = 0x05, - KEY_C = 0x06, - KEY_D = 0x07, - KEY_E = 0x08, - KEY_F = 0x09, - KEY_G = 0x0A, - KEY_H = 0x0B, - KEY_I = 0x0C, - KEY_J = 0x0D, - KEY_K = 0x0E, - KEY_L = 0x0F, - KEY_M = 0x10, - KEY_N = 0x11, - KEY_O = 0x12, - KEY_P = 0x13, - KEY_Q = 0x14, - KEY_R = 0x15, - KEY_S = 0x16, - KEY_T = 0x17, - KEY_U = 0x18, - KEY_V = 0x19, - KEY_W = 0x1A, - KEY_X = 0x1B, - KEY_Y = 0x1C, - KEY_Z = 0x1D, - KEY_1 = 0x1E, - KEY_2 = 0x1F, - KEY_3 = 0x20, - KEY_4 = 0x21, - KEY_5 = 0x22, - KEY_6 = 0x23, - KEY_7 = 0x24, - KEY_8 = 0x25, - KEY_9 = 0x26, - KEY_0 = 0x27, - KEY_ENTER = 0x28, - KEY_ESC = 0x29, - KEY_BACKSPACE = 0x2A, - KEY_TAB = 0x2B, - KEY_SPACE = 0x2C, - KEY_MINUS = 0x2D, - KEY_EQUAL = 0x2E, - KEY_LEFT_BRACE = 0x2F, - KEY_RIGHT_BRACE = 0x30, - KEY_BACKSLASH = 0x31, - KEY_NON_US_NUM = 0x32, - KEY_SEMICOLON = 0x33, - KEY_QUOTE = 0x34, - KEY_TILDE = 0x35, - KEY_COMMA = 0x36, - KEY_PERIOD = 0x37, - KEY_SLASH = 0x38, - KEY_CAPS_LOCK = 0x39, - KEY_F1 = 0x3A, - KEY_F2 = 0x3B, - KEY_F3 = 0x3C, - KEY_F4 = 0x3D, - KEY_F5 = 0x3E, - KEY_F6 = 0x3F, - KEY_F7 = 0x40, - KEY_F8 = 0x41, - KEY_F9 = 0x42, - KEY_F10 = 0x43, - KEY_F11 = 0x44, - KEY_F12 = 0x45, - KEY_PRINT = 0x46, - KEY_SCROLL_LOCK = 0x47, - KEY_PAUSE = 0x48, - KEY_INSERT = 0x49, - KEY_HOME = 0x4A, - KEY_PAGE_UP = 0x4B, - KEY_DELETE = 0x4C, - KEY_END = 0x4D, - KEY_PAGE_DOWN = 0x4E, - KEY_RIGHT_ARROW = 0x4F, - KEY_LEFT_ARROW = 0x50, - KEY_DOWN_ARROW = 0x51, - KEY_UP_ARROW = 0x52, - KEY_NUM_LOCK = 0x53, - KEYPAD_DIVIDE = 0x54, - KEYPAD_MULTIPLY = 0x55, - KEYPAD_SUBTRACT = 0x56, - KEYPAD_ADD = 0x57, - KEYPAD_ENTER = 0x58, - KEYPAD_1 = 0x59, - KEYPAD_2 = 0x5A, - KEYPAD_3 = 0x5B, - KEYPAD_4 = 0x5C, - KEYPAD_5 = 0x5D, - KEYPAD_6 = 0x5E, - KEYPAD_7 = 0x5F, - KEYPAD_8 = 0x60, - KEYPAD_9 = 0x61, - KEYPAD_0 = 0x62, - KEYPAD_DOT = 0x63, - KEY_NON_US = 0x64, - KEY_APPLICATION = 0x65, -}; - -/** HID keyboard modifier keys */ -enum HidKeyboardMods { - KEY_MOD_LEFT_CTRL = (1 << 8), - KEY_MOD_LEFT_SHIFT = (1 << 9), - KEY_MOD_LEFT_ALT = (1 << 10), - KEY_MOD_LEFT_GUI = (1 << 11), - KEY_MOD_RIGHT_CTRL = (1 << 12), - KEY_MOD_RIGHT_SHIFT = (1 << 13), - KEY_MOD_RIGHT_ALT = (1 << 14), - KEY_MOD_RIGHT_GUI = (1 << 15), -}; +#define HID_KEYBOARD_NONE 0x00 /** ASCII to keycode conversion table */ static const uint16_t hid_asciimap[] = { - KEY_NONE, // NUL - KEY_NONE, // SOH - KEY_NONE, // STX - KEY_NONE, // ETX - KEY_NONE, // EOT - KEY_NONE, // ENQ - KEY_NONE, // ACK - KEY_NONE, // BEL - KEY_BACKSPACE, // BS Backspace - KEY_TAB, // TAB Tab - KEY_ENTER, // LF Enter - KEY_NONE, // VT - KEY_NONE, // FF - KEY_NONE, // CR - KEY_NONE, // SO - KEY_NONE, // SI - KEY_NONE, // DEL - KEY_NONE, // DC1 - KEY_NONE, // DC2 - KEY_NONE, // DC3 - KEY_NONE, // DC4 - KEY_NONE, // NAK - KEY_NONE, // SYN - KEY_NONE, // ETB - KEY_NONE, // CAN - KEY_NONE, // EM - KEY_NONE, // SUB - KEY_NONE, // ESC - KEY_NONE, // FS - KEY_NONE, // GS - KEY_NONE, // RS - KEY_NONE, // US - KEY_SPACE, // ' ' Space - KEY_1 | KEY_MOD_LEFT_SHIFT, // ! - KEY_QUOTE | KEY_MOD_LEFT_SHIFT, // " - KEY_3 | KEY_MOD_LEFT_SHIFT, // # - KEY_4 | KEY_MOD_LEFT_SHIFT, // $ - KEY_5 | KEY_MOD_LEFT_SHIFT, // % - KEY_7 | KEY_MOD_LEFT_SHIFT, // & - KEY_QUOTE, // ' - KEY_9 | KEY_MOD_LEFT_SHIFT, // ( - KEY_0 | KEY_MOD_LEFT_SHIFT, // ) - KEY_8 | KEY_MOD_LEFT_SHIFT, // * - KEY_EQUAL | KEY_MOD_LEFT_SHIFT, // + - KEY_COMMA, // , - KEY_MINUS, // - - KEY_PERIOD, // . - KEY_SLASH, // / - KEY_0, // 0 - KEY_1, // 1 - KEY_2, // 2 - KEY_3, // 3 - KEY_4, // 4 - KEY_5, // 5 - KEY_6, // 6 - KEY_7, // 7 - KEY_8, // 8 - KEY_9, // 9 - KEY_SEMICOLON | KEY_MOD_LEFT_SHIFT, // : - KEY_SEMICOLON, // ; - KEY_COMMA | KEY_MOD_LEFT_SHIFT, // < - KEY_EQUAL, // = - KEY_PERIOD | KEY_MOD_LEFT_SHIFT, // > - KEY_SLASH | KEY_MOD_LEFT_SHIFT, // ? - KEY_2 | KEY_MOD_LEFT_SHIFT, // @ - KEY_A | KEY_MOD_LEFT_SHIFT, // A - KEY_B | KEY_MOD_LEFT_SHIFT, // B - KEY_C | KEY_MOD_LEFT_SHIFT, // C - KEY_D | KEY_MOD_LEFT_SHIFT, // D - KEY_E | KEY_MOD_LEFT_SHIFT, // E - KEY_F | KEY_MOD_LEFT_SHIFT, // F - KEY_G | KEY_MOD_LEFT_SHIFT, // G - KEY_H | KEY_MOD_LEFT_SHIFT, // H - KEY_I | KEY_MOD_LEFT_SHIFT, // I - KEY_J | KEY_MOD_LEFT_SHIFT, // J - KEY_K | KEY_MOD_LEFT_SHIFT, // K - KEY_L | KEY_MOD_LEFT_SHIFT, // L - KEY_M | KEY_MOD_LEFT_SHIFT, // M - KEY_N | KEY_MOD_LEFT_SHIFT, // N - KEY_O | KEY_MOD_LEFT_SHIFT, // O - KEY_P | KEY_MOD_LEFT_SHIFT, // P - KEY_Q | KEY_MOD_LEFT_SHIFT, // Q - KEY_R | KEY_MOD_LEFT_SHIFT, // R - KEY_S | KEY_MOD_LEFT_SHIFT, // S - KEY_T | KEY_MOD_LEFT_SHIFT, // T - KEY_U | KEY_MOD_LEFT_SHIFT, // U - KEY_V | KEY_MOD_LEFT_SHIFT, // V - KEY_W | KEY_MOD_LEFT_SHIFT, // W - KEY_X | KEY_MOD_LEFT_SHIFT, // X - KEY_Y | KEY_MOD_LEFT_SHIFT, // Y - KEY_Z | KEY_MOD_LEFT_SHIFT, // Z - KEY_LEFT_BRACE, // [ - KEY_BACKSLASH, // bslash - KEY_RIGHT_BRACE, // ] - KEY_6 | KEY_MOD_LEFT_SHIFT, // ^ - KEY_MINUS | KEY_MOD_LEFT_SHIFT, // _ - KEY_TILDE, // ` - KEY_A, // a - KEY_B, // b - KEY_C, // c - KEY_D, // d - KEY_E, // e - KEY_F, // f - KEY_G, // g - KEY_H, // h - KEY_I, // i - KEY_J, // j - KEY_K, // k - KEY_L, // l - KEY_M, // m - KEY_N, // n - KEY_O, // o - KEY_P, // p - KEY_Q, // q - KEY_R, // r - KEY_S, // s - KEY_T, // t - KEY_U, // u - KEY_V, // v - KEY_W, // w - KEY_X, // x - KEY_Y, // y - KEY_Z, // z - KEY_LEFT_BRACE | KEY_MOD_LEFT_SHIFT, // { - KEY_BACKSLASH | KEY_MOD_LEFT_SHIFT, // | - KEY_RIGHT_BRACE | KEY_MOD_LEFT_SHIFT, // } - KEY_TILDE | KEY_MOD_LEFT_SHIFT, // ~ - KEY_NONE, // DEL + HID_KEYBOARD_NONE, // NUL + HID_KEYBOARD_NONE, // SOH + HID_KEYBOARD_NONE, // STX + HID_KEYBOARD_NONE, // ETX + HID_KEYBOARD_NONE, // EOT + HID_KEYBOARD_NONE, // ENQ + HID_KEYBOARD_NONE, // ACK + HID_KEYBOARD_NONE, // BEL + HID_KEYPAD_BACKSPACE, // BS Backspace + HID_KEYPAD_TAB, // TAB Tab + HID_KEYPAD_ENTER, // LF Enter + HID_KEYBOARD_NONE, // VT + HID_KEYBOARD_NONE, // FF + HID_KEYBOARD_NONE, // CR + HID_KEYBOARD_NONE, // SO + HID_KEYBOARD_NONE, // SI + HID_KEYBOARD_NONE, // DEL + HID_KEYBOARD_NONE, // DC1 + HID_KEYBOARD_NONE, // DC2 + HID_KEYBOARD_NONE, // DC3 + HID_KEYBOARD_NONE, // DC4 + HID_KEYBOARD_NONE, // NAK + HID_KEYBOARD_NONE, // SYN + HID_KEYBOARD_NONE, // ETB + HID_KEYBOARD_NONE, // CAN + HID_KEYBOARD_NONE, // EM + HID_KEYBOARD_NONE, // SUB + HID_KEYBOARD_NONE, // ESC + HID_KEYBOARD_NONE, // FS + HID_KEYBOARD_NONE, // GS + HID_KEYBOARD_NONE, // RS + HID_KEYBOARD_NONE, // US + HID_KEYBOARD_SPACEBAR, // ' ' Space + HID_KEYBOARD_1 | HID_KEYBOARD_L_SHIFT, // ! + HID_KEYBOARD_APOSTROPHE | HID_KEYBOARD_L_SHIFT, // " + HID_KEYBOARD_3 | HID_KEYBOARD_L_SHIFT, // # + HID_KEYBOARD_4 | HID_KEYBOARD_L_SHIFT, // $ + HID_KEYBOARD_5 | HID_KEYBOARD_L_SHIFT, // % + HID_KEYBOARD_7 | HID_KEYBOARD_L_SHIFT, // & + HID_KEYBOARD_APOSTROPHE, // ' + HID_KEYBOARD_9 | HID_KEYBOARD_L_SHIFT, // ( + HID_KEYBOARD_0 | HID_KEYBOARD_L_SHIFT, // ) + HID_KEYBOARD_8 | HID_KEYBOARD_L_SHIFT, // * + HID_KEYBOARD_EQUAL_SIGN | HID_KEYBOARD_L_SHIFT, // + + HID_KEYPAD_COMMA, // , + HID_KEYBOARD_MINUS, // - + HID_KEYBOARD_DOT, // . + HID_KEYBOARD_SLASH, // / + HID_KEYBOARD_0, // 0 + HID_KEYBOARD_1, // 1 + HID_KEYBOARD_2, // 2 + HID_KEYBOARD_3, // 3 + HID_KEYBOARD_4, // 4 + HID_KEYBOARD_5, // 5 + HID_KEYBOARD_6, // 6 + HID_KEYBOARD_7, // 7 + HID_KEYBOARD_8, // 8 + HID_KEYBOARD_9, // 9 + HID_KEYBOARD_SEMICOLON | HID_KEYBOARD_L_SHIFT, // : + HID_KEYBOARD_SEMICOLON, // ; + HID_KEYPAD_COMMA | HID_KEYBOARD_L_SHIFT, // < + HID_KEYBOARD_EQUAL_SIGN, // = + HID_KEYBOARD_DOT | HID_KEYBOARD_L_SHIFT, // > + HID_KEYBOARD_SLASH | HID_KEYBOARD_L_SHIFT, // ? + HID_KEYBOARD_2 | HID_KEYBOARD_L_SHIFT, // @ + HID_KEYBOARD_A | HID_KEYBOARD_L_SHIFT, // A + HID_KEYBOARD_B | HID_KEYBOARD_L_SHIFT, // B + HID_KEYBOARD_C | HID_KEYBOARD_L_SHIFT, // C + HID_KEYBOARD_D | HID_KEYBOARD_L_SHIFT, // D + HID_KEYBOARD_E | HID_KEYBOARD_L_SHIFT, // E + HID_KEYBOARD_F | HID_KEYBOARD_L_SHIFT, // F + HID_KEYBOARD_G | HID_KEYBOARD_L_SHIFT, // G + HID_KEYBOARD_H | HID_KEYBOARD_L_SHIFT, // H + HID_KEYBOARD_I | HID_KEYBOARD_L_SHIFT, // I + HID_KEYBOARD_J | HID_KEYBOARD_L_SHIFT, // J + HID_KEYBOARD_K | HID_KEYBOARD_L_SHIFT, // K + HID_KEYBOARD_L | HID_KEYBOARD_L_SHIFT, // L + HID_KEYBOARD_M | HID_KEYBOARD_L_SHIFT, // M + HID_KEYBOARD_N | HID_KEYBOARD_L_SHIFT, // N + HID_KEYBOARD_O | HID_KEYBOARD_L_SHIFT, // O + HID_KEYBOARD_P | HID_KEYBOARD_L_SHIFT, // P + HID_KEYBOARD_Q | HID_KEYBOARD_L_SHIFT, // Q + HID_KEYBOARD_R | HID_KEYBOARD_L_SHIFT, // R + HID_KEYBOARD_S | HID_KEYBOARD_L_SHIFT, // S + HID_KEYBOARD_T | HID_KEYBOARD_L_SHIFT, // T + HID_KEYBOARD_U | HID_KEYBOARD_L_SHIFT, // U + HID_KEYBOARD_V | HID_KEYBOARD_L_SHIFT, // V + HID_KEYBOARD_W | HID_KEYBOARD_L_SHIFT, // W + HID_KEYBOARD_X | HID_KEYBOARD_L_SHIFT, // X + HID_KEYBOARD_Y | HID_KEYBOARD_L_SHIFT, // Y + HID_KEYBOARD_Z | HID_KEYBOARD_L_SHIFT, // Z + HID_KEYBOARD_OPEN_BRACKET, // [ + HID_KEYBOARD_BACKSLASH, // bslash + HID_KEYBOARD_CLOSE_BRACKET, // ] + HID_KEYBOARD_6 | HID_KEYBOARD_L_SHIFT, // ^ + HID_KEYBOARD_MINUS | HID_KEYBOARD_L_SHIFT, // _ + HID_KEYBOARD_GRAVE_ACCENT, // ` + HID_KEYBOARD_A, // a + HID_KEYBOARD_B, // b + HID_KEYBOARD_C, // c + HID_KEYBOARD_D, // d + HID_KEYBOARD_E, // e + HID_KEYBOARD_F, // f + HID_KEYBOARD_G, // g + HID_KEYBOARD_H, // h + HID_KEYBOARD_I, // i + HID_KEYBOARD_J, // j + HID_KEYBOARD_K, // k + HID_KEYBOARD_L, // l + HID_KEYBOARD_M, // m + HID_KEYBOARD_N, // n + HID_KEYBOARD_O, // o + HID_KEYBOARD_P, // p + HID_KEYBOARD_Q, // q + HID_KEYBOARD_R, // r + HID_KEYBOARD_S, // s + HID_KEYBOARD_T, // t + HID_KEYBOARD_U, // u + HID_KEYBOARD_V, // v + HID_KEYBOARD_W, // w + HID_KEYBOARD_X, // x + HID_KEYBOARD_Y, // y + HID_KEYBOARD_Z, // z + HID_KEYBOARD_OPEN_BRACKET | HID_KEYBOARD_L_SHIFT, // { + HID_KEYBOARD_BACKSLASH | HID_KEYBOARD_L_SHIFT, // | + HID_KEYBOARD_CLOSE_BRACKET | HID_KEYBOARD_L_SHIFT, // } + HID_KEYBOARD_GRAVE_ACCENT | HID_KEYBOARD_L_SHIFT, // ~ + HID_KEYBOARD_NONE, // DEL }; typedef struct { @@ -260,7 +149,19 @@ typedef struct { typedef void (*HidStateCallback)(bool state, void* context); /** ASCII to keycode conversion macro */ -#define HID_ASCII_TO_KEY(x) (((uint8_t)x < 128) ? (hid_asciimap[(uint8_t)x]) : KEY_NONE) +#define HID_ASCII_TO_KEY(x) (((uint8_t)x < 128) ? (hid_asciimap[(uint8_t)x]) : HID_KEYBOARD_NONE) + +/** HID keyboard modifiers */ +enum HidKeyboardModifiers { + HID_KB_MOD_L_CTRL = (1 << 0), + HID_KB_MOD_L_SHIFT = (1 << 1), + HID_KB_MOD_L_ALT = (1 << 2), + HID_KB_MOD_L_GUI = (1 << 3), + HID_KB_MOD_R_CTRL = (1 << 4), + HID_KB_MOD_R_SHIFT = (1 << 5), + HID_KB_MOD_R_ALT = (1 << 6), + HID_KB_MOD_R_GUI = (1 << 7), +}; /** HID keyboard leds */ enum HidKeyboardLeds { From c1c76e36e8f0a370ad925187e135f4583fbd2465 Mon Sep 17 00:00:00 2001 From: Cutch Date: Fri, 17 Jun 2022 13:20:55 -0400 Subject: [PATCH 02/12] Composite BLE Report Map, add consumer & mouse HID --- firmware/targets/f7/ble_glue/hid_service.c | 210 ++++++++---- firmware/targets/f7/ble_glue/hid_service.h | 11 +- .../targets/f7/furi_hal/furi_hal_bt_hid.c | 316 ++++++++++-------- .../furi_hal_include/furi_hal_bt_hid.h | 60 ++-- 4 files changed, 370 insertions(+), 227 deletions(-) diff --git a/firmware/targets/f7/ble_glue/hid_service.c b/firmware/targets/f7/ble_glue/hid_service.c index e30cdcb01b3..4941fa307be 100644 --- a/firmware/targets/f7/ble_glue/hid_service.c +++ b/firmware/targets/f7/ble_glue/hid_service.c @@ -9,10 +9,9 @@ typedef struct { uint16_t svc_handle; uint16_t protocol_mode_char_handle; - uint16_t report_char_handle; - uint16_t report_ref_desc_handle; + uint16_t report_char_handle[HID_SVC_REPORT_COUNT]; + uint16_t report_ref_desc_handle[HID_SVC_REPORT_COUNT]; uint16_t report_map_char_handle; - uint16_t keyboard_boot_char_handle; uint16_t info_char_handle; uint16_t ctrl_point_char_handle; } HIDSvc; @@ -47,12 +46,22 @@ void hid_svc_start() { SVCCTL_RegisterSvcHandler(hid_svc_event_handler); // Add service svc_uuid.Service_UUID_16 = HUMAN_INTERFACE_DEVICE_SERVICE_UUID; - status = - aci_gatt_add_service(UUID_TYPE_16, &svc_uuid, PRIMARY_SERVICE, 30, &hid_svc->svc_handle); + /** + * Add Human Interface Device Service + */ + status = aci_gatt_add_service( + UUID_TYPE_16, + &svc_uuid, + PRIMARY_SERVICE, + 2 + /* protocol mode */ + (4 * HID_SVC_INPUT_REPORT_COUNT) + (3 * HID_SVC_OUTPUT_REPORT_COUNT) + + (3 * HID_SVC_FEATURE_REPORT_COUNT) + 1 + 2 + 2 + + 2, /* Service + Report Map + HID Information + HID Control Point */ + &hid_svc->svc_handle); if(status) { FURI_LOG_E(TAG, "Failed to add HID service: %d", status); } - // Add Protocol mode characterstics + // Add Protocol mode characteristics char_uuid.Char_UUID_16 = PROTOCOL_MODE_CHAR_UUID; status = aci_gatt_add_char( hid_svc->svc_handle, @@ -75,42 +84,120 @@ void hid_svc_start() { if(status) { FURI_LOG_E(TAG, "Failed to update protocol mode characteristic: %d", status); } - // Add Report characterstics - char_uuid.Char_UUID_16 = REPORT_CHAR_UUID; - status = aci_gatt_add_char( - hid_svc->svc_handle, - UUID_TYPE_16, - &char_uuid, - HID_SVC_REPORT_MAX_LEN, - CHAR_PROP_READ | CHAR_PROP_NOTIFY, - ATTR_PERMISSION_NONE, - GATT_DONT_NOTIFY_EVENTS, - 10, - CHAR_VALUE_LEN_VARIABLE, - &hid_svc->report_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to add report characteristic: %d", status); - } - // Add Report descriptor - uint8_t desc_val[] = {0x00, 0x01}; - desc_uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID; - status = aci_gatt_add_char_desc( - hid_svc->svc_handle, - hid_svc->report_char_handle, - UUID_TYPE_16, - &desc_uuid, - HID_SVC_REPORT_REF_LEN, - HID_SVC_REPORT_REF_LEN, - desc_val, - ATTR_PERMISSION_NONE, - ATTR_ACCESS_READ_ONLY, - GATT_DONT_NOTIFY_EVENTS, - MIN_ENCRY_KEY_SIZE, - CHAR_VALUE_LEN_CONSTANT, - &hid_svc->report_ref_desc_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to add report reference descriptor: %d", status); + +#if(HID_SVC_REPORT_COUNT != 0) + for(uint8_t i = 0; i < HID_SVC_REPORT_COUNT; i++) { + if(i < HID_SVC_INPUT_REPORT_COUNT) { + uint8_t buf[2] = {i, 1}; // 1 input + char_uuid.Char_UUID_16 = REPORT_CHAR_UUID; + status = aci_gatt_add_char( + hid_svc->svc_handle, + UUID_TYPE_16, + &char_uuid, + HID_SVC_REPORT_MAX_LEN, + CHAR_PROP_READ | CHAR_PROP_NOTIFY, + ATTR_PERMISSION_NONE, + GATT_DONT_NOTIFY_EVENTS, + 10, + CHAR_VALUE_LEN_VARIABLE, + &(hid_svc->report_char_handle[i])); + if(status) { + FURI_LOG_E(TAG, "Failed to add report characteristic: %d", status); + } + + desc_uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID; + status = aci_gatt_add_char_desc( + hid_svc->svc_handle, + hid_svc->report_char_handle[i], + UUID_TYPE_16, + &desc_uuid, + HID_SVC_REPORT_REF_LEN, + HID_SVC_REPORT_REF_LEN, + buf, + ATTR_PERMISSION_NONE, + ATTR_ACCESS_READ_ONLY, + GATT_DONT_NOTIFY_EVENTS, + MIN_ENCRY_KEY_SIZE, + CHAR_VALUE_LEN_CONSTANT, + &(hid_svc->report_ref_desc_handle[i])); + if(status) { + FURI_LOG_E(TAG, "Failed to add report reference descriptor: %d", status); + } + } else if((i - HID_SVC_INPUT_REPORT_COUNT) < HID_SVC_OUTPUT_REPORT_COUNT) { + uint8_t buf[2] = {i, 2}; // 2 output + char_uuid.Char_UUID_16 = REPORT_CHAR_UUID; + status = aci_gatt_add_char( + hid_svc->svc_handle, + UUID_TYPE_16, + &char_uuid, + HID_SVC_REPORT_MAX_LEN, + CHAR_PROP_READ | CHAR_PROP_NOTIFY, + ATTR_PERMISSION_NONE, + GATT_DONT_NOTIFY_EVENTS, + 10, + CHAR_VALUE_LEN_VARIABLE, + &(hid_svc->report_char_handle[i])); + if(status) { + FURI_LOG_E(TAG, "Failed to add report characteristic: %d", status); + } + + desc_uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID; + status = aci_gatt_add_char_desc( + hid_svc->svc_handle, + hid_svc->report_char_handle[i], + UUID_TYPE_16, + &desc_uuid, + HID_SVC_REPORT_REF_LEN, + HID_SVC_REPORT_REF_LEN, + buf, + ATTR_PERMISSION_NONE, + ATTR_ACCESS_READ_ONLY, + GATT_DONT_NOTIFY_EVENTS, + MIN_ENCRY_KEY_SIZE, + CHAR_VALUE_LEN_CONSTANT, + &(hid_svc->report_ref_desc_handle[i])); + if(status) { + FURI_LOG_E(TAG, "Failed to add report reference descriptor: %d", status); + } + } else { + uint8_t buf[2] = {i, 3}; // 3 feature + char_uuid.Char_UUID_16 = REPORT_CHAR_UUID; + status = aci_gatt_add_char( + hid_svc->svc_handle, + UUID_TYPE_16, + &char_uuid, + HID_SVC_REPORT_MAX_LEN, + CHAR_PROP_READ | CHAR_PROP_NOTIFY, + ATTR_PERMISSION_NONE, + GATT_DONT_NOTIFY_EVENTS, + 10, + CHAR_VALUE_LEN_VARIABLE, + &(hid_svc->report_char_handle[i])); + if(status) { + FURI_LOG_E(TAG, "Failed to add report characteristic: %d", status); + } + + desc_uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID; + status = aci_gatt_add_char_desc( + hid_svc->svc_handle, + hid_svc->report_char_handle[i], + UUID_TYPE_16, + &desc_uuid, + HID_SVC_REPORT_REF_LEN, + HID_SVC_REPORT_REF_LEN, + buf, + ATTR_PERMISSION_NONE, + ATTR_ACCESS_READ_ONLY, + GATT_DONT_NOTIFY_EVENTS, + MIN_ENCRY_KEY_SIZE, + CHAR_VALUE_LEN_CONSTANT, + &(hid_svc->report_ref_desc_handle[i])); + if(status) { + FURI_LOG_E(TAG, "Failed to add report reference descriptor: %d", status); + } + } } +#endif // Add Report Map characteristic char_uuid.Char_UUID_16 = REPORT_MAP_CHAR_UUID; status = aci_gatt_add_char( @@ -127,22 +214,7 @@ void hid_svc_start() { if(status) { FURI_LOG_E(TAG, "Failed to add report map characteristic: %d", status); } - // Add Boot Keyboard characteristic - char_uuid.Char_UUID_16 = BOOT_KEYBOARD_INPUT_REPORT_CHAR_UUID; - status = aci_gatt_add_char( - hid_svc->svc_handle, - UUID_TYPE_16, - &char_uuid, - HID_SVC_BOOT_KEYBOARD_INPUT_REPORT_MAX_LEN, - CHAR_PROP_READ | CHAR_PROP_NOTIFY, - ATTR_PERMISSION_NONE, - GATT_NOTIFY_WRITE_REQ_AND_WAIT_FOR_APPL_RESP, - 10, - CHAR_VALUE_LEN_VARIABLE, - &hid_svc->keyboard_boot_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to add report map characteristic: %d", status); - } + // Add Information characteristic char_uuid.Char_UUID_16 = HID_INFORMATION_CHAR_UUID; status = aci_gatt_add_char( @@ -184,7 +256,7 @@ bool hid_svc_update_report_map(uint8_t* data, uint16_t len) { tBleStatus status = aci_gatt_update_char_value( hid_svc->svc_handle, hid_svc->report_map_char_handle, 0, len, data); if(status) { - FURI_LOG_E(TAG, "Failed updating report map characteristic"); + FURI_LOG_E(TAG, "Failed updating report map characteristic: %d", status); return false; } return true; @@ -194,10 +266,10 @@ bool hid_svc_update_input_report(uint8_t* data, uint16_t len) { furi_assert(data); furi_assert(hid_svc); - tBleStatus status = - aci_gatt_update_char_value(hid_svc->svc_handle, hid_svc->report_char_handle, 0, len, data); + tBleStatus status = aci_gatt_update_char_value( + hid_svc->svc_handle, hid_svc->report_char_handle[0], 0, len, data); if(status) { - FURI_LOG_E(TAG, "Failed updating report characteristic"); + FURI_LOG_E(TAG, "Failed updating report characteristic: %d", status); return false; } return true; @@ -210,7 +282,7 @@ bool hid_svc_update_info(uint8_t* data, uint16_t len) { tBleStatus status = aci_gatt_update_char_value(hid_svc->svc_handle, hid_svc->info_char_handle, 0, len, data); if(status) { - FURI_LOG_E(TAG, "Failed updating info characteristic"); + FURI_LOG_E(TAG, "Failed updating info characteristic: %d", status); return false; } return true; @@ -228,18 +300,18 @@ void hid_svc_stop() { if(status) { FURI_LOG_E(TAG, "Failed to delete Report Map characteristic: %d", status); } - status = aci_gatt_del_char(hid_svc->svc_handle, hid_svc->report_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to delete Report characteristic: %d", status); +#if(HID_SVC_INPUT_REPORT_COUNT != 0) + for(uint8_t i = 0; i < HID_SVC_REPORT_COUNT; i++) { + status = aci_gatt_del_char(hid_svc->svc_handle, hid_svc->report_char_handle[i]); + if(status) { + FURI_LOG_E(TAG, "Failed to delete Report characteristic: %d", status); + } } +#endif status = aci_gatt_del_char(hid_svc->svc_handle, hid_svc->protocol_mode_char_handle); if(status) { FURI_LOG_E(TAG, "Failed to delete Protocol Mode characteristic: %d", status); } - status = aci_gatt_del_char(hid_svc->svc_handle, hid_svc->keyboard_boot_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to delete Keyboard Boot characteristic: %d", status); - } status = aci_gatt_del_char(hid_svc->svc_handle, hid_svc->info_char_handle); if(status) { FURI_LOG_E(TAG, "Failed to delete Information characteristic: %d", status); diff --git a/firmware/targets/f7/ble_glue/hid_service.h b/firmware/targets/f7/ble_glue/hid_service.h index ed1394beb6b..0da41462fd2 100644 --- a/firmware/targets/f7/ble_glue/hid_service.h +++ b/firmware/targets/f7/ble_glue/hid_service.h @@ -3,13 +3,18 @@ #include #include -#define HID_SVC_REPORT_MAP_MAX_LEN (120) -#define HID_SVC_REPORT_MAX_LEN (9) -#define HID_SVC_BOOT_KEYBOARD_INPUT_REPORT_MAX_LEN (8) +#define HID_SVC_REPORT_MAP_MAX_LEN (512) +#define HID_SVC_REPORT_MAX_LEN (255) #define HID_SVC_REPORT_REF_LEN (2) #define HID_SVC_INFO_LEN (4) #define HID_SVC_CONTROL_POINT_LEN (1) +#define HID_SVC_INPUT_REPORT_COUNT (1) +#define HID_SVC_OUTPUT_REPORT_COUNT (0) +#define HID_SVC_FEATURE_REPORT_COUNT (0) +#define HID_SVC_REPORT_COUNT \ + (HID_SVC_INPUT_REPORT_COUNT + HID_SVC_OUTPUT_REPORT_COUNT + HID_SVC_FEATURE_REPORT_COUNT) + void hid_svc_start(); void hid_svc_stop(); diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c b/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c index 507dedfb260..b3ed101615e 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c @@ -1,4 +1,6 @@ #include "furi_hal_bt_hid.h" +#include "furi_hal_usb_hid.h" +#include "usb_hid.h" #include "dev_info_service.h" #include "battery_service.h" #include "hid_service.h" @@ -10,128 +12,114 @@ #define FURI_HAL_BT_HID_INFO_FLAG_REMOTE_WAKE_MSK (0x01) #define FURI_HAL_BT_HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK (0x02) -#define FURI_HAL_BT_HID_KB_KEYS_MAX (6) +#define FURI_HAL_BT_HID_KB_MAX_KEYS 6 +#define FURI_HAL_BT_HID_CONSUMER_MAX_KEYS 1 + +enum HidReportId { + ReportIdKeyboard = 1, + ReportIdMouse = 2, + ReportIdConsumer = 3, +}; typedef struct { - // uint8_t report_id; + uint8_t report_id; uint8_t mods; uint8_t reserved; - uint8_t key[FURI_HAL_BT_HID_KB_KEYS_MAX]; -} FuriHalBtHidKbReport; + uint8_t key[FURI_HAL_BT_HID_KB_MAX_KEYS]; +} __attribute__((__packed__)) FuriHalBtHidKbReport; typedef struct { uint8_t report_id; - uint8_t key; -} FuriHalBtHidMediaReport; + uint8_t btn; + int8_t x; + int8_t y; + int8_t wheel; +} __attribute__((__packed__)) FuriHalBtHidMouseReport; -// TODO make composite HID device +typedef struct { + uint8_t report_id; + uint16_t key[FURI_HAL_BT_HID_CONSUMER_MAX_KEYS]; +} __attribute__((__packed__)) FuriHalBtHidConsumerReport; + +// keyboard+mouse+consumer hid report static uint8_t furi_hal_bt_hid_report_map_data[] = { - 0x05, - 0x01, // Usage Page (Generic Desktop) - 0x09, - 0x06, // Usage (Keyboard) - 0xA1, - 0x01, // Collection (Application) - // 0x85, 0x01, // Report ID (1) - 0x05, - 0x07, // Usage Page (Key Codes) - 0x19, - 0xe0, // Usage Minimum (224) - 0x29, - 0xe7, // Usage Maximum (231) - 0x15, - 0x00, // Logical Minimum (0) - 0x25, - 0x01, // Logical Maximum (1) - 0x75, - 0x01, // Report Size (1) - 0x95, - 0x08, // Report Count (8) - 0x81, - 0x02, // Input (Data, Variable, Absolute) - - 0x95, - 0x01, // Report Count (1) - 0x75, - 0x08, // Report Size (8) - 0x81, - 0x01, // Input (Constant) reserved byte(1) - - 0x95, - 0x05, // Report Count (5) - 0x75, - 0x01, // Report Size (1) - 0x05, - 0x08, // Usage Page (Page# for LEDs) - 0x19, - 0x01, // Usage Minimum (1) - 0x29, - 0x05, // Usage Maximum (5) - 0x91, - 0x02, // Output (Data, Variable, Absolute), Led report - 0x95, - 0x01, // Report Count (1) - 0x75, - 0x03, // Report Size (3) - 0x91, - 0x01, // Output (Data, Variable, Absolute), Led report padding - - 0x95, - 0x06, // Report Count (6) - 0x75, - 0x08, // Report Size (8) - 0x15, - 0x00, // Logical Minimum (0) - 0x25, - 0x65, // Logical Maximum (101) - 0x05, - 0x07, // Usage Page (Key codes) - 0x19, - 0x00, // Usage Minimum (0) - 0x29, - 0x65, // Usage Maximum (101) - 0x81, - 0x00, // Input (Data, Array) Key array(6 bytes) - - 0x09, - 0x05, // Usage (Vendor Defined) - 0x15, - 0x00, // Logical Minimum (0) - 0x26, - 0xFF, - 0x00, // Logical Maximum (255) - 0x75, - 0x08, // Report Size (8 bit) - 0x95, - 0x02, // Report Count (2) - 0xB1, - 0x02, // Feature (Data, Variable, Absolute) - - 0xC0, // End Collection (Application) - - // 0x05, 0x0C, // Usage Page (Consumer) - // 0x09, 0x01, // Usage (Consumer Control) - // 0xA1, 0x01, // Collection (Application) - // 0x85, 0x02, // Report ID (2) - // 0x05, 0x0C, // Usage Page (Consumer) - // 0x15, 0x00, // Logical Minimum (0) - // 0x25, 0x01, // Logical Maximum (1) - // 0x75, 0x01, // Report Size (1) - // 0x95, 0x07, // Report Count (7) - // 0x09, 0xB5, // Usage (Scan Next Track) - // 0x09, 0xB6, // Usage (Scan Previous Track) - // 0x09, 0xB7, // Usage (Stop) - // 0x09, 0xB8, // Usage (Eject) - // 0x09, 0xCD, // Usage (Play/Pause) - // 0x09, 0xE2, // Usage (Mute) - // 0x09, 0xE9, // Usage (Volume Increment) - // 0x09, 0xEA, // Usage (Volume Decrement) - // 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - // 0xC0, // End Collection + // Keyboard Report + HID_USAGE_PAGE(HID_PAGE_DESKTOP), + HID_USAGE(HID_DESKTOP_KEYBOARD), + HID_COLLECTION(HID_APPLICATION_COLLECTION), + HID_REPORT_ID(ReportIdKeyboard), + HID_USAGE_PAGE(HID_DESKTOP_KEYPAD), + HID_USAGE_MINIMUM(HID_KEYBOARD_L_CTRL), + HID_USAGE_MAXIMUM(HID_KEYBOARD_R_GUI), + HID_LOGICAL_MINIMUM(0), + HID_LOGICAL_MAXIMUM(1), + HID_REPORT_SIZE(1), + HID_REPORT_COUNT(8), + HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + HID_REPORT_COUNT(1), + HID_REPORT_SIZE(8), + HID_INPUT(HID_IOF_CONSTANT | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + HID_USAGE_PAGE(HID_PAGE_LED), + HID_REPORT_COUNT(8), + HID_REPORT_SIZE(1), + HID_USAGE_MINIMUM(1), + HID_USAGE_MAXIMUM(8), + HID_OUTPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + HID_REPORT_COUNT(FURI_HAL_BT_HID_KB_MAX_KEYS), + HID_REPORT_SIZE(8), + HID_LOGICAL_MINIMUM(0), + HID_LOGICAL_MAXIMUM(101), + HID_USAGE_PAGE(HID_DESKTOP_KEYPAD), + HID_USAGE_MINIMUM(0), + HID_USAGE_MAXIMUM(101), + HID_INPUT(HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE), + HID_END_COLLECTION, + // Mouse Report + HID_USAGE_PAGE(HID_PAGE_DESKTOP), + HID_USAGE(HID_DESKTOP_MOUSE), + HID_COLLECTION(HID_APPLICATION_COLLECTION), + HID_USAGE(HID_DESKTOP_POINTER), + HID_COLLECTION(HID_PHYSICAL_COLLECTION), + HID_REPORT_ID(ReportIdMouse), + HID_USAGE_PAGE(HID_PAGE_BUTTON), + HID_USAGE_MINIMUM(1), + HID_USAGE_MAXIMUM(3), + HID_LOGICAL_MINIMUM(0), + HID_LOGICAL_MAXIMUM(1), + HID_REPORT_COUNT(3), + HID_REPORT_SIZE(1), + HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + HID_REPORT_SIZE(1), + HID_REPORT_COUNT(5), + HID_INPUT(HID_IOF_CONSTANT | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + HID_USAGE_PAGE(HID_PAGE_DESKTOP), + HID_USAGE(HID_DESKTOP_X), + HID_USAGE(HID_DESKTOP_Y), + HID_USAGE(HID_DESKTOP_WHEEL), + HID_LOGICAL_MINIMUM(-127), + HID_LOGICAL_MAXIMUM(127), + HID_REPORT_SIZE(8), + HID_REPORT_COUNT(3), + HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE), + HID_END_COLLECTION, + HID_END_COLLECTION, + // Consumer Report + HID_USAGE_PAGE(HID_PAGE_CONSUMER), + HID_USAGE(HID_CONSUMER_CONTROL), + HID_COLLECTION(HID_APPLICATION_COLLECTION), + HID_REPORT_ID(ReportIdConsumer), + HID_LOGICAL_MINIMUM(0), + HID_RI_LOGICAL_MAXIMUM(16, 0x3FF), + HID_USAGE_MINIMUM(0), + HID_RI_USAGE_MAXIMUM(16, 0x3FF), + HID_REPORT_COUNT(FURI_HAL_BT_HID_CONSUMER_MAX_KEYS), + HID_REPORT_SIZE(16), + HID_INPUT(HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE), + HID_END_COLLECTION, }; - FuriHalBtHidKbReport* kb_report = NULL; -FuriHalBtHidMediaReport* media_report = NULL; +FuriHalBtHidMouseReport* mouse_report = NULL; +FuriHalBtHidConsumerReport* consumer_report = NULL; void furi_hal_bt_hid_start() { // Start device info @@ -148,7 +136,11 @@ void furi_hal_bt_hid_start() { } // Configure HID Keyboard kb_report = malloc(sizeof(FuriHalBtHidKbReport)); - media_report = malloc(sizeof(FuriHalBtHidMediaReport)); + kb_report->report_id = ReportIdKeyboard; + mouse_report = malloc(sizeof(FuriHalBtHidMouseReport)); + mouse_report->report_id = ReportIdMouse; + consumer_report = malloc(sizeof(FuriHalBtHidConsumerReport)); + consumer_report->report_id = ReportIdConsumer; // Configure Report Map characteristic hid_svc_update_report_map( furi_hal_bt_hid_report_map_data, sizeof(furi_hal_bt_hid_report_map_data)); @@ -165,6 +157,8 @@ void furi_hal_bt_hid_start() { void furi_hal_bt_hid_stop() { furi_assert(kb_report); + furi_assert(mouse_report); + furi_assert(consumer_report); // Stop all services if(dev_info_svc_is_started()) { dev_info_svc_stop(); @@ -176,15 +170,16 @@ void furi_hal_bt_hid_stop() { hid_svc_stop(); } free(kb_report); - free(media_report); - media_report = NULL; + free(mouse_report); + free(consumer_report); kb_report = NULL; + mouse_report = NULL; + consumer_report = NULL; } bool furi_hal_bt_hid_kb_press(uint16_t button) { furi_assert(kb_report); - // kb_report->report_id = 0x01; - for(uint8_t i = 0; i < FURI_HAL_BT_HID_KB_KEYS_MAX; i++) { + for(uint8_t i = 0; i < FURI_HAL_BT_HID_KB_MAX_KEYS; i++) { if(kb_report->key[i] == 0) { kb_report->key[i] = button & 0xFF; break; @@ -196,8 +191,7 @@ bool furi_hal_bt_hid_kb_press(uint16_t button) { bool furi_hal_bt_hid_kb_release(uint16_t button) { furi_assert(kb_report); - // kb_report->report_id = 0x01; - for(uint8_t i = 0; i < FURI_HAL_BT_HID_KB_KEYS_MAX; i++) { + for(uint8_t i = 0; i < FURI_HAL_BT_HID_KB_MAX_KEYS; i++) { if(kb_report->key[i] == (button & 0xFF)) { kb_report->key[i] = 0; break; @@ -209,28 +203,80 @@ bool furi_hal_bt_hid_kb_release(uint16_t button) { bool furi_hal_bt_hid_kb_release_all() { furi_assert(kb_report); - // kb_report->report_id = 0x01; - memset(kb_report, 0, sizeof(FuriHalBtHidKbReport)); + for(uint8_t i = 0; i < FURI_HAL_BT_HID_KB_MAX_KEYS; i++) { + kb_report->key[i] = 0; + } + kb_report->mods = 0; return hid_svc_update_input_report((uint8_t*)kb_report, sizeof(FuriHalBtHidKbReport)); } -bool furi_hal_bt_hid_media_press(uint8_t button) { - furi_assert(media_report); - media_report->report_id = 0x02; - media_report->key |= (0x01 << button); - return hid_svc_update_input_report((uint8_t*)media_report, sizeof(FuriHalBtHidMediaReport)); +bool furi_hal_bt_hid_consumer_key_press(uint16_t button) { + furi_assert(consumer_report); + for(uint8_t i = 0; i < FURI_HAL_BT_HID_CONSUMER_MAX_KEYS; i++) { + if(consumer_report->key[i] == 0) { + consumer_report->key[i] = button; + break; + } + } + return hid_svc_update_input_report( + (uint8_t*)consumer_report, sizeof(FuriHalBtHidConsumerReport)); +} + +bool furi_hal_bt_hid_consumer_key_release(uint16_t button) { + furi_assert(consumer_report); + for(uint8_t i = 0; i < FURI_HAL_BT_HID_CONSUMER_MAX_KEYS; i++) { + if(consumer_report->key[i] == button) { + consumer_report->key[i] = 0; + break; + } + } + return hid_svc_update_input_report( + (uint8_t*)consumer_report, sizeof(FuriHalBtHidConsumerReport)); +} + +bool furi_hal_bt_hid_consumer_key_release_all() { + furi_assert(consumer_report); + for(uint8_t i = 0; i < FURI_HAL_BT_HID_CONSUMER_MAX_KEYS; i++) { + consumer_report->key[i] = 0; + } + return hid_svc_update_input_report( + (uint8_t*)consumer_report, sizeof(FuriHalBtHidConsumerReport)); +} + +bool furi_hal_bt_hid_mouse_move(int8_t dx, int8_t dy) { + furi_assert(mouse_report); + mouse_report->x = dx; + mouse_report->y = dy; + bool state = + hid_svc_update_input_report((uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); + mouse_report->x = 0; + mouse_report->y = 0; + return state; +} + +bool furi_hal_bt_hid_mouse_press(uint8_t button) { + furi_assert(mouse_report); + mouse_report->btn |= button; + return hid_svc_update_input_report((uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); +} + +bool furi_hal_bt_hid_mouse_release(uint8_t button) { + furi_assert(mouse_report); + mouse_report->btn &= ~button; + return hid_svc_update_input_report((uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); } -bool furi_hal_bt_hid_media_release(uint8_t button) { - furi_assert(media_report); - media_report->report_id = 0x02; - media_report->key &= ~(0x01 << button); - return hid_svc_update_input_report((uint8_t*)media_report, sizeof(FuriHalBtHidMediaReport)); +bool furi_hal_bt_hid_mouse_release_all() { + furi_assert(mouse_report); + mouse_report->btn = 0; + return hid_svc_update_input_report((uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); } -bool furi_hal_bt_hid_media_release_all() { - furi_assert(media_report); - media_report->report_id = 0x02; - media_report->key = 0x00; - return hid_svc_update_input_report((uint8_t*)media_report, sizeof(FuriHalBtHidMediaReport)); +bool furi_hal_bt_hid_mouse_scroll(int8_t delta) { + furi_assert(mouse_report); + mouse_report->wheel = delta; + bool state = + hid_svc_update_input_report((uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); + mouse_report->wheel = 0; + return state; } diff --git a/firmware/targets/furi_hal_include/furi_hal_bt_hid.h b/firmware/targets/furi_hal_include/furi_hal_bt_hid.h index 4faeebaeb3f..e35edd01c06 100644 --- a/firmware/targets/furi_hal_include/furi_hal_bt_hid.h +++ b/firmware/targets/furi_hal_include/furi_hal_bt_hid.h @@ -3,17 +3,6 @@ #include #include -enum FuriHalBtHidMediKeys { - FuriHalBtHidMediaScanNext, - FuriHalBtHidMediaScanPrevious, - FuriHalBtHidMediaStop, - FuriHalBtHidMediaEject, - FuriHalBtHidMediaPlayPause, - FuriHalBtHidMediaMute, - FuriHalBtHidMediaVolumeUp, - FuriHalBtHidMediaVolumeDown, -}; - /** Start Hid Keyboard Profile */ void furi_hal_bt_hid_start(); @@ -44,20 +33,51 @@ bool furi_hal_bt_hid_kb_release(uint16_t button); */ bool furi_hal_bt_hid_kb_release_all(); -/** Release all media buttons +/** Set mouse movement and send HID report * - * @return true on success + * @param dx x coordinate delta + * @param dy y coordinate delta */ -bool furi_hal_bt_hid_media_press(uint8_t button); +bool furi_hal_bt_hid_mouse_move(int8_t dx, int8_t dy); -/** Release all media buttons +/** Set mouse button to pressed state and send HID report * - * @return true on success + * @param button key code */ -bool furi_hal_bt_hid_media_release(uint8_t button); +bool furi_hal_bt_hid_mouse_press(uint8_t button); -/** Release all media buttons +/** Set mouse button to released state and send HID report * - * @return true on success + * @param button key code + */ +bool furi_hal_bt_hid_mouse_release(uint8_t button); + +/** Set mouse button to released state and send HID report + * + * @param button key code + */ +bool furi_hal_bt_hid_mouse_release_all(); + +/** Set mouse wheel position and send HID report + * + * @param delta number of scroll steps + */ +bool furi_hal_bt_hid_mouse_scroll(int8_t delta); + +/** Set the following consumer key to pressed state and send HID report + * + * @param button key code + */ +bool furi_hal_bt_hid_consumer_key_press(uint16_t button); + +/** Set the following consumer key to released state and send HID report + * + * @param button key code + */ +bool furi_hal_bt_hid_consumer_key_release(uint16_t button); + +/** Set consumer key to released state and send HID report + * + * @param button key code */ -bool furi_hal_bt_hid_media_release_all(); +bool furi_hal_bt_hid_consumer_key_release_all(); From 00cb82d7b0b1939085f824949ebbc4bb4175cdeb Mon Sep 17 00:00:00 2001 From: Cutch Date: Fri, 17 Jun 2022 13:21:41 -0400 Subject: [PATCH 03/12] Add Mouse & keyboard bt remote, fixed media remote --- applications/bt/bt_hid_app/bt_hid.c | 36 +- applications/bt/bt_hid_app/bt_hid.h | 6 + .../bt/bt_hid_app/views/bt_hid_keyboard.c | 382 ++++++++++++++++++ .../bt/bt_hid_app/views/bt_hid_keyboard.h | 13 + .../bt/bt_hid_app/views/bt_hid_keynote.c | 153 +++---- .../bt/bt_hid_app/views/bt_hid_media.c | 36 +- .../bt/bt_hid_app/views/bt_hid_mouse.c | 207 ++++++++++ .../bt/bt_hid_app/views/bt_hid_mouse.h | 13 + assets/compiled/assets_icons.c | 8 + assets/compiled/assets_icons.h | 2 + .../icons/BLE/BLE_HID/Ble_connected_15x15.png | Bin 0 -> 177 bytes .../BLE/BLE_HID/Ble_disconnected_15x15.png | Bin 0 -> 178 bytes firmware/targets/f7/furi_hal/furi_hal_bt.c | 4 +- 13 files changed, 764 insertions(+), 96 deletions(-) create mode 100644 applications/bt/bt_hid_app/views/bt_hid_keyboard.c create mode 100644 applications/bt/bt_hid_app/views/bt_hid_keyboard.h create mode 100644 applications/bt/bt_hid_app/views/bt_hid_mouse.c create mode 100644 applications/bt/bt_hid_app/views/bt_hid_mouse.h create mode 100644 assets/icons/BLE/BLE_HID/Ble_connected_15x15.png create mode 100644 assets/icons/BLE/BLE_HID/Ble_disconnected_15x15.png diff --git a/applications/bt/bt_hid_app/bt_hid.c b/applications/bt/bt_hid_app/bt_hid.c index 4b1037cdd73..47ee2268d81 100755 --- a/applications/bt/bt_hid_app/bt_hid.c +++ b/applications/bt/bt_hid_app/bt_hid.c @@ -6,7 +6,9 @@ enum BtDebugSubmenuIndex { BtHidSubmenuIndexKeynote, + BtHidSubmenuIndexKeyboard, BtHidSubmenuIndexMedia, + BtHidSubmenuIndexMouse, }; void bt_hid_submenu_callback(void* context, uint32_t index) { @@ -15,9 +17,15 @@ void bt_hid_submenu_callback(void* context, uint32_t index) { if(index == BtHidSubmenuIndexKeynote) { app->view_id = BtHidViewKeynote; view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewKeynote); + } else if(index == BtHidSubmenuIndexKeyboard) { + app->view_id = BtHidViewKeyboard; + view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewKeyboard); } else if(index == BtHidSubmenuIndexMedia) { app->view_id = BtHidViewMedia; view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewMedia); + } else if(index == BtHidSubmenuIndexMouse) { + app->view_id = BtHidViewMouse; + view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewMouse); } } @@ -25,10 +33,11 @@ void bt_hid_dialog_callback(DialogExResult result, void* context) { furi_assert(context); BtHid* app = context; if(result == DialogExResultLeft) { - // TODO switch to Submenu after Media is done view_dispatcher_stop(app->view_dispatcher); } else if(result == DialogExResultRight) { - view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewKeynote); + view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id); // Show last view + } else if(result == DialogExResultCenter) { + view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewSubmenu); } } @@ -52,7 +61,9 @@ void bt_hid_connection_status_changed_callback(BtStatus status, void* context) { notification_internal_message(bt_hid->notifications, &sequence_reset_blue); } bt_hid_keynote_set_connected_status(bt_hid->bt_hid_keynote, connected); + bt_hid_keyboard_set_connected_status(bt_hid->bt_hid_keyboard, connected); bt_hid_media_set_connected_status(bt_hid->bt_hid_media, connected); + bt_hid_mouse_set_connected_status(bt_hid->bt_hid_mouse, connected); } BtHid* bt_hid_app_alloc() { @@ -76,8 +87,11 @@ BtHid* bt_hid_app_alloc() { app->submenu = submenu_alloc(); submenu_add_item( app->submenu, "Keynote", BtHidSubmenuIndexKeynote, bt_hid_submenu_callback, app); + submenu_add_item( + app->submenu, "Keyboard", BtHidSubmenuIndexKeyboard, bt_hid_submenu_callback, app); submenu_add_item( app->submenu, "Media player", BtHidSubmenuIndexMedia, bt_hid_submenu_callback, app); + submenu_add_item(app->submenu, "Mouse", BtHidSubmenuIndexMouse, bt_hid_submenu_callback, app); view_set_previous_callback(submenu_get_view(app->submenu), bt_hid_exit); view_dispatcher_add_view( app->view_dispatcher, BtHidViewSubmenu, submenu_get_view(app->submenu)); @@ -88,6 +102,7 @@ BtHid* bt_hid_app_alloc() { dialog_ex_set_context(app->dialog, app); dialog_ex_set_left_button_text(app->dialog, "Exit"); dialog_ex_set_right_button_text(app->dialog, "Stay"); + dialog_ex_set_center_button_text(app->dialog, "Menu"); dialog_ex_set_header(app->dialog, "Close current app?", 16, 12, AlignLeft, AlignTop); view_dispatcher_add_view( app->view_dispatcher, BtHidViewExitConfirm, dialog_ex_get_view(app->dialog)); @@ -99,12 +114,25 @@ BtHid* bt_hid_app_alloc() { view_dispatcher_add_view( app->view_dispatcher, BtHidViewKeynote, bt_hid_keynote_get_view(app->bt_hid_keynote)); + // Keyboard view + app->bt_hid_keyboard = bt_hid_keyboard_alloc(); + view_set_previous_callback( + bt_hid_keyboard_get_view(app->bt_hid_keyboard), bt_hid_exit_confirm_view); + view_dispatcher_add_view( + app->view_dispatcher, BtHidViewKeyboard, bt_hid_keyboard_get_view(app->bt_hid_keyboard)); + // Media view app->bt_hid_media = bt_hid_media_alloc(); view_set_previous_callback(bt_hid_media_get_view(app->bt_hid_media), bt_hid_exit_confirm_view); view_dispatcher_add_view( app->view_dispatcher, BtHidViewMedia, bt_hid_media_get_view(app->bt_hid_media)); + // Mouse view + app->bt_hid_mouse = bt_hid_mouse_alloc(); + view_set_previous_callback(bt_hid_mouse_get_view(app->bt_hid_mouse), bt_hid_exit_confirm_view); + view_dispatcher_add_view( + app->view_dispatcher, BtHidViewMouse, bt_hid_mouse_get_view(app->bt_hid_mouse)); + // TODO switch to menu after Media is done view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewKeynote); @@ -124,8 +152,12 @@ void bt_hid_app_free(BtHid* app) { dialog_ex_free(app->dialog); view_dispatcher_remove_view(app->view_dispatcher, BtHidViewKeynote); bt_hid_keynote_free(app->bt_hid_keynote); + view_dispatcher_remove_view(app->view_dispatcher, BtHidViewKeyboard); + bt_hid_keyboard_free(app->bt_hid_keyboard); view_dispatcher_remove_view(app->view_dispatcher, BtHidViewMedia); bt_hid_media_free(app->bt_hid_media); + view_dispatcher_remove_view(app->view_dispatcher, BtHidViewMouse); + bt_hid_mouse_free(app->bt_hid_mouse); view_dispatcher_free(app->view_dispatcher); // Close records diff --git a/applications/bt/bt_hid_app/bt_hid.h b/applications/bt/bt_hid_app/bt_hid.h index 875cac58945..81d092db4d0 100644 --- a/applications/bt/bt_hid_app/bt_hid.h +++ b/applications/bt/bt_hid_app/bt_hid.h @@ -10,7 +10,9 @@ #include #include #include "views/bt_hid_keynote.h" +#include "views/bt_hid_keyboard.h" #include "views/bt_hid_media.h" +#include "views/bt_hid_mouse.h" typedef struct { Bt* bt; @@ -20,13 +22,17 @@ typedef struct { Submenu* submenu; DialogEx* dialog; BtHidKeynote* bt_hid_keynote; + BtHidKeyboard* bt_hid_keyboard; BtHidMedia* bt_hid_media; + BtHidMouse* bt_hid_mouse; uint32_t view_id; } BtHid; typedef enum { BtHidViewSubmenu, BtHidViewKeynote, + BtHidViewKeyboard, BtHidViewMedia, + BtHidViewMouse, BtHidViewExitConfirm, } BtHidView; diff --git a/applications/bt/bt_hid_app/views/bt_hid_keyboard.c b/applications/bt/bt_hid_app/views/bt_hid_keyboard.c new file mode 100644 index 00000000000..86d90aef89c --- /dev/null +++ b/applications/bt/bt_hid_app/views/bt_hid_keyboard.c @@ -0,0 +1,382 @@ +#include "bt_hid_keyboard.h" +#include +#include +#include +#include +#include + +struct BtHidKeyboard { + View* view; +}; + +typedef struct { + bool shift; + bool alt; + bool ctrl; + bool gui; + uint8_t x; + uint8_t y; + uint8_t last_key_code; + uint8_t modifier_code; + bool ok_pressed; + bool back_pressed; + bool connected; +} BtHidKeyboardModel; + +typedef struct { + uint8_t width; + char* key; + const Icon* icon; + char* shift_key; + uint8_t value; +} BtHidKeyboardKey; + +typedef struct { + int8_t x; + int8_t y; +} BtHidKeyboardPoint; +// 4 BY 12 +#define MARGIN_TOP 0 +#define MARGIN_LEFT 4 +#define KEY_WIDTH 9 +#define KEY_HEIGHT 12 +#define KEY_PADDING 1 +#define ROW_COUNT 6 +#define COLUMN_COUNT 12 + +// 0 width items are not drawn, but there value is used +BtHidKeyboardKey keyboardKeySet[ROW_COUNT][COLUMN_COUNT] = { + { + {.width = 1, .icon = NULL, .key = "1", .shift_key = "!", .value = HID_KEYBOARD_1}, + {.width = 1, .icon = NULL, .key = "2", .shift_key = "@", .value = HID_KEYBOARD_2}, + {.width = 1, .icon = NULL, .key = "3", .shift_key = "#", .value = HID_KEYBOARD_3}, + {.width = 1, .icon = NULL, .key = "4", .shift_key = "$", .value = HID_KEYBOARD_4}, + {.width = 1, .icon = NULL, .key = "5", .shift_key = "%", .value = HID_KEYBOARD_5}, + {.width = 1, .icon = NULL, .key = "6", .shift_key = "^", .value = HID_KEYBOARD_6}, + {.width = 1, .icon = NULL, .key = "7", .shift_key = "&", .value = HID_KEYBOARD_7}, + {.width = 1, .icon = NULL, .key = "8", .shift_key = "*", .value = HID_KEYBOARD_8}, + {.width = 1, .icon = NULL, .key = "9", .shift_key = "(", .value = HID_KEYBOARD_9}, + {.width = 1, .icon = NULL, .key = "0", .shift_key = ")", .value = HID_KEYBOARD_0}, + {.width = 2, .icon = &I_Pin_arrow_left_9x7, .value = HID_KEYBOARD_DELETE}, + {.width = 0, .value = HID_KEYBOARD_DELETE}, + }, + { + {.width = 1, .icon = NULL, .key = "q", .shift_key = "Q", .value = HID_KEYBOARD_Q}, + {.width = 1, .icon = NULL, .key = "w", .shift_key = "W", .value = HID_KEYBOARD_W}, + {.width = 1, .icon = NULL, .key = "e", .shift_key = "E", .value = HID_KEYBOARD_E}, + {.width = 1, .icon = NULL, .key = "r", .shift_key = "R", .value = HID_KEYBOARD_R}, + {.width = 1, .icon = NULL, .key = "t", .shift_key = "T", .value = HID_KEYBOARD_T}, + {.width = 1, .icon = NULL, .key = "y", .shift_key = "Y", .value = HID_KEYBOARD_Y}, + {.width = 1, .icon = NULL, .key = "u", .shift_key = "U", .value = HID_KEYBOARD_U}, + {.width = 1, .icon = NULL, .key = "i", .shift_key = "I", .value = HID_KEYBOARD_I}, + {.width = 1, .icon = NULL, .key = "o", .shift_key = "O", .value = HID_KEYBOARD_O}, + {.width = 1, .icon = NULL, .key = "p", .shift_key = "P", .value = HID_KEYBOARD_P}, + {.width = 1, .icon = NULL, .key = "[", .shift_key = "{", .value = HID_KEYBOARD_OPEN_BRACKET}, + {.width = 1, + .icon = NULL, + .key = "]", + .shift_key = "}", + .value = HID_KEYBOARD_CLOSE_BRACKET}, + }, + { + {.width = 1, .icon = NULL, .key = "a", .shift_key = "A", .value = HID_KEYBOARD_Q}, + {.width = 1, .icon = NULL, .key = "s", .shift_key = "S", .value = HID_KEYBOARD_W}, + {.width = 1, .icon = NULL, .key = "d", .shift_key = "D", .value = HID_KEYBOARD_E}, + {.width = 1, .icon = NULL, .key = "f", .shift_key = "F", .value = HID_KEYBOARD_R}, + {.width = 1, .icon = NULL, .key = "g", .shift_key = "G", .value = HID_KEYBOARD_T}, + {.width = 1, .icon = NULL, .key = "h", .shift_key = "H", .value = HID_KEYBOARD_Y}, + {.width = 1, .icon = NULL, .key = "j", .shift_key = "J", .value = HID_KEYBOARD_U}, + {.width = 1, .icon = NULL, .key = "k", .shift_key = "K", .value = HID_KEYBOARD_I}, + {.width = 1, .icon = NULL, .key = "l", .shift_key = "L", .value = HID_KEYBOARD_O}, + {.width = 1, .icon = NULL, .key = ";", .shift_key = ":", .value = HID_KEYBOARD_SEMICOLON}, + {.width = 2, .icon = &I_Pin_arrow_right_9x7, .value = HID_KEYBOARD_RETURN}, + {.width = 0, .value = HID_KEYBOARD_RETURN}, + }, + { + {.width = 1, .icon = NULL, .key = "z", .shift_key = "Z", .value = HID_KEYBOARD_Z}, + {.width = 1, .icon = NULL, .key = "x", .shift_key = "X", .value = HID_KEYBOARD_X}, + {.width = 1, .icon = NULL, .key = "c", .shift_key = "C", .value = HID_KEYBOARD_C}, + {.width = 1, .icon = NULL, .key = "v", .shift_key = "V", .value = HID_KEYBOARD_V}, + {.width = 1, .icon = NULL, .key = "b", .shift_key = "B", .value = HID_KEYBOARD_B}, + {.width = 1, .icon = NULL, .key = "n", .shift_key = "N", .value = HID_KEYBOARD_N}, + {.width = 1, .icon = NULL, .key = "m", .shift_key = "M", .value = HID_KEYBOARD_M}, + {.width = 1, .icon = NULL, .key = "/", .shift_key = "?", .value = HID_KEYBOARD_SLASH}, + {.width = 1, .icon = NULL, .key = "\\", .shift_key = "|", .value = HID_KEYBOARD_BACKSLASH}, + {.width = 1, .icon = NULL, .key = "`", .shift_key = "~", .value = HID_KEYBOARD_GRAVE_ACCENT}, + {.width = 1, .icon = &I_ButtonUp_7x4, .value = HID_KEYBOARD_UP_ARROW}, + {.width = 1, .icon = NULL, .key = "-", .shift_key = "_", .value = HID_KEYBOARD_MINUS}, + }, + { + {.width = 1, .icon = &I_Pin_arrow_up7x9, .value = HID_KEYBOARD_L_SHIFT}, + {.width = 1, .icon = NULL, .key = ",", .shift_key = "<", .value = HID_KEYPAD_COMMA}, + {.width = 1, .icon = NULL, .key = ".", .shift_key = ">", .value = HID_KEYBOARD_DOT}, + {.width = 4, .icon = NULL, .key = " ", .value = HID_KEYBOARD_SPACEBAR}, + {.width = 0, .value = HID_KEYBOARD_SPACEBAR}, + {.width = 0, .value = HID_KEYBOARD_SPACEBAR}, + {.width = 0, .value = HID_KEYBOARD_SPACEBAR}, + {.width = 1, .icon = NULL, .key = "'", .shift_key = "\"", .value = HID_KEYBOARD_APOSTROPHE}, + {.width = 1, .icon = NULL, .key = "=", .shift_key = "+", .value = HID_KEYBOARD_EQUAL_SIGN}, + {.width = 1, .icon = &I_ButtonLeft_4x7, .value = HID_KEYBOARD_LEFT_ARROW}, + {.width = 1, .icon = &I_ButtonDown_7x4, .value = HID_KEYBOARD_DOWN_ARROW}, + {.width = 1, .icon = &I_ButtonRight_4x7, .value = HID_KEYBOARD_RIGHT_ARROW}, + }, + { + {.width = 3, .icon = NULL, .key = "Ctrl", .value = HID_KEYBOARD_L_CTRL}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_CTRL}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_CTRL}, + {.width = 3, .icon = NULL, .key = "Alt", .value = HID_KEYBOARD_L_ALT}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_ALT}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_ALT}, + {.width = 3, .icon = NULL, .key = "Gui", .value = HID_KEYBOARD_L_GUI}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_GUI}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_GUI}, + {.width = 3, .icon = NULL, .key = "Tab", .value = HID_KEYBOARD_TAB}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_TAB}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_TAB}, + }, +}; +static void bt_hid_keyboard_to_upper(char* str) { + while(*str) { + *str = toupper((unsigned char)*str); + str++; + } +} +char keyString[5]; +static void bt_hid_keyboard_draw_key( + Canvas* canvas, + BtHidKeyboardModel* model, + uint8_t x, + uint8_t y, + BtHidKeyboardKey key, + bool selected) { + if(!key.width) return; + + canvas_set_color(canvas, ColorBlack); + uint8_t keyWidth = KEY_WIDTH * key.width + KEY_PADDING * (key.width - 1); + if(selected) { + // Draw a filled box + elements_slightly_rounded_box( + canvas, + MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING), + MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING), + keyWidth, + KEY_HEIGHT); + canvas_set_color(canvas, ColorWhite); + } else { + // Draw a framed box + elements_slightly_rounded_frame( + canvas, + MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING), + MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING), + keyWidth, + KEY_HEIGHT); + } + if(key.icon != NULL) { + // Draw the icon centered on the button + canvas_draw_icon( + canvas, + MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING) + keyWidth / 2 - key.icon->width / 2, + MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING) + KEY_HEIGHT / 2 - key.icon->height / 2, + key.icon); + } else { + // If shift is toggled use the shift key when available + strcpy(keyString, (model->shift && key.shift_key != 0) ? key.shift_key : key.key); + // Upper case if ctrl or alt was toggled true + if((model->ctrl && key.value == HID_KEYBOARD_L_CTRL) || + (model->alt && key.value == HID_KEYBOARD_L_ALT) || + (model->gui && key.value == HID_KEYBOARD_L_GUI)) { + bt_hid_keyboard_to_upper(keyString); + } + canvas_draw_str_aligned( + canvas, + MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING) + keyWidth / 2 + 1, + MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING) + KEY_HEIGHT / 2, + AlignCenter, + AlignCenter, + keyString); + } +} + +static void bt_hid_keyboard_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); + BtHidKeyboardModel* model = context; + + // Header + if(!model->connected) { + canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Keyboard"); + elements_multiline_text_aligned( + canvas, 4, 60, AlignLeft, AlignBottom, "Waiting for Connection..."); + return; // Dont render the keyboard if we are not yet connected + } + + canvas_set_font(canvas, FontKeyboard); + // Start shifting the all keys up if on the next row (Scrolling) + uint8_t initY = model->y - 4 > 0 ? model->y - 4 : 0; + for(uint8_t y = initY; y < ROW_COUNT; y++) { + BtHidKeyboardKey* keyboardKeyRow = keyboardKeySet[y]; + uint8_t x = 0; + for(uint8_t i = 0; i < COLUMN_COUNT; i++) { + BtHidKeyboardKey key = keyboardKeyRow[i]; + // Select when the button is hovered + // Select if the button is hovered within its width + // Select if back is clicked and its the backspace key + // Deselect when the button clicked or not hovered + bool keySelected = (x <= model->x && model->x < (x + key.width)) && y == model->y; + bool backSelected = model->back_pressed && key.value == HID_KEYBOARD_DELETE; + bt_hid_keyboard_draw_key( + canvas, + model, + x, + y - initY, + key, + (!model->ok_pressed && keySelected) || backSelected); + x += key.width; + } + } +} +static uint8_t bt_hid_keyboard_get_selected_key(BtHidKeyboardModel* model, InputType type) { + BtHidKeyboardKey key = keyboardKeySet[model->y][model->x]; + // Use upper case if shift is toggled or its a long press + bool useUppercase = (model->shift || type == InputTypeLong); + // Check if the key has an upper case version + bool hasUppercase = key.shift_key != 0; + if(useUppercase && hasUppercase) + return key.value; + else + return key.value; +} +static void bt_hid_keyboard_get_select_key(BtHidKeyboardModel* model, BtHidKeyboardPoint delta) { + // Keep going until a valid spot is found, this allows for nulls and zero width keys in the map + do { + if(((int8_t)model->y) + delta.y < 0) + model->y = ROW_COUNT - 1; + else + model->y = (model->y + delta.y) % ROW_COUNT; + } while(delta.y != 0 && keyboardKeySet[model->y][model->x].value == 0); + + do { + if(((int8_t)model->x) + delta.x < 0) + model->x = COLUMN_COUNT - 1; + else + model->x = (model->x + delta.x) % COLUMN_COUNT; + } while(delta.x != 0 && keyboardKeySet[model->y][model->x].width == + 0); // Skip zero width keys, pretend they are one key +} + +static void bt_hid_keyboard_process(BtHidKeyboard* bt_hid_keyboard, InputEvent* event) { + with_view_model( + bt_hid_keyboard->view, (BtHidKeyboardModel * model) { + if(event->key == InputKeyOk) { + if(event->type == InputTypePress) { + model->ok_pressed = true; + } else if(event->type == InputTypeLong || event->type == InputTypeShort) { + // Long press will allow for a shift modifier to be included + model->last_key_code = bt_hid_keyboard_get_selected_key(model, event->type); + + // Toggle the modifier key when clicked, and click the key + if(model->last_key_code == HID_KEYBOARD_L_SHIFT) { + model->shift = !model->shift; + if(model->shift) + model->modifier_code |= HID_KB_MOD_L_SHIFT; + else + model->modifier_code &= ~HID_KB_MOD_L_SHIFT; + } else if(model->last_key_code == HID_KEYBOARD_L_ALT) { + model->alt = !model->alt; + if(model->alt) + model->modifier_code |= HID_KB_MOD_L_ALT; + else + model->modifier_code &= ~HID_KB_MOD_L_ALT; + } else if(model->last_key_code == HID_KEYBOARD_L_CTRL) { + model->ctrl = !model->ctrl; + if(model->ctrl) + model->modifier_code |= HID_KB_MOD_L_CTRL; + else + model->modifier_code &= ~HID_KB_MOD_L_CTRL; + } else if(model->last_key_code == HID_KEYBOARD_L_GUI) { + model->gui = !model->gui; + if(model->gui) + model->modifier_code |= HID_KB_MOD_L_GUI; + else + model->modifier_code &= ~HID_KB_MOD_L_GUI; + } + furi_hal_bt_hid_kb_press( + ((model->modifier_code << 8) & 0XFF00) | model->last_key_code); + } else if(event->type == InputTypeRelease) { + // Release happens after short and long presses + furi_hal_bt_hid_kb_release( + ((model->modifier_code << 8) & 0XFF00) | model->last_key_code); + model->ok_pressed = false; + } + } else if(event->key == InputKeyBack) { + // If back is pressed for a short time, backspace + if(event->type == InputTypePress) { + model->back_pressed = true; + } else if(event->type == InputTypeShort) { + furi_hal_bt_hid_kb_press(HID_KEYBOARD_DELETE); + furi_hal_bt_hid_kb_release(HID_KEYBOARD_DELETE); + } else if(event->type == InputTypeRelease) { + model->back_pressed = false; + } + } else if(event->type == InputTypePress || event->type == InputTypeRepeat) { + // Cycle the selected keys + if(event->key == InputKeyUp) { + bt_hid_keyboard_get_select_key(model, (BtHidKeyboardPoint){.x = 0, .y = -1}); + } else if(event->key == InputKeyDown) { + bt_hid_keyboard_get_select_key(model, (BtHidKeyboardPoint){.x = 0, .y = 1}); + } else if(event->key == InputKeyLeft) { + bt_hid_keyboard_get_select_key(model, (BtHidKeyboardPoint){.x = -1, .y = 0}); + } else if(event->key == InputKeyRight) { + bt_hid_keyboard_get_select_key(model, (BtHidKeyboardPoint){.x = 1, .y = 0}); + } + } + return true; + }); +} + +static bool bt_hid_keyboard_input_callback(InputEvent* event, void* context) { + furi_assert(context); + BtHidKeyboard* bt_hid_keyboard = context; + bool consumed = false; + + if(event->type == InputTypeLong && event->key == InputKeyBack) { + furi_hal_bt_hid_kb_release_all(); + } else { + bt_hid_keyboard_process(bt_hid_keyboard, event); + consumed = true; + } + + return consumed; +} + +BtHidKeyboard* bt_hid_keyboard_alloc() { + BtHidKeyboard* bt_hid_keyboard = malloc(sizeof(BtHidKeyboard)); + bt_hid_keyboard->view = view_alloc(); + view_set_context(bt_hid_keyboard->view, bt_hid_keyboard); + view_allocate_model(bt_hid_keyboard->view, ViewModelTypeLocking, sizeof(BtHidKeyboardModel)); + view_set_draw_callback(bt_hid_keyboard->view, bt_hid_keyboard_draw_callback); + view_set_input_callback(bt_hid_keyboard->view, bt_hid_keyboard_input_callback); + + return bt_hid_keyboard; +} + +void bt_hid_keyboard_free(BtHidKeyboard* bt_hid_keyboard) { + furi_assert(bt_hid_keyboard); + view_free(bt_hid_keyboard->view); + free(bt_hid_keyboard); +} + +View* bt_hid_keyboard_get_view(BtHidKeyboard* bt_hid_keyboard) { + furi_assert(bt_hid_keyboard); + return bt_hid_keyboard->view; +} + +void bt_hid_keyboard_set_connected_status(BtHidKeyboard* bt_hid_keyboard, bool connected) { + furi_assert(bt_hid_keyboard); + with_view_model( + bt_hid_keyboard->view, (BtHidKeyboardModel * model) { + model->connected = connected; + return true; + }); +} diff --git a/applications/bt/bt_hid_app/views/bt_hid_keyboard.h b/applications/bt/bt_hid_app/views/bt_hid_keyboard.h new file mode 100644 index 00000000000..b2cc928e2a9 --- /dev/null +++ b/applications/bt/bt_hid_app/views/bt_hid_keyboard.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +typedef struct BtHidKeyboard BtHidKeyboard; + +BtHidKeyboard* bt_hid_keyboard_alloc(); + +void bt_hid_keyboard_free(BtHidKeyboard* bt_hid_keyboard); + +View* bt_hid_keyboard_get_view(BtHidKeyboard* bt_hid_keyboard); + +void bt_hid_keyboard_set_connected_status(BtHidKeyboard* bt_hid_keyboard, bool connected); diff --git a/applications/bt/bt_hid_app/views/bt_hid_keynote.c b/applications/bt/bt_hid_app/views/bt_hid_keynote.c index c4225227ad2..1ff23aa8493 100755 --- a/applications/bt/bt_hid_app/views/bt_hid_keynote.c +++ b/applications/bt/bt_hid_app/views/bt_hid_keynote.c @@ -14,6 +14,7 @@ typedef struct { bool right_pressed; bool down_pressed; bool ok_pressed; + bool back_pressed; bool connected; } BtHidKeynoteModel; @@ -35,106 +36,119 @@ static void bt_hid_keynote_draw_callback(Canvas* canvas, void* context) { BtHidKeynoteModel* model = context; // Header - canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned(canvas, 9, 3, AlignLeft, AlignTop, "Keynote"); - canvas_set_font(canvas, FontSecondary); - - // Connected status if(model->connected) { - canvas_draw_icon(canvas, 18, 18, &I_Ble_connected_38x34); - elements_multiline_text_aligned(canvas, 9, 60, AlignLeft, AlignBottom, "Connected"); + canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); } else { - canvas_draw_icon(canvas, 18, 18, &I_Ble_disconnected_24x34); - elements_multiline_text_aligned(canvas, 3, 60, AlignLeft, AlignBottom, "Disconnected"); + canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); } + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Keynote"); + canvas_set_font(canvas, FontSecondary); // Up - canvas_draw_icon(canvas, 86, 4, &I_Button_18x18); + canvas_draw_icon(canvas, 21, 24, &I_Button_18x18); if(model->up_pressed) { - elements_slightly_rounded_box(canvas, 89, 6, 13, 13); + elements_slightly_rounded_box(canvas, 24, 26, 13, 13); canvas_set_color(canvas, ColorWhite); } - bt_hid_keynote_draw_arrow(canvas, 95, 10, CanvasDirectionBottomToTop); + bt_hid_keynote_draw_arrow(canvas, 30, 30, CanvasDirectionBottomToTop); canvas_set_color(canvas, ColorBlack); // Down - canvas_draw_icon(canvas, 86, 25, &I_Button_18x18); + canvas_draw_icon(canvas, 21, 45, &I_Button_18x18); if(model->down_pressed) { - elements_slightly_rounded_box(canvas, 89, 27, 13, 13); + elements_slightly_rounded_box(canvas, 24, 47, 13, 13); canvas_set_color(canvas, ColorWhite); } - bt_hid_keynote_draw_arrow(canvas, 95, 35, CanvasDirectionTopToBottom); + bt_hid_keynote_draw_arrow(canvas, 30, 55, CanvasDirectionTopToBottom); canvas_set_color(canvas, ColorBlack); // Left - canvas_draw_icon(canvas, 65, 25, &I_Button_18x18); + canvas_draw_icon(canvas, 0, 45, &I_Button_18x18); if(model->left_pressed) { - elements_slightly_rounded_box(canvas, 68, 27, 13, 13); + elements_slightly_rounded_box(canvas, 3, 47, 13, 13); canvas_set_color(canvas, ColorWhite); } - bt_hid_keynote_draw_arrow(canvas, 72, 33, CanvasDirectionRightToLeft); + bt_hid_keynote_draw_arrow(canvas, 7, 53, CanvasDirectionRightToLeft); canvas_set_color(canvas, ColorBlack); // Right - canvas_draw_icon(canvas, 107, 25, &I_Button_18x18); + canvas_draw_icon(canvas, 42, 45, &I_Button_18x18); if(model->right_pressed) { - elements_slightly_rounded_box(canvas, 110, 27, 13, 13); + elements_slightly_rounded_box(canvas, 65, 47, 13, 13); canvas_set_color(canvas, ColorWhite); } - bt_hid_keynote_draw_arrow(canvas, 118, 33, CanvasDirectionLeftToRight); + bt_hid_keynote_draw_arrow(canvas, 53, 53, CanvasDirectionLeftToRight); canvas_set_color(canvas, ColorBlack); // Ok - canvas_draw_icon(canvas, 63, 45, &I_Space_65x18); + canvas_draw_icon(canvas, 63, 25, &I_Space_65x18); if(model->ok_pressed) { - elements_slightly_rounded_box(canvas, 66, 47, 60, 13); + elements_slightly_rounded_box(canvas, 66, 27, 60, 13); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 74, 49, &I_Ok_btn_9x9); - elements_multiline_text_aligned(canvas, 91, 56, AlignLeft, AlignBottom, "Space"); -} + canvas_draw_icon(canvas, 74, 29, &I_Ok_btn_9x9); + elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Space"); + canvas_set_color(canvas, ColorBlack); -static void bt_hid_keynote_process_press(BtHidKeynote* bt_hid_keynote, InputEvent* event) { - with_view_model( - bt_hid_keynote->view, (BtHidKeynoteModel * model) { - if(event->key == InputKeyUp) { - model->up_pressed = true; - furi_hal_bt_hid_kb_press(KEY_UP_ARROW); - } else if(event->key == InputKeyDown) { - model->down_pressed = true; - furi_hal_bt_hid_kb_press(KEY_DOWN_ARROW); - } else if(event->key == InputKeyLeft) { - model->left_pressed = true; - furi_hal_bt_hid_kb_press(KEY_LEFT_ARROW); - } else if(event->key == InputKeyRight) { - model->right_pressed = true; - furi_hal_bt_hid_kb_press(KEY_RIGHT_ARROW); - } else if(event->key == InputKeyOk) { - model->ok_pressed = true; - furi_hal_bt_hid_kb_press(KEY_SPACE); - } - return true; - }); + // Back + canvas_draw_icon(canvas, 63, 45, &I_Space_65x18); + if(model->back_pressed) { + elements_slightly_rounded_box(canvas, 66, 47, 60, 13); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 110, 49, &I_Ok_btn_9x9); + elements_multiline_text_aligned(canvas, 76, 56, AlignLeft, AlignBottom, "Back"); } -static void bt_hid_keynote_process_release(BtHidKeynote* bt_hid_keynote, InputEvent* event) { +static void bt_hid_keynote_process(BtHidKeynote* bt_hid_keynote, InputEvent* event) { with_view_model( bt_hid_keynote->view, (BtHidKeynoteModel * model) { - if(event->key == InputKeyUp) { - model->up_pressed = false; - furi_hal_bt_hid_kb_release(KEY_UP_ARROW); - } else if(event->key == InputKeyDown) { - model->down_pressed = false; - furi_hal_bt_hid_kb_release(KEY_DOWN_ARROW); - } else if(event->key == InputKeyLeft) { - model->left_pressed = false; - furi_hal_bt_hid_kb_release(KEY_LEFT_ARROW); - } else if(event->key == InputKeyRight) { - model->right_pressed = false; - furi_hal_bt_hid_kb_release(KEY_RIGHT_ARROW); - } else if(event->key == InputKeyOk) { - model->ok_pressed = false; - furi_hal_bt_hid_kb_release(KEY_SPACE); + if(event->type == InputTypePress) { + if(event->key == InputKeyUp) { + model->up_pressed = true; + furi_hal_bt_hid_kb_press(HID_KEYBOARD_UP_ARROW); + } else if(event->key == InputKeyDown) { + model->down_pressed = true; + furi_hal_bt_hid_kb_press(HID_KEYBOARD_DOWN_ARROW); + } else if(event->key == InputKeyLeft) { + model->left_pressed = true; + furi_hal_bt_hid_kb_press(HID_KEYBOARD_LEFT_ARROW); + } else if(event->key == InputKeyRight) { + model->right_pressed = true; + furi_hal_bt_hid_kb_press(HID_KEYBOARD_RIGHT_ARROW); + } else if(event->key == InputKeyOk) { + model->ok_pressed = true; + furi_hal_bt_hid_kb_press(HID_KEYBOARD_SPACEBAR); + } else if(event->key == InputKeyBack) { + model->back_pressed = true; + } + } else if(event->type == InputTypeRelease) { + if(event->key == InputKeyUp) { + model->up_pressed = false; + furi_hal_bt_hid_kb_release(HID_KEYBOARD_UP_ARROW); + } else if(event->key == InputKeyDown) { + model->down_pressed = false; + furi_hal_bt_hid_kb_release(HID_KEYBOARD_DOWN_ARROW); + } else if(event->key == InputKeyLeft) { + model->left_pressed = false; + furi_hal_bt_hid_kb_release(HID_KEYBOARD_LEFT_ARROW); + } else if(event->key == InputKeyRight) { + model->right_pressed = false; + furi_hal_bt_hid_kb_release(HID_KEYBOARD_RIGHT_ARROW); + } else if(event->key == InputKeyOk) { + model->ok_pressed = false; + furi_hal_bt_hid_kb_release(HID_KEYBOARD_SPACEBAR); + } else if(event->key == InputKeyBack) { + model->back_pressed = false; + } + } else if(event->type == InputTypeShort) { + if(event->key == InputKeyBack) { + furi_hal_bt_hid_kb_press(HID_KEYBOARD_DELETE); + furi_hal_bt_hid_kb_release(HID_KEYBOARD_DELETE); + furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_AC_BACK); + furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_AC_BACK); + } } return true; }); @@ -145,16 +159,11 @@ static bool bt_hid_keynote_input_callback(InputEvent* event, void* context) { BtHidKeynote* bt_hid_keynote = context; bool consumed = false; - if(event->type == InputTypePress) { - bt_hid_keynote_process_press(bt_hid_keynote, event); - consumed = true; - } else if(event->type == InputTypeRelease) { - bt_hid_keynote_process_release(bt_hid_keynote, event); + if(event->type == InputTypeLong && event->key == InputKeyBack) { + furi_hal_bt_hid_kb_release_all(); + } else { + bt_hid_keynote_process(bt_hid_keynote, event); consumed = true; - } else if(event->type == InputTypeShort) { - if(event->key == InputKeyBack) { - furi_hal_hid_kb_release_all(); - } } return consumed; diff --git a/applications/bt/bt_hid_app/views/bt_hid_media.c b/applications/bt/bt_hid_app/views/bt_hid_media.c index 695ce3c36da..b384f47cf18 100755 --- a/applications/bt/bt_hid_app/views/bt_hid_media.c +++ b/applications/bt/bt_hid_app/views/bt_hid_media.c @@ -35,18 +35,14 @@ static void bt_hid_media_draw_callback(Canvas* canvas, void* context) { BtHidMediaModel* model = context; // Header - canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned(canvas, 9, 3, AlignLeft, AlignTop, "Media player"); - canvas_set_font(canvas, FontSecondary); - - // Connected status if(model->connected) { - canvas_draw_icon(canvas, 23, 17, &I_Ble_connected_38x34); - elements_multiline_text_aligned(canvas, 35, 61, AlignCenter, AlignBottom, "Connected"); + canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); } else { - canvas_draw_icon(canvas, 23, 17, &I_Ble_disconnected_24x34); - elements_multiline_text_aligned(canvas, 35, 61, AlignCenter, AlignBottom, "Disconnected"); + canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); } + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Media"); + canvas_set_font(canvas, FontSecondary); // Keypad circles canvas_draw_icon(canvas, 76, 8, &I_Circles_47x47); @@ -100,19 +96,19 @@ static void bt_hid_media_process_press(BtHidMedia* bt_hid_media, InputEvent* eve bt_hid_media->view, (BtHidMediaModel * model) { if(event->key == InputKeyUp) { model->up_pressed = true; - furi_hal_bt_hid_media_press(FuriHalBtHidMediaVolumeUp); + furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_VOLUME_INCREMENT); } else if(event->key == InputKeyDown) { model->down_pressed = true; - furi_hal_bt_hid_media_press(FuriHalBtHidMediaVolumeDown); + furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_VOLUME_DECREMENT); } else if(event->key == InputKeyLeft) { model->left_pressed = true; - furi_hal_bt_hid_media_press(FuriHalBtHidMediaScanPrevious); + furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_SCAN_PREVIOUS_TRACK); } else if(event->key == InputKeyRight) { model->right_pressed = true; - furi_hal_bt_hid_media_press(FuriHalBtHidMediaScanNext); + furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_SCAN_NEXT_TRACK); } else if(event->key == InputKeyOk) { model->ok_pressed = true; - furi_hal_bt_hid_media_press(FuriHalBtHidMediaPlayPause); + furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_PLAY_PAUSE); } return true; }); @@ -123,19 +119,19 @@ static void bt_hid_media_process_release(BtHidMedia* bt_hid_media, InputEvent* e bt_hid_media->view, (BtHidMediaModel * model) { if(event->key == InputKeyUp) { model->up_pressed = false; - furi_hal_bt_hid_media_release(FuriHalBtHidMediaVolumeUp); + furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_VOLUME_INCREMENT); } else if(event->key == InputKeyDown) { model->down_pressed = false; - furi_hal_bt_hid_media_release(FuriHalBtHidMediaVolumeDown); + furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_VOLUME_DECREMENT); } else if(event->key == InputKeyLeft) { model->left_pressed = false; - furi_hal_bt_hid_media_release(FuriHalBtHidMediaScanPrevious); + furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_SCAN_PREVIOUS_TRACK); } else if(event->key == InputKeyRight) { model->right_pressed = false; - furi_hal_bt_hid_media_release(FuriHalBtHidMediaScanNext); + furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_SCAN_NEXT_TRACK); } else if(event->key == InputKeyOk) { model->ok_pressed = false; - furi_hal_bt_hid_media_release(FuriHalBtHidMediaPlayPause); + furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_PLAY_PAUSE); } return true; }); @@ -154,7 +150,7 @@ static bool bt_hid_media_input_callback(InputEvent* event, void* context) { consumed = true; } else if(event->type == InputTypeShort) { if(event->key == InputKeyBack) { - furi_hal_bt_hid_media_release_all(); + furi_hal_bt_hid_consumer_key_release_all(); } } diff --git a/applications/bt/bt_hid_app/views/bt_hid_mouse.c b/applications/bt/bt_hid_app/views/bt_hid_mouse.c new file mode 100644 index 00000000000..fb1537a2c9d --- /dev/null +++ b/applications/bt/bt_hid_app/views/bt_hid_mouse.c @@ -0,0 +1,207 @@ +#include "bt_hid_mouse.h" +#include +#include +#include +#include + +struct BtHidMouse { + View* view; +}; +#define MOUSE_MOVE_SHORT 5 +#define MOUSE_MOVE_LONG 20 + +typedef struct { + bool left_pressed; + bool up_pressed; + bool right_pressed; + bool down_pressed; + bool left_mouse_pressed; + bool left_mouse_held; + bool right_mouse_pressed; + bool connected; +} BtHidMouseModel; + +static void bt_hid_mouse_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); + BtHidMouseModel* model = context; + + // Header + if(model->connected) { + canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); + } else { + canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); + } + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Mouse"); + canvas_set_font(canvas, FontSecondary); + + if(model->left_mouse_held == true) { + elements_multiline_text_aligned(canvas, 0, 60, AlignLeft, AlignBottom, "Selecting..."); + } + + // Keypad circles + canvas_draw_icon(canvas, 64, 8, &I_Circles_47x47); + + // Up + if(model->up_pressed) { + canvas_draw_icon(canvas, 81, 9, &I_Pressed_Button_13x13); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 84, 10, &I_Pin_arrow_up7x9); + canvas_set_color(canvas, ColorBlack); + + // Down + if(model->down_pressed) { + canvas_draw_icon(canvas, 81, 41, &I_Pressed_Button_13x13); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 84, 43, &I_Pin_arrow_down_7x9); + canvas_set_color(canvas, ColorBlack); + + // Left + if(model->left_pressed) { + canvas_draw_icon(canvas, 65, 25, &I_Pressed_Button_13x13); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 67, 28, &I_Pin_arrow_left_9x7); + canvas_set_color(canvas, ColorBlack); + + // Right + if(model->right_pressed) { + canvas_draw_icon(canvas, 97, 25, &I_Pressed_Button_13x13); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 99, 28, &I_Pin_arrow_right_9x7); + canvas_set_color(canvas, ColorBlack); + + // Ok + if(model->left_mouse_pressed) { + canvas_draw_icon(canvas, 81, 25, &I_Pressed_Button_13x13); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 83, 27, &I_Ok_btn_9x9); + canvas_set_color(canvas, ColorBlack); + + // Back + if(model->right_mouse_pressed) { + canvas_draw_icon(canvas, 108, 48, &I_Pressed_Button_13x13); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 110, 50, &I_Ok_btn_9x9); +} + +static void bt_hid_mouse_process(BtHidMouse* bt_hid_mouse, InputEvent* event) { + with_view_model( + bt_hid_mouse->view, (BtHidMouseModel * model) { + if(event->key == InputKeyBack) { + if(event->type == InputTypeShort) { + furi_hal_bt_hid_mouse_press(HID_MOUSE_BTN_RIGHT); + furi_hal_bt_hid_mouse_release(HID_MOUSE_BTN_RIGHT); + } else if(event->type == InputTypePress) { + model->right_mouse_pressed = true; + } else if(event->type == InputTypeRelease) { + model->right_mouse_pressed = false; + } + } else if(event->key == InputKeyOk) { + if(event->type == InputTypeShort) { + // Just release if it was being held before + if(!model->left_mouse_held) furi_hal_bt_hid_mouse_press(HID_MOUSE_BTN_LEFT); + furi_hal_bt_hid_mouse_release(HID_MOUSE_BTN_LEFT); + model->left_mouse_held = false; + } else if(event->type == InputTypeLong) { + furi_hal_bt_hid_mouse_press(HID_MOUSE_BTN_LEFT); + model->left_mouse_held = true; + model->left_mouse_pressed = true; + } else if(event->type == InputTypePress) { + model->left_mouse_pressed = true; + } else if(event->type == InputTypeRelease) { + // Only release if it wasn't a long press + if(!model->left_mouse_held) model->left_mouse_pressed = false; + } + + } else if(event->key == InputKeyRight) { + if(event->type == InputTypePress) { + model->right_pressed = true; + furi_hal_bt_hid_mouse_move(MOUSE_MOVE_SHORT, 0); + } else if(event->type == InputTypeRepeat) { + furi_hal_bt_hid_mouse_move(MOUSE_MOVE_LONG, 0); + } else if(event->type == InputTypeRelease) { + model->right_pressed = false; + } + } else if(event->key == InputKeyLeft) { + if(event->type == InputTypePress) { + model->left_pressed = true; + furi_hal_bt_hid_mouse_move(-MOUSE_MOVE_SHORT, 0); + } else if(event->type == InputTypeRepeat) { + furi_hal_bt_hid_mouse_move(-MOUSE_MOVE_LONG, 0); + } else if(event->type == InputTypeRelease) { + model->left_pressed = false; + } + } else if(event->key == InputKeyDown) { + if(event->type == InputTypePress) { + model->down_pressed = true; + furi_hal_bt_hid_mouse_move(0, MOUSE_MOVE_SHORT); + } else if(event->type == InputTypeRepeat) { + furi_hal_bt_hid_mouse_move(0, MOUSE_MOVE_LONG); + } else if(event->type == InputTypeRelease) { + model->down_pressed = false; + } + } else if(event->key == InputKeyUp) { + if(event->type == InputTypePress) { + model->up_pressed = true; + furi_hal_bt_hid_mouse_move(0, -MOUSE_MOVE_SHORT); + } else if(event->type == InputTypeRepeat) { + furi_hal_bt_hid_mouse_move(0, -MOUSE_MOVE_LONG); + } else if(event->type == InputTypeRelease) { + model->up_pressed = false; + } + } + return true; + }); +} + +static bool bt_hid_mouse_input_callback(InputEvent* event, void* context) { + furi_assert(context); + BtHidMouse* bt_hid_mouse = context; + bool consumed = false; + + if(event->type == InputTypeLong && event->key == InputKeyBack) { + furi_hal_bt_hid_mouse_release_all(); + } else { + bt_hid_mouse_process(bt_hid_mouse, event); + consumed = true; + } + + return consumed; +} + +BtHidMouse* bt_hid_mouse_alloc() { + BtHidMouse* bt_hid_mouse = malloc(sizeof(BtHidMouse)); + bt_hid_mouse->view = view_alloc(); + view_set_context(bt_hid_mouse->view, bt_hid_mouse); + view_allocate_model(bt_hid_mouse->view, ViewModelTypeLocking, sizeof(BtHidMouseModel)); + view_set_draw_callback(bt_hid_mouse->view, bt_hid_mouse_draw_callback); + view_set_input_callback(bt_hid_mouse->view, bt_hid_mouse_input_callback); + + return bt_hid_mouse; +} + +void bt_hid_mouse_free(BtHidMouse* bt_hid_mouse) { + furi_assert(bt_hid_mouse); + view_free(bt_hid_mouse->view); + free(bt_hid_mouse); +} + +View* bt_hid_mouse_get_view(BtHidMouse* bt_hid_mouse) { + furi_assert(bt_hid_mouse); + return bt_hid_mouse->view; +} + +void bt_hid_mouse_set_connected_status(BtHidMouse* bt_hid_mouse, bool connected) { + furi_assert(bt_hid_mouse); + with_view_model( + bt_hid_mouse->view, (BtHidMouseModel * model) { + model->connected = connected; + return true; + }); +} diff --git a/applications/bt/bt_hid_app/views/bt_hid_mouse.h b/applications/bt/bt_hid_app/views/bt_hid_mouse.h new file mode 100644 index 00000000000..a82971d7689 --- /dev/null +++ b/applications/bt/bt_hid_app/views/bt_hid_mouse.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +typedef struct BtHidMouse BtHidMouse; + +BtHidMouse* bt_hid_mouse_alloc(); + +void bt_hid_mouse_free(BtHidMouse* bt_hid_mouse); + +View* bt_hid_mouse_get_view(BtHidMouse* bt_hid_mouse); + +void bt_hid_mouse_set_connected_status(BtHidMouse* bt_hid_mouse, bool connected); diff --git a/assets/compiled/assets_icons.c b/assets/compiled/assets_icons.c index fb125095a6c..9346d07e6b3 100644 --- a/assets/compiled/assets_icons.c +++ b/assets/compiled/assets_icons.c @@ -79,9 +79,15 @@ const uint8_t* const _I_update_10px[] = {_I_update_10px_0}; const uint8_t _I_BLE_Pairing_128x64_0[] = {0x01,0x00,0xb7,0x01,0x00,0x6c,0x38,0x1f,0xd0,0x10,0x76,0xe0,0x03,0xdd,0x40,0x07,0xf4,0x82,0x01,0x08,0x07,0xf4,0xc0,0x1f,0x91,0x08,0x07,0x00,0x1f,0xc0,0x0d,0x1e,0xe8,0x3f,0xc0,0x03,0x58,0x80,0xcf,0x11,0xd9,0xaf,0x85,0x77,0x01,0xf7,0x60,0xf8,0x45,0xff,0x05,0xed,0x9e,0x7c,0x09,0xdb,0xe0,0x2f,0x78,0x03,0x3c,0x8e,0xee,0x8a,0x43,0x81,0xfb,0x0c,0x66,0xe8,0xfc,0x59,0xba,0x6f,0x28,0x1b,0xfb,0xa3,0x80,0xfc,0xa0,0x1f,0xc6,0x86,0xbf,0xc3,0x78,0xce,0x04,0x19,0x26,0x77,0xfa,0x43,0xbe,0x12,0xa0,0x7e,0xf8,0x2a,0xa2,0x02,0xff,0x89,0x27,0x01,0xbf,0x99,0x38,0x8a,0xfc,0x0f,0x8e,0x07,0xfe,0x0e,0x94,0x2c,0x07,0xfc,0x7f,0x1f,0xf5,0x00,0xc3,0x00,0xe4,0x31,0x13,0xd1,0x00,0x0a,0xb8,0x19,0x25,0x91,0xc0,0x81,0xe2,0xb9,0x4d,0x5d,0x78,0x64,0x2e,0x84,0x80,0x61,0x07,0x02,0x3e,0x2a,0xa4,0xa2,0x00,0xf2,0x40,0x20,0xe3,0x21,0xa0,0x62,0x9f,0x60,0x05,0x02,0x3e,0x36,0x41,0x66,0x23,0x20,0x51,0xfc,0x40,0x68,0x0f,0x15,0x90,0x60,0x20,0x1b,0x09,0x89,0x70,0x46,0x42,0x07,0x14,0x99,0x41,0xe8,0x1f,0x18,0x0c,0x07,0xc1,0x19,0xff,0xc3,0xce,0x6b,0x54,0x8f,0xe0,0x3f,0x90,0x78,0x17,0x02,0x1a,0x70,0x39,0x01,0xa0,0xb1,0x53,0xb5,0x88,0xc7,0xe0,0x98,0x08,0x3a,0xd5,0xe8,0x97,0xd0,0x78,0xcf,0xe1,0x07,0xf1,0x0d,0x08,0x00,0x74,0x10,0x80,0x18,0xe8,0x97,0xc3,0xf2,0xff,0xc4,0x03,0xe3,0x04,0x8c,0x19,0xcc,0x00,0x35,0x0c,0x3c,0x03,0xf9,0x3f,0xb0,0x8f,0xc6,0x31,0x0e,0x0f,0x90,0x90,0xb5,0x45,0xc1,0xf8,0x4f,0xf0,0xde,0x18,0xcc,0x82,0x08,0x1f,0x22,0x20,0xd0,0x3a,0xab,0xd1,0xe0,0x5f,0xa1,0x1b,0x19,0x8d,0x02,0x04,0x9a,0x1d,0x04,0x28,0x26,0x36,0xa8,0x05,0xf0,0xe0,0x3f,0x04,0xf8,0xd0,0x30,0x55,0xfa,0xad,0x54,0x3e,0x35,0x09,0xab,0xac,0xbf,0x2b,0xf2,0x0a,0x0e,0xfb,0x55,0xaa,0x0f,0x94,0x68,0x04,0x30,0x6f,0xd3,0x7c,0xb0,0x15,0x0f,0xfd,0x7f,0xeb,0x05,0x4f,0x0b,0x60,0xa3,0x1f,0x28,0x0b,0xfc,0xbc,0x30,0x1f,0xf7,0xfe,0x54,0x2c,0x18,0x30,0x3c,0x6f,0x00,0xf2,0x1c,0x8c,0xf8,0x10,0x3c,0x00,0xf8,0xd5,0x5c,0x05,0xb8,0xb0,0xaa,0xdb,0x01,0x2b,0x31,0x0a,0xdc,0xa7,0x00,0xe6,0x00,0x0c,0x56,0x00,0x7e,0x10,0x00,0xcc,0x01,0xf0,0x1f,0x1b,0x40,0x2e,0x00,0x07,0x16,0x10,0x90,0x02,0xe5,0x90,0x06,0x29,0x00,0x2a,0xa9,0x00,0x2f,0x10,0x02,0xa5,0x10,0x02,0xf1,0x00,0x2a,0xa0,0x0d,0xc0,0x00,0xec,0x01,0xfd,0x60,0x17,0x6a,0xc0,0x60,0x40,0xfd,0xc0,0x30,0x04,0x01,0xb0,0xb0,0x7f,0x45,0x80,}; const uint8_t* const _I_BLE_Pairing_128x64[] = {_I_BLE_Pairing_128x64_0}; +const uint8_t _I_Ble_connected_15x15_0[] = {0x00,0xE0,0x03,0xF8,0x0F,0x7C,0x1F,0x7E,0x3E,0x5E,0x3D,0x5F,0x7B,0x3F,0x7D,0x7F,0x7E,0x3F,0x7D,0x5F,0x7B,0x5E,0x3D,0x7E,0x3E,0x7C,0x1F,0xF8,0x0F,0xE0,0x03,}; +const uint8_t* const _I_Ble_connected_15x15[] = {_I_Ble_connected_15x15_0}; + const uint8_t _I_Ble_connected_38x34_0[] = {0x01,0x00,0x60,0x00,0x80,0x7f,0xc0,0x65,0xc0,0xff,0xc0,0xc0,0x83,0xf0,0xff,0xc3,0xc0,0x83,0xf8,0xff,0xc7,0xc0,0x83,0xfc,0xff,0xcf,0xc0,0x8d,0xfe,0xf9,0xdf,0xe0,0x10,0x30,0x21,0xc1,0xff,0xfc,0x31,0x40,0xc3,0x80,0x87,0x0c,0xff,0xcc,0xc0,0x83,0x1c,0x02,0x1c,0x62,0x7f,0xf3,0xfe,0x4c,0x27,0x00,0x42,0xb8,0x4e,0x3f,0xf3,0x0f,0xff,0x80,0x04,0x20,0x11,0xe0,0x00,0x84,0x44,0x20,0x47,0x07,0x20,0x60,0xc4,0x48,0x2c,0x41,0xb2,0x10,0x14,0x94,0x85,0x43,0x2f,0x21,0xa1,0x0e,0xf2,0x86,0x44,0x82,0x26,0x91,0x48,0x80,}; const uint8_t* const _I_Ble_connected_38x34[] = {_I_Ble_connected_38x34_0}; +const uint8_t _I_Ble_disconnected_15x15_0[] = {0x00,0xE0,0x03,0x18,0x0C,0x84,0x10,0x82,0x21,0xA2,0x22,0xA1,0x44,0xC1,0x42,0x81,0x41,0xC1,0x42,0xA1,0x44,0xA2,0x22,0x82,0x21,0x84,0x10,0x18,0x0C,0xE0,0x03,}; +const uint8_t* const _I_Ble_disconnected_15x15[] = {_I_Ble_disconnected_15x15_0}; + const uint8_t _I_Ble_disconnected_24x34_0[] = {0x01,0x00,0x3c,0x00,0x80,0x7f,0xe0,0x1c,0x08,0x04,0x0e,0x61,0x00,0x86,0x42,0x20,0x11,0x08,0x24,0x02,0x40,0x02,0x28,0x14,0x32,0x80,0x02,0x28,0x0c,0xf3,0x00,0x02,0x3e,0x60,0x08,0xf8,0x30,0xcc,0x18,0x08,0xa0,0x3c,0xf0,0x58,0x80,0x88,0x2e,0xa0,0xb4,0x0b,0xb0,0x8d,0x02,0xea,0x3b,0x52,0x3a,0x94,0x08,0xac,0x45,0xc2,0x31,0x10,}; const uint8_t* const _I_Ble_disconnected_24x34[] = {_I_Ble_disconnected_24x34_0}; @@ -670,7 +676,9 @@ const Icon I_u2f_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.fram const Icon I_unknown_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_unknown_10px}; const Icon I_update_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_update_10px}; const Icon I_BLE_Pairing_128x64 = {.width=128,.height=64,.frame_count=1,.frame_rate=0,.frames=_I_BLE_Pairing_128x64}; +const Icon I_Ble_connected_15x15 = {.width=15,.height=15,.frame_count=1,.frame_rate=0,.frames=_I_Ble_connected_15x15}; const Icon I_Ble_connected_38x34 = {.width=38,.height=34,.frame_count=1,.frame_rate=0,.frames=_I_Ble_connected_38x34}; +const Icon I_Ble_disconnected_15x15 = {.width=15,.height=15,.frame_count=1,.frame_rate=0,.frames=_I_Ble_disconnected_15x15}; const Icon I_Ble_disconnected_24x34 = {.width=24,.height=34,.frame_count=1,.frame_rate=0,.frames=_I_Ble_disconnected_24x34}; const Icon I_Button_18x18 = {.width=18,.height=18,.frame_count=1,.frame_rate=0,.frames=_I_Button_18x18}; const Icon I_Circles_47x47 = {.width=47,.height=47,.frame_count=1,.frame_rate=0,.frames=_I_Circles_47x47}; diff --git a/assets/compiled/assets_icons.h b/assets/compiled/assets_icons.h index 45947880287..d1d4294a552 100644 --- a/assets/compiled/assets_icons.h +++ b/assets/compiled/assets_icons.h @@ -20,7 +20,9 @@ extern const Icon I_u2f_10px; extern const Icon I_unknown_10px; extern const Icon I_update_10px; extern const Icon I_BLE_Pairing_128x64; +extern const Icon I_Ble_connected_15x15; extern const Icon I_Ble_connected_38x34; +extern const Icon I_Ble_disconnected_15x15; extern const Icon I_Ble_disconnected_24x34; extern const Icon I_Button_18x18; extern const Icon I_Circles_47x47; diff --git a/assets/icons/BLE/BLE_HID/Ble_connected_15x15.png b/assets/icons/BLE/BLE_HID/Ble_connected_15x15.png new file mode 100644 index 0000000000000000000000000000000000000000..58776828ed48a1c3a497755800660b79ea3b8137 GIT binary patch literal 177 zcmeAS@N?(olHy`uVBq!ia0vp^{2({Zh|P-#^I!>>dQMXri7U8|T@ zv7L;LDP~#8^={?X^Shd#k?^xXW6s* bch2Oog!)SEiB$UnbOVE@tDnm{r-UW|4(3Jx literal 0 HcmV?d00001 diff --git a/assets/icons/BLE/BLE_HID/Ble_disconnected_15x15.png b/assets/icons/BLE/BLE_HID/Ble_disconnected_15x15.png new file mode 100644 index 0000000000000000000000000000000000000000..bfc1e7d7f187d88125e1e4b4bb2367d5261359b4 GIT binary patch literal 178 zcmeAS@N?(olHy`uVBq!ia0vp^{220QW{FyL_7{J;KY zD!cHpBWd?U7^82mSk>g>lELXLt>-t(#MCds=m!JOCzjqq-I*4xa*eE?TmsDd?!?S> zc)obEnRW9-o?TaSjl7>-ye`fAx` literal 0 HcmV?d00001 diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt.c b/firmware/targets/f7/furi_hal/furi_hal_bt.c index c7ee7dc23e0..aa4e264ff24 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_bt.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt.c @@ -218,8 +218,8 @@ bool furi_hal_bt_start_app(FuriHalBtProfile profile, GapEventCallback event_cb, } else if(profile == FuriHalBtProfileHidKeyboard) { // Change MAC address for HID profile config->mac_address[2]++; - // Change name Flipper -> Keynote - const char* clicker_str = "Keynote"; + // Change name Flipper -> Control + const char* clicker_str = "Control"; memcpy(&config->adv_name[1], clicker_str, strlen(clicker_str)); } if(!gap_init(config, event_cb, context)) { From 534381f1b2ccff1ef54e5e7cbaf0cca1d12526da Mon Sep 17 00:00:00 2001 From: Cutch Date: Fri, 17 Jun 2022 14:10:55 -0400 Subject: [PATCH 04/12] BT Keyboard remove long press shift --- applications/bt/bt_hid_app/views/bt_hid_keyboard.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/applications/bt/bt_hid_app/views/bt_hid_keyboard.c b/applications/bt/bt_hid_app/views/bt_hid_keyboard.c index 86d90aef89c..1a8a10332ed 100644 --- a/applications/bt/bt_hid_app/views/bt_hid_keyboard.c +++ b/applications/bt/bt_hid_app/views/bt_hid_keyboard.c @@ -127,7 +127,7 @@ BtHidKeyboardKey keyboardKeySet[ROW_COUNT][COLUMN_COUNT] = { {.width = 3, .icon = NULL, .key = "Alt", .value = HID_KEYBOARD_L_ALT}, {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_ALT}, {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_ALT}, - {.width = 3, .icon = NULL, .key = "Gui", .value = HID_KEYBOARD_L_GUI}, + {.width = 3, .icon = NULL, .key = "Cmd", .value = HID_KEYBOARD_L_GUI}, {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_GUI}, {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_GUI}, {.width = 3, .icon = NULL, .key = "Tab", .value = HID_KEYBOARD_TAB}, @@ -236,10 +236,10 @@ static void bt_hid_keyboard_draw_callback(Canvas* canvas, void* context) { } } } -static uint8_t bt_hid_keyboard_get_selected_key(BtHidKeyboardModel* model, InputType type) { +static uint8_t bt_hid_keyboard_get_selected_key(BtHidKeyboardModel* model) { BtHidKeyboardKey key = keyboardKeySet[model->y][model->x]; - // Use upper case if shift is toggled or its a long press - bool useUppercase = (model->shift || type == InputTypeLong); + // Use upper case if shift is toggled + bool useUppercase = model->shift; // Check if the key has an upper case version bool hasUppercase = key.shift_key != 0; if(useUppercase && hasUppercase) @@ -272,8 +272,7 @@ static void bt_hid_keyboard_process(BtHidKeyboard* bt_hid_keyboard, InputEvent* if(event->type == InputTypePress) { model->ok_pressed = true; } else if(event->type == InputTypeLong || event->type == InputTypeShort) { - // Long press will allow for a shift modifier to be included - model->last_key_code = bt_hid_keyboard_get_selected_key(model, event->type); + model->last_key_code = bt_hid_keyboard_get_selected_key(model); // Toggle the modifier key when clicked, and click the key if(model->last_key_code == HID_KEYBOARD_L_SHIFT) { From 3d354126d259ed3cc0f8a89d5259967e66e214ff Mon Sep 17 00:00:00 2001 From: Cutch Date: Sat, 18 Jun 2022 00:22:14 -0400 Subject: [PATCH 05/12] Fix usb hid modifier keys --- applications/bad_usb/bad_usb_script.c | 22 ++-- .../bt/bt_hid_app/views/bt_hid_keyboard.c | 24 ++-- .../furi_hal_include/furi_hal_usb_hid.h | 118 +++++++++--------- 3 files changed, 81 insertions(+), 83 deletions(-) diff --git a/applications/bad_usb/bad_usb_script.c b/applications/bad_usb/bad_usb_script.c index 637a3422cbc..5558a189ee4 100644 --- a/applications/bad_usb/bad_usb_script.c +++ b/applications/bad_usb/bad_usb_script.c @@ -45,17 +45,17 @@ typedef struct { } DuckyKey; static const DuckyKey ducky_keys[] = { - {"CTRL-ALT", HID_KEYBOARD_L_CTRL | HID_KEYBOARD_L_ALT}, - {"CTRL-SHIFT", HID_KEYBOARD_L_CTRL | HID_KEYBOARD_L_SHIFT}, - {"ALT-SHIFT", HID_KEYBOARD_L_ALT | HID_KEYBOARD_L_SHIFT}, - {"ALT-GUI", HID_KEYBOARD_L_ALT | HID_KEYBOARD_L_GUI}, - - {"CTRL", HID_KEYBOARD_L_CTRL}, - {"CONTROL", HID_KEYBOARD_L_CTRL}, - {"SHIFT", HID_KEYBOARD_L_SHIFT}, - {"ALT", HID_KEYBOARD_L_ALT}, - {"GUI", HID_KEYBOARD_L_GUI}, - {"WINDOWS", HID_KEYBOARD_L_GUI}, + {"CTRL-ALT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_ALT}, + {"CTRL-SHIFT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT}, + {"ALT-SHIFT", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_SHIFT}, + {"ALT-GUI", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_GUI}, + + {"CTRL", KEY_MOD_LEFT_CTRL}, + {"CONTROL", KEY_MOD_LEFT_CTRL}, + {"SHIFT", KEY_MOD_LEFT_SHIFT}, + {"ALT", KEY_MOD_LEFT_ALT}, + {"GUI", KEY_MOD_LEFT_GUI}, + {"WINDOWS", KEY_MOD_LEFT_GUI}, {"DOWNARROW", HID_KEYBOARD_DOWN_ARROW}, {"DOWN", HID_KEYBOARD_DOWN_ARROW}, diff --git a/applications/bt/bt_hid_app/views/bt_hid_keyboard.c b/applications/bt/bt_hid_app/views/bt_hid_keyboard.c index 1a8a10332ed..825791d9871 100644 --- a/applications/bt/bt_hid_app/views/bt_hid_keyboard.c +++ b/applications/bt/bt_hid_app/views/bt_hid_keyboard.c @@ -17,7 +17,7 @@ typedef struct { uint8_t x; uint8_t y; uint8_t last_key_code; - uint8_t modifier_code; + uint16_t modifier_code; bool ok_pressed; bool back_pressed; bool connected; @@ -278,34 +278,32 @@ static void bt_hid_keyboard_process(BtHidKeyboard* bt_hid_keyboard, InputEvent* if(model->last_key_code == HID_KEYBOARD_L_SHIFT) { model->shift = !model->shift; if(model->shift) - model->modifier_code |= HID_KB_MOD_L_SHIFT; + model->modifier_code |= KEY_MOD_LEFT_SHIFT; else - model->modifier_code &= ~HID_KB_MOD_L_SHIFT; + model->modifier_code &= ~KEY_MOD_LEFT_SHIFT; } else if(model->last_key_code == HID_KEYBOARD_L_ALT) { model->alt = !model->alt; if(model->alt) - model->modifier_code |= HID_KB_MOD_L_ALT; + model->modifier_code |= KEY_MOD_LEFT_ALT; else - model->modifier_code &= ~HID_KB_MOD_L_ALT; + model->modifier_code &= ~KEY_MOD_LEFT_ALT; } else if(model->last_key_code == HID_KEYBOARD_L_CTRL) { model->ctrl = !model->ctrl; if(model->ctrl) - model->modifier_code |= HID_KB_MOD_L_CTRL; + model->modifier_code |= KEY_MOD_LEFT_CTRL; else - model->modifier_code &= ~HID_KB_MOD_L_CTRL; + model->modifier_code &= ~KEY_MOD_LEFT_CTRL; } else if(model->last_key_code == HID_KEYBOARD_L_GUI) { model->gui = !model->gui; if(model->gui) - model->modifier_code |= HID_KB_MOD_L_GUI; + model->modifier_code |= KEY_MOD_LEFT_GUI; else - model->modifier_code &= ~HID_KB_MOD_L_GUI; + model->modifier_code &= ~KEY_MOD_LEFT_GUI; } - furi_hal_bt_hid_kb_press( - ((model->modifier_code << 8) & 0XFF00) | model->last_key_code); + furi_hal_bt_hid_kb_press(model->modifier_code | model->last_key_code); } else if(event->type == InputTypeRelease) { // Release happens after short and long presses - furi_hal_bt_hid_kb_release( - ((model->modifier_code << 8) & 0XFF00) | model->last_key_code); + furi_hal_bt_hid_kb_release(model->modifier_code | model->last_key_code); model->ok_pressed = false; } } else if(event->key == InputKeyBack) { diff --git a/firmware/targets/furi_hal_include/furi_hal_usb_hid.h b/firmware/targets/furi_hal_include/furi_hal_usb_hid.h index 7438e8feb32..7fe2d8d1450 100644 --- a/firmware/targets/furi_hal_include/furi_hal_usb_hid.h +++ b/firmware/targets/furi_hal_include/furi_hal_usb_hid.h @@ -7,6 +7,18 @@ #define HID_KEYBOARD_NONE 0x00 +/** HID keyboard modifier keys */ +enum HidKeyboardMods { + KEY_MOD_LEFT_CTRL = (1 << 8), + KEY_MOD_LEFT_SHIFT = (1 << 9), + KEY_MOD_LEFT_ALT = (1 << 10), + KEY_MOD_LEFT_GUI = (1 << 11), + KEY_MOD_RIGHT_CTRL = (1 << 12), + KEY_MOD_RIGHT_SHIFT = (1 << 13), + KEY_MOD_RIGHT_ALT = (1 << 14), + KEY_MOD_RIGHT_GUI = (1 << 15), +}; + /** ASCII to keycode conversion table */ static const uint16_t hid_asciimap[] = { HID_KEYBOARD_NONE, // NUL @@ -42,17 +54,17 @@ static const uint16_t hid_asciimap[] = { HID_KEYBOARD_NONE, // RS HID_KEYBOARD_NONE, // US HID_KEYBOARD_SPACEBAR, // ' ' Space - HID_KEYBOARD_1 | HID_KEYBOARD_L_SHIFT, // ! - HID_KEYBOARD_APOSTROPHE | HID_KEYBOARD_L_SHIFT, // " - HID_KEYBOARD_3 | HID_KEYBOARD_L_SHIFT, // # - HID_KEYBOARD_4 | HID_KEYBOARD_L_SHIFT, // $ - HID_KEYBOARD_5 | HID_KEYBOARD_L_SHIFT, // % - HID_KEYBOARD_7 | HID_KEYBOARD_L_SHIFT, // & + HID_KEYBOARD_1 | KEY_MOD_LEFT_SHIFT, // ! + HID_KEYBOARD_APOSTROPHE | KEY_MOD_LEFT_SHIFT, // " + HID_KEYBOARD_3 | KEY_MOD_LEFT_SHIFT, // # + HID_KEYBOARD_4 | KEY_MOD_LEFT_SHIFT, // $ + HID_KEYBOARD_5 | KEY_MOD_LEFT_SHIFT, // % + HID_KEYBOARD_7 | KEY_MOD_LEFT_SHIFT, // & HID_KEYBOARD_APOSTROPHE, // ' - HID_KEYBOARD_9 | HID_KEYBOARD_L_SHIFT, // ( - HID_KEYBOARD_0 | HID_KEYBOARD_L_SHIFT, // ) - HID_KEYBOARD_8 | HID_KEYBOARD_L_SHIFT, // * - HID_KEYBOARD_EQUAL_SIGN | HID_KEYBOARD_L_SHIFT, // + + HID_KEYBOARD_9 | KEY_MOD_LEFT_SHIFT, // ( + HID_KEYBOARD_0 | KEY_MOD_LEFT_SHIFT, // ) + HID_KEYBOARD_8 | KEY_MOD_LEFT_SHIFT, // * + HID_KEYBOARD_EQUAL_SIGN | KEY_MOD_LEFT_SHIFT, // + HID_KEYPAD_COMMA, // , HID_KEYBOARD_MINUS, // - HID_KEYBOARD_DOT, // . @@ -67,44 +79,44 @@ static const uint16_t hid_asciimap[] = { HID_KEYBOARD_7, // 7 HID_KEYBOARD_8, // 8 HID_KEYBOARD_9, // 9 - HID_KEYBOARD_SEMICOLON | HID_KEYBOARD_L_SHIFT, // : + HID_KEYBOARD_SEMICOLON | KEY_MOD_LEFT_SHIFT, // : HID_KEYBOARD_SEMICOLON, // ; - HID_KEYPAD_COMMA | HID_KEYBOARD_L_SHIFT, // < + HID_KEYPAD_COMMA | KEY_MOD_LEFT_SHIFT, // < HID_KEYBOARD_EQUAL_SIGN, // = - HID_KEYBOARD_DOT | HID_KEYBOARD_L_SHIFT, // > - HID_KEYBOARD_SLASH | HID_KEYBOARD_L_SHIFT, // ? - HID_KEYBOARD_2 | HID_KEYBOARD_L_SHIFT, // @ - HID_KEYBOARD_A | HID_KEYBOARD_L_SHIFT, // A - HID_KEYBOARD_B | HID_KEYBOARD_L_SHIFT, // B - HID_KEYBOARD_C | HID_KEYBOARD_L_SHIFT, // C - HID_KEYBOARD_D | HID_KEYBOARD_L_SHIFT, // D - HID_KEYBOARD_E | HID_KEYBOARD_L_SHIFT, // E - HID_KEYBOARD_F | HID_KEYBOARD_L_SHIFT, // F - HID_KEYBOARD_G | HID_KEYBOARD_L_SHIFT, // G - HID_KEYBOARD_H | HID_KEYBOARD_L_SHIFT, // H - HID_KEYBOARD_I | HID_KEYBOARD_L_SHIFT, // I - HID_KEYBOARD_J | HID_KEYBOARD_L_SHIFT, // J - HID_KEYBOARD_K | HID_KEYBOARD_L_SHIFT, // K - HID_KEYBOARD_L | HID_KEYBOARD_L_SHIFT, // L - HID_KEYBOARD_M | HID_KEYBOARD_L_SHIFT, // M - HID_KEYBOARD_N | HID_KEYBOARD_L_SHIFT, // N - HID_KEYBOARD_O | HID_KEYBOARD_L_SHIFT, // O - HID_KEYBOARD_P | HID_KEYBOARD_L_SHIFT, // P - HID_KEYBOARD_Q | HID_KEYBOARD_L_SHIFT, // Q - HID_KEYBOARD_R | HID_KEYBOARD_L_SHIFT, // R - HID_KEYBOARD_S | HID_KEYBOARD_L_SHIFT, // S - HID_KEYBOARD_T | HID_KEYBOARD_L_SHIFT, // T - HID_KEYBOARD_U | HID_KEYBOARD_L_SHIFT, // U - HID_KEYBOARD_V | HID_KEYBOARD_L_SHIFT, // V - HID_KEYBOARD_W | HID_KEYBOARD_L_SHIFT, // W - HID_KEYBOARD_X | HID_KEYBOARD_L_SHIFT, // X - HID_KEYBOARD_Y | HID_KEYBOARD_L_SHIFT, // Y - HID_KEYBOARD_Z | HID_KEYBOARD_L_SHIFT, // Z + HID_KEYBOARD_DOT | KEY_MOD_LEFT_SHIFT, // > + HID_KEYBOARD_SLASH | KEY_MOD_LEFT_SHIFT, // ? + HID_KEYBOARD_2 | KEY_MOD_LEFT_SHIFT, // @ + HID_KEYBOARD_A | KEY_MOD_LEFT_SHIFT, // A + HID_KEYBOARD_B | KEY_MOD_LEFT_SHIFT, // B + HID_KEYBOARD_C | KEY_MOD_LEFT_SHIFT, // C + HID_KEYBOARD_D | KEY_MOD_LEFT_SHIFT, // D + HID_KEYBOARD_E | KEY_MOD_LEFT_SHIFT, // E + HID_KEYBOARD_F | KEY_MOD_LEFT_SHIFT, // F + HID_KEYBOARD_G | KEY_MOD_LEFT_SHIFT, // G + HID_KEYBOARD_H | KEY_MOD_LEFT_SHIFT, // H + HID_KEYBOARD_I | KEY_MOD_LEFT_SHIFT, // I + HID_KEYBOARD_J | KEY_MOD_LEFT_SHIFT, // J + HID_KEYBOARD_K | KEY_MOD_LEFT_SHIFT, // K + HID_KEYBOARD_L | KEY_MOD_LEFT_SHIFT, // L + HID_KEYBOARD_M | KEY_MOD_LEFT_SHIFT, // M + HID_KEYBOARD_N | KEY_MOD_LEFT_SHIFT, // N + HID_KEYBOARD_O | KEY_MOD_LEFT_SHIFT, // O + HID_KEYBOARD_P | KEY_MOD_LEFT_SHIFT, // P + HID_KEYBOARD_Q | KEY_MOD_LEFT_SHIFT, // Q + HID_KEYBOARD_R | KEY_MOD_LEFT_SHIFT, // R + HID_KEYBOARD_S | KEY_MOD_LEFT_SHIFT, // S + HID_KEYBOARD_T | KEY_MOD_LEFT_SHIFT, // T + HID_KEYBOARD_U | KEY_MOD_LEFT_SHIFT, // U + HID_KEYBOARD_V | KEY_MOD_LEFT_SHIFT, // V + HID_KEYBOARD_W | KEY_MOD_LEFT_SHIFT, // W + HID_KEYBOARD_X | KEY_MOD_LEFT_SHIFT, // X + HID_KEYBOARD_Y | KEY_MOD_LEFT_SHIFT, // Y + HID_KEYBOARD_Z | KEY_MOD_LEFT_SHIFT, // Z HID_KEYBOARD_OPEN_BRACKET, // [ HID_KEYBOARD_BACKSLASH, // bslash HID_KEYBOARD_CLOSE_BRACKET, // ] - HID_KEYBOARD_6 | HID_KEYBOARD_L_SHIFT, // ^ - HID_KEYBOARD_MINUS | HID_KEYBOARD_L_SHIFT, // _ + HID_KEYBOARD_6 | KEY_MOD_LEFT_SHIFT, // ^ + HID_KEYBOARD_MINUS | KEY_MOD_LEFT_SHIFT, // _ HID_KEYBOARD_GRAVE_ACCENT, // ` HID_KEYBOARD_A, // a HID_KEYBOARD_B, // b @@ -132,10 +144,10 @@ static const uint16_t hid_asciimap[] = { HID_KEYBOARD_X, // x HID_KEYBOARD_Y, // y HID_KEYBOARD_Z, // z - HID_KEYBOARD_OPEN_BRACKET | HID_KEYBOARD_L_SHIFT, // { - HID_KEYBOARD_BACKSLASH | HID_KEYBOARD_L_SHIFT, // | - HID_KEYBOARD_CLOSE_BRACKET | HID_KEYBOARD_L_SHIFT, // } - HID_KEYBOARD_GRAVE_ACCENT | HID_KEYBOARD_L_SHIFT, // ~ + HID_KEYBOARD_OPEN_BRACKET | KEY_MOD_LEFT_SHIFT, // { + HID_KEYBOARD_BACKSLASH | KEY_MOD_LEFT_SHIFT, // | + HID_KEYBOARD_CLOSE_BRACKET | KEY_MOD_LEFT_SHIFT, // } + HID_KEYBOARD_GRAVE_ACCENT | KEY_MOD_LEFT_SHIFT, // ~ HID_KEYBOARD_NONE, // DEL }; @@ -151,18 +163,6 @@ typedef void (*HidStateCallback)(bool state, void* context); /** ASCII to keycode conversion macro */ #define HID_ASCII_TO_KEY(x) (((uint8_t)x < 128) ? (hid_asciimap[(uint8_t)x]) : HID_KEYBOARD_NONE) -/** HID keyboard modifiers */ -enum HidKeyboardModifiers { - HID_KB_MOD_L_CTRL = (1 << 0), - HID_KB_MOD_L_SHIFT = (1 << 1), - HID_KB_MOD_L_ALT = (1 << 2), - HID_KB_MOD_L_GUI = (1 << 3), - HID_KB_MOD_R_CTRL = (1 << 4), - HID_KB_MOD_R_SHIFT = (1 << 5), - HID_KB_MOD_R_ALT = (1 << 6), - HID_KB_MOD_R_GUI = (1 << 7), -}; - /** HID keyboard leds */ enum HidKeyboardLeds { HID_KB_LED_NUM = (1 << 0), From f8e486d831281039a2947e318ca929366fa117d0 Mon Sep 17 00:00:00 2001 From: Cutch Date: Tue, 21 Jun 2022 07:07:10 -0400 Subject: [PATCH 06/12] Fixed misaligned bad usb keys --- applications/bad_usb/bad_usb_script.c | 6 +++--- firmware/targets/furi_hal_include/furi_hal_usb_hid.h | 12 +++++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/applications/bad_usb/bad_usb_script.c b/applications/bad_usb/bad_usb_script.c index 5558a189ee4..8837b4086a8 100644 --- a/applications/bad_usb/bad_usb_script.c +++ b/applications/bad_usb/bad_usb_script.c @@ -217,9 +217,9 @@ static bool ducky_string(const char* param) { static uint16_t ducky_get_keycode(const char* param, bool accept_chars) { for(uint8_t i = 0; i < (sizeof(ducky_keys) / sizeof(ducky_keys[0])); i++) { - uint8_t HID_KEYBOARD_cmd_len = strlen(ducky_keys[i].name); - if((strncmp(param, ducky_keys[i].name, HID_KEYBOARD_cmd_len) == 0) && - (ducky_is_line_end(param[HID_KEYBOARD_cmd_len]))) { + uint8_t key_cmd_len = strlen(ducky_keys[i].name); + if((strncmp(param, ducky_keys[i].name, key_cmd_len) == 0) && + (ducky_is_line_end(param[key_cmd_len]))) { return ducky_keys[i].keycode; } } diff --git a/firmware/targets/furi_hal_include/furi_hal_usb_hid.h b/firmware/targets/furi_hal_include/furi_hal_usb_hid.h index 7fe2d8d1450..97bac7f049f 100644 --- a/firmware/targets/furi_hal_include/furi_hal_usb_hid.h +++ b/firmware/targets/furi_hal_include/furi_hal_usb_hid.h @@ -6,6 +6,8 @@ #include "hid_usage_led.h" #define HID_KEYBOARD_NONE 0x00 +// Remapping the colon key which is shift + ; to comma +#define HID_KEYBOARD_COMMA HID_KEYBOARD_COLON /** HID keyboard modifier keys */ enum HidKeyboardMods { @@ -29,9 +31,9 @@ static const uint16_t hid_asciimap[] = { HID_KEYBOARD_NONE, // ENQ HID_KEYBOARD_NONE, // ACK HID_KEYBOARD_NONE, // BEL - HID_KEYPAD_BACKSPACE, // BS Backspace - HID_KEYPAD_TAB, // TAB Tab - HID_KEYPAD_ENTER, // LF Enter + HID_KEYBOARD_DELETE, // BS Backspace + HID_KEYBOARD_TAB, // TAB Tab + HID_KEYBOARD_RETURN, // LF Enter HID_KEYBOARD_NONE, // VT HID_KEYBOARD_NONE, // FF HID_KEYBOARD_NONE, // CR @@ -65,7 +67,7 @@ static const uint16_t hid_asciimap[] = { HID_KEYBOARD_0 | KEY_MOD_LEFT_SHIFT, // ) HID_KEYBOARD_8 | KEY_MOD_LEFT_SHIFT, // * HID_KEYBOARD_EQUAL_SIGN | KEY_MOD_LEFT_SHIFT, // + - HID_KEYPAD_COMMA, // , + HID_KEYBOARD_COMMA, // , HID_KEYBOARD_MINUS, // - HID_KEYBOARD_DOT, // . HID_KEYBOARD_SLASH, // / @@ -81,7 +83,7 @@ static const uint16_t hid_asciimap[] = { HID_KEYBOARD_9, // 9 HID_KEYBOARD_SEMICOLON | KEY_MOD_LEFT_SHIFT, // : HID_KEYBOARD_SEMICOLON, // ; - HID_KEYPAD_COMMA | KEY_MOD_LEFT_SHIFT, // < + HID_KEYBOARD_COMMA | KEY_MOD_LEFT_SHIFT, // < HID_KEYBOARD_EQUAL_SIGN, // = HID_KEYBOARD_DOT | KEY_MOD_LEFT_SHIFT, // > HID_KEYBOARD_SLASH | KEY_MOD_LEFT_SHIFT, // ? From 055c18976e092aef5708539b6da9ac70b6c8db81 Mon Sep 17 00:00:00 2001 From: Cutch Date: Wed, 6 Jul 2022 22:04:30 -0400 Subject: [PATCH 07/12] Fix keyboard app keys --- .../bt/bt_hid_app/views/bt_hid_keyboard.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/applications/bt/bt_hid_app/views/bt_hid_keyboard.c b/applications/bt/bt_hid_app/views/bt_hid_keyboard.c index 825791d9871..8b6dd94a4b4 100644 --- a/applications/bt/bt_hid_app/views/bt_hid_keyboard.c +++ b/applications/bt/bt_hid_app/views/bt_hid_keyboard.c @@ -79,15 +79,15 @@ BtHidKeyboardKey keyboardKeySet[ROW_COUNT][COLUMN_COUNT] = { .value = HID_KEYBOARD_CLOSE_BRACKET}, }, { - {.width = 1, .icon = NULL, .key = "a", .shift_key = "A", .value = HID_KEYBOARD_Q}, - {.width = 1, .icon = NULL, .key = "s", .shift_key = "S", .value = HID_KEYBOARD_W}, - {.width = 1, .icon = NULL, .key = "d", .shift_key = "D", .value = HID_KEYBOARD_E}, - {.width = 1, .icon = NULL, .key = "f", .shift_key = "F", .value = HID_KEYBOARD_R}, - {.width = 1, .icon = NULL, .key = "g", .shift_key = "G", .value = HID_KEYBOARD_T}, - {.width = 1, .icon = NULL, .key = "h", .shift_key = "H", .value = HID_KEYBOARD_Y}, - {.width = 1, .icon = NULL, .key = "j", .shift_key = "J", .value = HID_KEYBOARD_U}, - {.width = 1, .icon = NULL, .key = "k", .shift_key = "K", .value = HID_KEYBOARD_I}, - {.width = 1, .icon = NULL, .key = "l", .shift_key = "L", .value = HID_KEYBOARD_O}, + {.width = 1, .icon = NULL, .key = "a", .shift_key = "A", .value = HID_KEYBOARD_A}, + {.width = 1, .icon = NULL, .key = "s", .shift_key = "S", .value = HID_KEYBOARD_S}, + {.width = 1, .icon = NULL, .key = "d", .shift_key = "D", .value = HID_KEYBOARD_D}, + {.width = 1, .icon = NULL, .key = "f", .shift_key = "F", .value = HID_KEYBOARD_F}, + {.width = 1, .icon = NULL, .key = "g", .shift_key = "G", .value = HID_KEYBOARD_G}, + {.width = 1, .icon = NULL, .key = "h", .shift_key = "H", .value = HID_KEYBOARD_H}, + {.width = 1, .icon = NULL, .key = "j", .shift_key = "J", .value = HID_KEYBOARD_J}, + {.width = 1, .icon = NULL, .key = "k", .shift_key = "K", .value = HID_KEYBOARD_K}, + {.width = 1, .icon = NULL, .key = "l", .shift_key = "L", .value = HID_KEYBOARD_L}, {.width = 1, .icon = NULL, .key = ";", .shift_key = ":", .value = HID_KEYBOARD_SEMICOLON}, {.width = 2, .icon = &I_Pin_arrow_right_9x7, .value = HID_KEYBOARD_RETURN}, {.width = 0, .value = HID_KEYBOARD_RETURN}, From d98d0bc84e07757e8ca6f5a9d2311d78aa7237c0 Mon Sep 17 00:00:00 2001 From: Cutch Date: Thu, 7 Jul 2022 00:13:38 -0400 Subject: [PATCH 08/12] Partial fix for bt app and linux --- .../bt/bt_hid_app/views/bt_hid_keynote.c | 2 +- firmware/targets/f7/ble_glue/hid_service.c | 62 ------------------- 2 files changed, 1 insertion(+), 63 deletions(-) diff --git a/applications/bt/bt_hid_app/views/bt_hid_keynote.c b/applications/bt/bt_hid_app/views/bt_hid_keynote.c index 1ff23aa8493..60a1ebc0877 100755 --- a/applications/bt/bt_hid_app/views/bt_hid_keynote.c +++ b/applications/bt/bt_hid_app/views/bt_hid_keynote.c @@ -75,7 +75,7 @@ static void bt_hid_keynote_draw_callback(Canvas* canvas, void* context) { // Right canvas_draw_icon(canvas, 42, 45, &I_Button_18x18); if(model->right_pressed) { - elements_slightly_rounded_box(canvas, 65, 47, 13, 13); + elements_slightly_rounded_box(canvas, 45, 47, 13, 13); canvas_set_color(canvas, ColorWhite); } bt_hid_keynote_draw_arrow(canvas, 53, 53, CanvasDirectionLeftToRight); diff --git a/firmware/targets/f7/ble_glue/hid_service.c b/firmware/targets/f7/ble_glue/hid_service.c index 4941fa307be..0497dcbcf6b 100644 --- a/firmware/targets/f7/ble_glue/hid_service.c +++ b/firmware/targets/f7/ble_glue/hid_service.c @@ -10,7 +10,6 @@ typedef struct { uint16_t svc_handle; uint16_t protocol_mode_char_handle; uint16_t report_char_handle[HID_SVC_REPORT_COUNT]; - uint16_t report_ref_desc_handle[HID_SVC_REPORT_COUNT]; uint16_t report_map_char_handle; uint16_t info_char_handle; uint16_t ctrl_point_char_handle; @@ -39,7 +38,6 @@ void hid_svc_start() { tBleStatus status; hid_svc = malloc(sizeof(HIDSvc)); Service_UUID_t svc_uuid = {}; - Char_Desc_Uuid_t desc_uuid = {}; Char_UUID_t char_uuid = {}; // Register event handler @@ -88,7 +86,6 @@ void hid_svc_start() { #if(HID_SVC_REPORT_COUNT != 0) for(uint8_t i = 0; i < HID_SVC_REPORT_COUNT; i++) { if(i < HID_SVC_INPUT_REPORT_COUNT) { - uint8_t buf[2] = {i, 1}; // 1 input char_uuid.Char_UUID_16 = REPORT_CHAR_UUID; status = aci_gatt_add_char( hid_svc->svc_handle, @@ -104,27 +101,7 @@ void hid_svc_start() { if(status) { FURI_LOG_E(TAG, "Failed to add report characteristic: %d", status); } - - desc_uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID; - status = aci_gatt_add_char_desc( - hid_svc->svc_handle, - hid_svc->report_char_handle[i], - UUID_TYPE_16, - &desc_uuid, - HID_SVC_REPORT_REF_LEN, - HID_SVC_REPORT_REF_LEN, - buf, - ATTR_PERMISSION_NONE, - ATTR_ACCESS_READ_ONLY, - GATT_DONT_NOTIFY_EVENTS, - MIN_ENCRY_KEY_SIZE, - CHAR_VALUE_LEN_CONSTANT, - &(hid_svc->report_ref_desc_handle[i])); - if(status) { - FURI_LOG_E(TAG, "Failed to add report reference descriptor: %d", status); - } } else if((i - HID_SVC_INPUT_REPORT_COUNT) < HID_SVC_OUTPUT_REPORT_COUNT) { - uint8_t buf[2] = {i, 2}; // 2 output char_uuid.Char_UUID_16 = REPORT_CHAR_UUID; status = aci_gatt_add_char( hid_svc->svc_handle, @@ -140,27 +117,7 @@ void hid_svc_start() { if(status) { FURI_LOG_E(TAG, "Failed to add report characteristic: %d", status); } - - desc_uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID; - status = aci_gatt_add_char_desc( - hid_svc->svc_handle, - hid_svc->report_char_handle[i], - UUID_TYPE_16, - &desc_uuid, - HID_SVC_REPORT_REF_LEN, - HID_SVC_REPORT_REF_LEN, - buf, - ATTR_PERMISSION_NONE, - ATTR_ACCESS_READ_ONLY, - GATT_DONT_NOTIFY_EVENTS, - MIN_ENCRY_KEY_SIZE, - CHAR_VALUE_LEN_CONSTANT, - &(hid_svc->report_ref_desc_handle[i])); - if(status) { - FURI_LOG_E(TAG, "Failed to add report reference descriptor: %d", status); - } } else { - uint8_t buf[2] = {i, 3}; // 3 feature char_uuid.Char_UUID_16 = REPORT_CHAR_UUID; status = aci_gatt_add_char( hid_svc->svc_handle, @@ -176,25 +133,6 @@ void hid_svc_start() { if(status) { FURI_LOG_E(TAG, "Failed to add report characteristic: %d", status); } - - desc_uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID; - status = aci_gatt_add_char_desc( - hid_svc->svc_handle, - hid_svc->report_char_handle[i], - UUID_TYPE_16, - &desc_uuid, - HID_SVC_REPORT_REF_LEN, - HID_SVC_REPORT_REF_LEN, - buf, - ATTR_PERMISSION_NONE, - ATTR_ACCESS_READ_ONLY, - GATT_DONT_NOTIFY_EVENTS, - MIN_ENCRY_KEY_SIZE, - CHAR_VALUE_LEN_CONSTANT, - &(hid_svc->report_ref_desc_handle[i])); - if(status) { - FURI_LOG_E(TAG, "Failed to add report reference descriptor: %d", status); - } } } #endif From 08d6707e83d716a528ea15eaeaeca321872dc903 Mon Sep 17 00:00:00 2001 From: Cutch Date: Thu, 7 Jul 2022 12:34:09 -0400 Subject: [PATCH 09/12] Update to work across platforms --- firmware/targets/f7/ble_glue/hid_service.c | 66 ++++++++++++++++++- firmware/targets/f7/ble_glue/hid_service.h | 6 +- .../targets/f7/furi_hal/furi_hal_bt_hid.c | 46 ++++++------- 3 files changed, 90 insertions(+), 28 deletions(-) diff --git a/firmware/targets/f7/ble_glue/hid_service.c b/firmware/targets/f7/ble_glue/hid_service.c index 0497dcbcf6b..95be8c5942b 100644 --- a/firmware/targets/f7/ble_glue/hid_service.c +++ b/firmware/targets/f7/ble_glue/hid_service.c @@ -10,6 +10,7 @@ typedef struct { uint16_t svc_handle; uint16_t protocol_mode_char_handle; uint16_t report_char_handle[HID_SVC_REPORT_COUNT]; + uint16_t report_ref_desc_handle[HID_SVC_REPORT_COUNT]; uint16_t report_map_char_handle; uint16_t info_char_handle; uint16_t ctrl_point_char_handle; @@ -38,6 +39,7 @@ void hid_svc_start() { tBleStatus status; hid_svc = malloc(sizeof(HIDSvc)); Service_UUID_t svc_uuid = {}; + Char_Desc_Uuid_t desc_uuid = {}; Char_UUID_t char_uuid = {}; // Register event handler @@ -86,6 +88,7 @@ void hid_svc_start() { #if(HID_SVC_REPORT_COUNT != 0) for(uint8_t i = 0; i < HID_SVC_REPORT_COUNT; i++) { if(i < HID_SVC_INPUT_REPORT_COUNT) { + uint8_t buf[2] = {i + 1, 1}; // 1 input char_uuid.Char_UUID_16 = REPORT_CHAR_UUID; status = aci_gatt_add_char( hid_svc->svc_handle, @@ -101,7 +104,27 @@ void hid_svc_start() { if(status) { FURI_LOG_E(TAG, "Failed to add report characteristic: %d", status); } + + desc_uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID; + status = aci_gatt_add_char_desc( + hid_svc->svc_handle, + hid_svc->report_char_handle[i], + UUID_TYPE_16, + &desc_uuid, + HID_SVC_REPORT_REF_LEN, + HID_SVC_REPORT_REF_LEN, + buf, + ATTR_PERMISSION_NONE, + ATTR_ACCESS_READ_WRITE, + GATT_DONT_NOTIFY_EVENTS, + MIN_ENCRY_KEY_SIZE, + CHAR_VALUE_LEN_CONSTANT, + &(hid_svc->report_ref_desc_handle[i])); + if(status) { + FURI_LOG_E(TAG, "Failed to add report reference descriptor: %d", status); + } } else if((i - HID_SVC_INPUT_REPORT_COUNT) < HID_SVC_OUTPUT_REPORT_COUNT) { + uint8_t buf[2] = {i + 1, 2}; // 2 output char_uuid.Char_UUID_16 = REPORT_CHAR_UUID; status = aci_gatt_add_char( hid_svc->svc_handle, @@ -117,7 +140,27 @@ void hid_svc_start() { if(status) { FURI_LOG_E(TAG, "Failed to add report characteristic: %d", status); } + + desc_uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID; + status = aci_gatt_add_char_desc( + hid_svc->svc_handle, + hid_svc->report_char_handle[i], + UUID_TYPE_16, + &desc_uuid, + HID_SVC_REPORT_REF_LEN, + HID_SVC_REPORT_REF_LEN, + buf, + ATTR_PERMISSION_NONE, + ATTR_ACCESS_READ_WRITE, + GATT_DONT_NOTIFY_EVENTS, + MIN_ENCRY_KEY_SIZE, + CHAR_VALUE_LEN_CONSTANT, + &(hid_svc->report_ref_desc_handle[i])); + if(status) { + FURI_LOG_E(TAG, "Failed to add report reference descriptor: %d", status); + } } else { + uint8_t buf[2] = {i + 1, 3}; // 3 feature char_uuid.Char_UUID_16 = REPORT_CHAR_UUID; status = aci_gatt_add_char( hid_svc->svc_handle, @@ -133,6 +176,25 @@ void hid_svc_start() { if(status) { FURI_LOG_E(TAG, "Failed to add report characteristic: %d", status); } + + desc_uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID; + status = aci_gatt_add_char_desc( + hid_svc->svc_handle, + hid_svc->report_char_handle[i], + UUID_TYPE_16, + &desc_uuid, + HID_SVC_REPORT_REF_LEN, + HID_SVC_REPORT_REF_LEN, + buf, + ATTR_PERMISSION_NONE, + ATTR_ACCESS_READ_WRITE, + GATT_DONT_NOTIFY_EVENTS, + MIN_ENCRY_KEY_SIZE, + CHAR_VALUE_LEN_CONSTANT, + &(hid_svc->report_ref_desc_handle[i])); + if(status) { + FURI_LOG_E(TAG, "Failed to add report reference descriptor: %d", status); + } } } #endif @@ -200,12 +262,12 @@ bool hid_svc_update_report_map(uint8_t* data, uint16_t len) { return true; } -bool hid_svc_update_input_report(uint8_t* data, uint16_t len) { +bool hid_svc_update_input_report(uint8_t input_report_num, uint8_t* data, uint16_t len) { furi_assert(data); furi_assert(hid_svc); tBleStatus status = aci_gatt_update_char_value( - hid_svc->svc_handle, hid_svc->report_char_handle[0], 0, len, data); + hid_svc->svc_handle, hid_svc->report_char_handle[input_report_num], 0, len, data); if(status) { FURI_LOG_E(TAG, "Failed updating report characteristic: %d", status); return false; diff --git a/firmware/targets/f7/ble_glue/hid_service.h b/firmware/targets/f7/ble_glue/hid_service.h index 0da41462fd2..96d1d7d93ad 100644 --- a/firmware/targets/f7/ble_glue/hid_service.h +++ b/firmware/targets/f7/ble_glue/hid_service.h @@ -3,13 +3,13 @@ #include #include -#define HID_SVC_REPORT_MAP_MAX_LEN (512) +#define HID_SVC_REPORT_MAP_MAX_LEN (255) #define HID_SVC_REPORT_MAX_LEN (255) #define HID_SVC_REPORT_REF_LEN (2) #define HID_SVC_INFO_LEN (4) #define HID_SVC_CONTROL_POINT_LEN (1) -#define HID_SVC_INPUT_REPORT_COUNT (1) +#define HID_SVC_INPUT_REPORT_COUNT (3) #define HID_SVC_OUTPUT_REPORT_COUNT (0) #define HID_SVC_FEATURE_REPORT_COUNT (0) #define HID_SVC_REPORT_COUNT \ @@ -23,6 +23,6 @@ bool hid_svc_is_started(); bool hid_svc_update_report_map(uint8_t* data, uint16_t len); -bool hid_svc_update_input_report(uint8_t* data, uint16_t len); +bool hid_svc_update_input_report(uint8_t input_report_num, uint8_t* data, uint16_t len); bool hid_svc_update_info(uint8_t* data, uint16_t len); diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c b/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c index b3ed101615e..99db85b6d56 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c @@ -15,21 +15,19 @@ #define FURI_HAL_BT_HID_KB_MAX_KEYS 6 #define FURI_HAL_BT_HID_CONSUMER_MAX_KEYS 1 -enum HidReportId { - ReportIdKeyboard = 1, - ReportIdMouse = 2, - ReportIdConsumer = 3, +enum HidInputNumber { + ReportIdKeyboard = 0, // Maps to report id 1 + ReportIdMouse = 1, // Maps to report id 2 + ReportIdConsumer = 2, // Maps to report id 3 }; typedef struct { - uint8_t report_id; uint8_t mods; uint8_t reserved; uint8_t key[FURI_HAL_BT_HID_KB_MAX_KEYS]; } __attribute__((__packed__)) FuriHalBtHidKbReport; typedef struct { - uint8_t report_id; uint8_t btn; int8_t x; int8_t y; @@ -37,7 +35,6 @@ typedef struct { } __attribute__((__packed__)) FuriHalBtHidMouseReport; typedef struct { - uint8_t report_id; uint16_t key[FURI_HAL_BT_HID_CONSUMER_MAX_KEYS]; } __attribute__((__packed__)) FuriHalBtHidConsumerReport; @@ -136,11 +133,8 @@ void furi_hal_bt_hid_start() { } // Configure HID Keyboard kb_report = malloc(sizeof(FuriHalBtHidKbReport)); - kb_report->report_id = ReportIdKeyboard; mouse_report = malloc(sizeof(FuriHalBtHidMouseReport)); - mouse_report->report_id = ReportIdMouse; consumer_report = malloc(sizeof(FuriHalBtHidConsumerReport)); - consumer_report->report_id = ReportIdConsumer; // Configure Report Map characteristic hid_svc_update_report_map( furi_hal_bt_hid_report_map_data, sizeof(furi_hal_bt_hid_report_map_data)); @@ -186,7 +180,8 @@ bool furi_hal_bt_hid_kb_press(uint16_t button) { } } kb_report->mods |= (button >> 8); - return hid_svc_update_input_report((uint8_t*)kb_report, sizeof(FuriHalBtHidKbReport)); + return hid_svc_update_input_report( + ReportIdKeyboard, (uint8_t*)kb_report, sizeof(FuriHalBtHidKbReport)); } bool furi_hal_bt_hid_kb_release(uint16_t button) { @@ -198,7 +193,8 @@ bool furi_hal_bt_hid_kb_release(uint16_t button) { } } kb_report->mods &= ~(button >> 8); - return hid_svc_update_input_report((uint8_t*)kb_report, sizeof(FuriHalBtHidKbReport)); + return hid_svc_update_input_report( + ReportIdKeyboard, (uint8_t*)kb_report, sizeof(FuriHalBtHidKbReport)); } bool furi_hal_bt_hid_kb_release_all() { @@ -207,7 +203,8 @@ bool furi_hal_bt_hid_kb_release_all() { kb_report->key[i] = 0; } kb_report->mods = 0; - return hid_svc_update_input_report((uint8_t*)kb_report, sizeof(FuriHalBtHidKbReport)); + return hid_svc_update_input_report( + ReportIdKeyboard, (uint8_t*)kb_report, sizeof(FuriHalBtHidKbReport)); } bool furi_hal_bt_hid_consumer_key_press(uint16_t button) { @@ -219,7 +216,7 @@ bool furi_hal_bt_hid_consumer_key_press(uint16_t button) { } } return hid_svc_update_input_report( - (uint8_t*)consumer_report, sizeof(FuriHalBtHidConsumerReport)); + ReportIdConsumer, (uint8_t*)consumer_report, sizeof(FuriHalBtHidConsumerReport)); } bool furi_hal_bt_hid_consumer_key_release(uint16_t button) { @@ -231,7 +228,7 @@ bool furi_hal_bt_hid_consumer_key_release(uint16_t button) { } } return hid_svc_update_input_report( - (uint8_t*)consumer_report, sizeof(FuriHalBtHidConsumerReport)); + ReportIdConsumer, (uint8_t*)consumer_report, sizeof(FuriHalBtHidConsumerReport)); } bool furi_hal_bt_hid_consumer_key_release_all() { @@ -240,15 +237,15 @@ bool furi_hal_bt_hid_consumer_key_release_all() { consumer_report->key[i] = 0; } return hid_svc_update_input_report( - (uint8_t*)consumer_report, sizeof(FuriHalBtHidConsumerReport)); + ReportIdConsumer, (uint8_t*)consumer_report, sizeof(FuriHalBtHidConsumerReport)); } bool furi_hal_bt_hid_mouse_move(int8_t dx, int8_t dy) { furi_assert(mouse_report); mouse_report->x = dx; mouse_report->y = dy; - bool state = - hid_svc_update_input_report((uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); + bool state = hid_svc_update_input_report( + ReportIdMouse, (uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); mouse_report->x = 0; mouse_report->y = 0; return state; @@ -257,26 +254,29 @@ bool furi_hal_bt_hid_mouse_move(int8_t dx, int8_t dy) { bool furi_hal_bt_hid_mouse_press(uint8_t button) { furi_assert(mouse_report); mouse_report->btn |= button; - return hid_svc_update_input_report((uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); + return hid_svc_update_input_report( + ReportIdMouse, (uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); } bool furi_hal_bt_hid_mouse_release(uint8_t button) { furi_assert(mouse_report); mouse_report->btn &= ~button; - return hid_svc_update_input_report((uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); + return hid_svc_update_input_report( + ReportIdMouse, (uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); } bool furi_hal_bt_hid_mouse_release_all() { furi_assert(mouse_report); mouse_report->btn = 0; - return hid_svc_update_input_report((uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); + return hid_svc_update_input_report( + ReportIdMouse, (uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); } bool furi_hal_bt_hid_mouse_scroll(int8_t delta) { furi_assert(mouse_report); mouse_report->wheel = delta; - bool state = - hid_svc_update_input_report((uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); + bool state = hid_svc_update_input_report( + ReportIdMouse, (uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); mouse_report->wheel = 0; return state; } From 6ebe6e451f141d2033361f0c9bc47e072e7c039e Mon Sep 17 00:00:00 2001 From: Cutch Date: Thu, 7 Jul 2022 13:38:58 -0400 Subject: [PATCH 10/12] Fix for report ids --- .../targets/f7/furi_hal/furi_hal_bt_hid.c | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c b/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c index 99db85b6d56..7c1cf73a7c1 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c @@ -15,10 +15,17 @@ #define FURI_HAL_BT_HID_KB_MAX_KEYS 6 #define FURI_HAL_BT_HID_CONSUMER_MAX_KEYS 1 +// Report ids cant be 0 +enum HidReportId { + ReportIdKeyboard = 1, + ReportIdMouse = 2, + ReportIdConsumer = 3, +}; +// Report numbers corresponded to the report id with an offset of 1 enum HidInputNumber { - ReportIdKeyboard = 0, // Maps to report id 1 - ReportIdMouse = 1, // Maps to report id 2 - ReportIdConsumer = 2, // Maps to report id 3 + ReportNumberKeyboard = 0, + ReportNumberMouse = 1, + ReportNumberConsumer = 2, }; typedef struct { @@ -181,7 +188,7 @@ bool furi_hal_bt_hid_kb_press(uint16_t button) { } kb_report->mods |= (button >> 8); return hid_svc_update_input_report( - ReportIdKeyboard, (uint8_t*)kb_report, sizeof(FuriHalBtHidKbReport)); + ReportNumberKeyboard, (uint8_t*)kb_report, sizeof(FuriHalBtHidKbReport)); } bool furi_hal_bt_hid_kb_release(uint16_t button) { @@ -194,7 +201,7 @@ bool furi_hal_bt_hid_kb_release(uint16_t button) { } kb_report->mods &= ~(button >> 8); return hid_svc_update_input_report( - ReportIdKeyboard, (uint8_t*)kb_report, sizeof(FuriHalBtHidKbReport)); + ReportNumberKeyboard, (uint8_t*)kb_report, sizeof(FuriHalBtHidKbReport)); } bool furi_hal_bt_hid_kb_release_all() { @@ -204,7 +211,7 @@ bool furi_hal_bt_hid_kb_release_all() { } kb_report->mods = 0; return hid_svc_update_input_report( - ReportIdKeyboard, (uint8_t*)kb_report, sizeof(FuriHalBtHidKbReport)); + ReportNumberKeyboard, (uint8_t*)kb_report, sizeof(FuriHalBtHidKbReport)); } bool furi_hal_bt_hid_consumer_key_press(uint16_t button) { @@ -216,7 +223,7 @@ bool furi_hal_bt_hid_consumer_key_press(uint16_t button) { } } return hid_svc_update_input_report( - ReportIdConsumer, (uint8_t*)consumer_report, sizeof(FuriHalBtHidConsumerReport)); + ReportNumberConsumer, (uint8_t*)consumer_report, sizeof(FuriHalBtHidConsumerReport)); } bool furi_hal_bt_hid_consumer_key_release(uint16_t button) { @@ -228,7 +235,7 @@ bool furi_hal_bt_hid_consumer_key_release(uint16_t button) { } } return hid_svc_update_input_report( - ReportIdConsumer, (uint8_t*)consumer_report, sizeof(FuriHalBtHidConsumerReport)); + ReportNumberConsumer, (uint8_t*)consumer_report, sizeof(FuriHalBtHidConsumerReport)); } bool furi_hal_bt_hid_consumer_key_release_all() { @@ -237,7 +244,7 @@ bool furi_hal_bt_hid_consumer_key_release_all() { consumer_report->key[i] = 0; } return hid_svc_update_input_report( - ReportIdConsumer, (uint8_t*)consumer_report, sizeof(FuriHalBtHidConsumerReport)); + ReportNumberConsumer, (uint8_t*)consumer_report, sizeof(FuriHalBtHidConsumerReport)); } bool furi_hal_bt_hid_mouse_move(int8_t dx, int8_t dy) { @@ -245,7 +252,7 @@ bool furi_hal_bt_hid_mouse_move(int8_t dx, int8_t dy) { mouse_report->x = dx; mouse_report->y = dy; bool state = hid_svc_update_input_report( - ReportIdMouse, (uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); + ReportNumberMouse, (uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); mouse_report->x = 0; mouse_report->y = 0; return state; @@ -255,28 +262,28 @@ bool furi_hal_bt_hid_mouse_press(uint8_t button) { furi_assert(mouse_report); mouse_report->btn |= button; return hid_svc_update_input_report( - ReportIdMouse, (uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); + ReportNumberMouse, (uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); } bool furi_hal_bt_hid_mouse_release(uint8_t button) { furi_assert(mouse_report); mouse_report->btn &= ~button; return hid_svc_update_input_report( - ReportIdMouse, (uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); + ReportNumberMouse, (uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); } bool furi_hal_bt_hid_mouse_release_all() { furi_assert(mouse_report); mouse_report->btn = 0; return hid_svc_update_input_report( - ReportIdMouse, (uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); + ReportNumberMouse, (uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); } bool furi_hal_bt_hid_mouse_scroll(int8_t delta) { furi_assert(mouse_report); mouse_report->wheel = delta; bool state = hid_svc_update_input_report( - ReportIdMouse, (uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); + ReportNumberMouse, (uint8_t*)mouse_report, sizeof(FuriHalBtHidMouseReport)); mouse_report->wheel = 0; return state; } From d419fe04f1a9ed3b3d691f63954b2d542cbaf502 Mon Sep 17 00:00:00 2001 From: Aleksandr Kutuzov Date: Fri, 8 Jul 2022 21:19:42 +0900 Subject: [PATCH 11/12] BtHidApp: move variable from bss to model, cleanup naming. --- .../bt/bt_hid_app/views/bt_hid_keyboard.c | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/applications/bt/bt_hid_app/views/bt_hid_keyboard.c b/applications/bt/bt_hid_app/views/bt_hid_keyboard.c index 8b6dd94a4b4..1088e2959d6 100644 --- a/applications/bt/bt_hid_app/views/bt_hid_keyboard.c +++ b/applications/bt/bt_hid_app/views/bt_hid_keyboard.c @@ -21,6 +21,7 @@ typedef struct { bool ok_pressed; bool back_pressed; bool connected; + char key_string[5]; } BtHidKeyboardModel; typedef struct { @@ -35,6 +36,7 @@ typedef struct { int8_t x; int8_t y; } BtHidKeyboardPoint; + // 4 BY 12 #define MARGIN_TOP 0 #define MARGIN_LEFT 4 @@ -45,7 +47,7 @@ typedef struct { #define COLUMN_COUNT 12 // 0 width items are not drawn, but there value is used -BtHidKeyboardKey keyboardKeySet[ROW_COUNT][COLUMN_COUNT] = { +const BtHidKeyboardKey bt_hid_keyboard_keyset[ROW_COUNT][COLUMN_COUNT] = { { {.width = 1, .icon = NULL, .key = "1", .shift_key = "!", .value = HID_KEYBOARD_1}, {.width = 1, .icon = NULL, .key = "2", .shift_key = "@", .value = HID_KEYBOARD_2}, @@ -135,13 +137,14 @@ BtHidKeyboardKey keyboardKeySet[ROW_COUNT][COLUMN_COUNT] = { {.width = 0, .icon = NULL, .value = HID_KEYBOARD_TAB}, }, }; + static void bt_hid_keyboard_to_upper(char* str) { while(*str) { *str = toupper((unsigned char)*str); str++; } } -char keyString[5]; + static void bt_hid_keyboard_draw_key( Canvas* canvas, BtHidKeyboardModel* model, @@ -180,12 +183,12 @@ static void bt_hid_keyboard_draw_key( key.icon); } else { // If shift is toggled use the shift key when available - strcpy(keyString, (model->shift && key.shift_key != 0) ? key.shift_key : key.key); + strcpy(model->key_string, (model->shift && key.shift_key != 0) ? key.shift_key : key.key); // Upper case if ctrl or alt was toggled true if((model->ctrl && key.value == HID_KEYBOARD_L_CTRL) || (model->alt && key.value == HID_KEYBOARD_L_ALT) || (model->gui && key.value == HID_KEYBOARD_L_GUI)) { - bt_hid_keyboard_to_upper(keyString); + bt_hid_keyboard_to_upper(model->key_string); } canvas_draw_str_aligned( canvas, @@ -193,7 +196,7 @@ static void bt_hid_keyboard_draw_key( MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING) + KEY_HEIGHT / 2, AlignCenter, AlignCenter, - keyString); + model->key_string); } } @@ -215,7 +218,7 @@ static void bt_hid_keyboard_draw_callback(Canvas* canvas, void* context) { // Start shifting the all keys up if on the next row (Scrolling) uint8_t initY = model->y - 4 > 0 ? model->y - 4 : 0; for(uint8_t y = initY; y < ROW_COUNT; y++) { - BtHidKeyboardKey* keyboardKeyRow = keyboardKeySet[y]; + const BtHidKeyboardKey* keyboardKeyRow = bt_hid_keyboard_keyset[y]; uint8_t x = 0; for(uint8_t i = 0; i < COLUMN_COUNT; i++) { BtHidKeyboardKey key = keyboardKeyRow[i]; @@ -236,8 +239,9 @@ static void bt_hid_keyboard_draw_callback(Canvas* canvas, void* context) { } } } + static uint8_t bt_hid_keyboard_get_selected_key(BtHidKeyboardModel* model) { - BtHidKeyboardKey key = keyboardKeySet[model->y][model->x]; + BtHidKeyboardKey key = bt_hid_keyboard_keyset[model->y][model->x]; // Use upper case if shift is toggled bool useUppercase = model->shift; // Check if the key has an upper case version @@ -247,6 +251,7 @@ static uint8_t bt_hid_keyboard_get_selected_key(BtHidKeyboardModel* model) { else return key.value; } + static void bt_hid_keyboard_get_select_key(BtHidKeyboardModel* model, BtHidKeyboardPoint delta) { // Keep going until a valid spot is found, this allows for nulls and zero width keys in the map do { @@ -254,14 +259,14 @@ static void bt_hid_keyboard_get_select_key(BtHidKeyboardModel* model, BtHidKeybo model->y = ROW_COUNT - 1; else model->y = (model->y + delta.y) % ROW_COUNT; - } while(delta.y != 0 && keyboardKeySet[model->y][model->x].value == 0); + } while(delta.y != 0 && bt_hid_keyboard_keyset[model->y][model->x].value == 0); do { if(((int8_t)model->x) + delta.x < 0) model->x = COLUMN_COUNT - 1; else model->x = (model->x + delta.x) % COLUMN_COUNT; - } while(delta.x != 0 && keyboardKeySet[model->y][model->x].width == + } while(delta.x != 0 && bt_hid_keyboard_keyset[model->y][model->x].width == 0); // Skip zero width keys, pretend they are one key } From 374cf04bdeb1b43656d2d2d1fdcc6eb2f4406ad2 Mon Sep 17 00:00:00 2001 From: Aleksandr Kutuzov Date: Fri, 8 Jul 2022 21:31:01 +0900 Subject: [PATCH 12/12] FuriHal: add const to immutable data declaration --- firmware/targets/f7/ble_glue/hid_service.c | 2 +- firmware/targets/f7/ble_glue/hid_service.h | 2 +- firmware/targets/f7/furi_hal/furi_hal_bt_hid.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/targets/f7/ble_glue/hid_service.c b/firmware/targets/f7/ble_glue/hid_service.c index 95be8c5942b..0efe1747b63 100644 --- a/firmware/targets/f7/ble_glue/hid_service.c +++ b/firmware/targets/f7/ble_glue/hid_service.c @@ -249,7 +249,7 @@ void hid_svc_start() { } } -bool hid_svc_update_report_map(uint8_t* data, uint16_t len) { +bool hid_svc_update_report_map(const uint8_t* data, uint16_t len) { furi_assert(data); furi_assert(hid_svc); diff --git a/firmware/targets/f7/ble_glue/hid_service.h b/firmware/targets/f7/ble_glue/hid_service.h index 96d1d7d93ad..723460d496a 100644 --- a/firmware/targets/f7/ble_glue/hid_service.h +++ b/firmware/targets/f7/ble_glue/hid_service.h @@ -21,7 +21,7 @@ void hid_svc_stop(); bool hid_svc_is_started(); -bool hid_svc_update_report_map(uint8_t* data, uint16_t len); +bool hid_svc_update_report_map(const uint8_t* data, uint16_t len); bool hid_svc_update_input_report(uint8_t input_report_num, uint8_t* data, uint16_t len); diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c b/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c index 7c1cf73a7c1..22415199cbd 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c @@ -46,7 +46,7 @@ typedef struct { } __attribute__((__packed__)) FuriHalBtHidConsumerReport; // keyboard+mouse+consumer hid report -static uint8_t furi_hal_bt_hid_report_map_data[] = { +static const uint8_t furi_hal_bt_hid_report_map_data[] = { // Keyboard Report HID_USAGE_PAGE(HID_PAGE_DESKTOP), HID_USAGE(HID_DESKTOP_KEYBOARD),