Browse Source

Initial changes on #215 (#216)

* Initial changes on #215

* CLang format changes

---------

Co-authored-by: akopachov <akopachov@users.noreply.github.com>
Alexander Kopachov 2 years ago
parent
commit
d341c1c91a

+ 2 - 2
assets/cli/cli_help.txt

@@ -11,7 +11,7 @@ Usage:
   totp notify [<notification>...]
   totp (timezone | tz) [<timezone>]
   totp reset
-  totp automation [-k <layout>] [<automation>...]
+  totp automation [-k <layout>] [-w <delay>] [<automation>...]
 
 Commands:
   help, h, ?       Show command usage help
@@ -54,4 +54,4 @@ Options:
   -f             Force command to do not ask user for interactive confirmation
   -c <slot>      New crypto key slot. Must be between 12 and 100
   -k <layout>    Automation keyboard layout. Must be one of: QWERTY, AZERTY, QWERTZ
-  
+  -w <delay>     Automation initial delay in seconds. Must be positive float value [default: 0.5]

+ 36 - 4
cli/plugins/automation/automation.c

@@ -17,6 +17,7 @@
 #define TOTP_CLI_COMMAND_AUTOMATION_LAYOUT_AZERTY "AZERTY"
 #define TOTP_CLI_COMMAND_AUTOMATION_LAYOUT_QWERTZ "QWERTZ"
 #define TOTP_CLI_COMMAND_AUTOMATION_ARG_KB_LAYOUT_PREFIX "-k"
+#define TOTP_CLI_COMMAND_AUTOMATION_ARG_INITIAL_DELAY_PREFIX "-w"
 
 static void print_method(AutomationMethod method, const char* color) {
 #ifdef TOTP_BADBT_AUTOMATION_ENABLED
@@ -64,6 +65,11 @@ static void print_kb_layout(AutomationKeyboardLayout layout, const char* color)
     TOTP_CLI_PRINTF_COLORFUL(color, "%s", layoutToPrint);
 }
 
+static void print_initial_delay(uint16_t initial_delay, const char* color) {
+    double delay_sec = initial_delay / 1000.0;
+    TOTP_CLI_PRINTF_COLORFUL(color, "%.1f", delay_sec);
+}
+
 static bool
     parse_automation_keyboard_layout(const FuriString* str, AutomationKeyboardLayout* out) {
     bool result = true;
@@ -89,6 +95,7 @@ static void handle(PluginState* plugin_state, FuriString* args, Cli* cli) {
     bool new_method_provided = false;
     AutomationMethod new_method = AutomationMethodNone;
     AutomationKeyboardLayout new_kb_layout = plugin_state->automation_kb_layout;
+    uint16_t new_initial_delay = plugin_state->automation_initial_delay;
     bool args_valid = true;
     while(args_read_string_and_trim(args, temp_str)) {
         if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_AUTOMATION_METHOD_NONE) == 0) {
@@ -110,6 +117,19 @@ static void handle(PluginState* plugin_state, FuriString* args, Cli* cli) {
                 args_valid = false;
                 break;
             }
+        } else if(
+            furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_AUTOMATION_ARG_INITIAL_DELAY_PREFIX) ==
+            0) {
+            float temp_float;
+            char* strtof_endptr;
+            if(args_read_string_and_trim(args, temp_str) &&
+               (temp_float = strtof(furi_string_get_cstr(temp_str), &strtof_endptr)) >= 0 &&
+               *strtof_endptr == 0) {
+                new_initial_delay = (uint16_t)(temp_float * 1000.0f);
+            } else {
+                args_valid = false;
+                break;
+            }
         } else {
             args_valid = false;
             break;
@@ -122,17 +142,26 @@ static void handle(PluginState* plugin_state, FuriString* args, Cli* cli) {
             break;
         }
 
-        if(new_method_provided) {
+        if(new_method_provided || new_kb_layout != plugin_state->automation_kb_layout ||
+           new_initial_delay != plugin_state->automation_initial_delay) {
             TOTP_CLI_LOCK_UI(plugin_state);
 
-            plugin_state->automation_method = new_method;
+            if(new_method_provided) {
+                plugin_state->automation_method = new_method;
+            }
+
             plugin_state->automation_kb_layout = new_kb_layout;
+            plugin_state->automation_initial_delay = new_initial_delay;
             if(totp_config_file_update_automation_method(plugin_state)) {
                 TOTP_CLI_PRINTF_SUCCESS("Automation method is set to ");
-                print_method(new_method, TOTP_CLI_COLOR_SUCCESS);
+                print_method(plugin_state->automation_method, TOTP_CLI_COLOR_SUCCESS);
                 TOTP_CLI_PRINTF_SUCCESS(" (");
                 print_kb_layout(plugin_state->automation_kb_layout, TOTP_CLI_COLOR_SUCCESS);
                 TOTP_CLI_PRINTF_SUCCESS(")");
+                TOTP_CLI_PRINTF_SUCCESS(" [");
+                print_initial_delay(
+                    plugin_state->automation_initial_delay, TOTP_CLI_COLOR_SUCCESS);
+                TOTP_CLI_PRINTF_SUCCESS(" sec.]");
                 cli_nl();
             } else {
                 TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE();
@@ -153,6 +182,9 @@ static void handle(PluginState* plugin_state, FuriString* args, Cli* cli) {
             TOTP_CLI_PRINTF_INFO(" (");
             print_kb_layout(plugin_state->automation_kb_layout, TOTP_CLI_COLOR_INFO);
             TOTP_CLI_PRINTF_INFO(")");
+            TOTP_CLI_PRINTF_INFO(" [");
+            print_initial_delay(plugin_state->automation_initial_delay, TOTP_CLI_COLOR_INFO);
+            TOTP_CLI_PRINTF_INFO(" sec.]");
             cli_nl();
         }
     } while(false);
@@ -170,4 +202,4 @@ static const FlipperAppPluginDescriptor plugin_descriptor = {
 
 const FlipperAppPluginDescriptor* totp_cli_automation_plugin_ep() {
     return &plugin_descriptor;
-}
+}

+ 3 - 1
lib/roll_value/roll_value.c

@@ -25,4 +25,6 @@ TOTP_ROLL_VALUE_FN(int8_t, int8_t)
 
 TOTP_ROLL_VALUE_FN(uint8_t, int8_t)
 
-TOTP_ROLL_VALUE_FN(size_t, int16_t);
+TOTP_ROLL_VALUE_FN(size_t, int16_t);
+
+TOTP_ROLL_VALUE_FN(uint16_t, int16_t);

+ 12 - 1
lib/roll_value/roll_value.h

@@ -56,4 +56,15 @@ TOTP_ROLL_VALUE_FN_HEADER(uint8_t, int8_t);
  * @param max maximum possible value
  * @param overflow_behavior defines what to do when value reaches constraint value
  */
-TOTP_ROLL_VALUE_FN_HEADER(size_t, int16_t);
+TOTP_ROLL_VALUE_FN_HEADER(size_t, int16_t);
+
+/**
+ * @brief Rolls \c uint16_t \p value using \p min and \p max as an value constraints with \p step step.
+ *        When value reaches constraint value \p overflow_behavior defines what to do next.
+ * @param[in,out] value value to roll
+ * @param step step to be used to change value
+ * @param min minimal possible value
+ * @param max maximum possible value
+ * @param overflow_behavior defines what to do when value reaches constraint value
+ */
+TOTP_ROLL_VALUE_FN_HEADER(uint16_t, int16_t);

+ 28 - 1
services/config/config.c

@@ -177,6 +177,10 @@ static bool totp_open_config_file(Storage* storage, FlipperFormat** file) {
         flipper_format_write_uint32(
             fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, &tmp_uint32, 1);
 
+        tmp_uint32 = 500;
+        flipper_format_write_uint32(
+            fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_INITIAL_DELAY, &tmp_uint32, 1);
+
         tmp_uint32 = 0; //-V1048
         flipper_format_write_uint32(fff_data_file, TOTP_CONFIG_KEY_FONT, &tmp_uint32, 1);
 
@@ -262,6 +266,12 @@ bool totp_config_file_update_automation_method(const PluginState* plugin_state)
             break;
         }
 
+        tmp_uint32 = plugin_state->automation_initial_delay;
+        if(!flipper_format_insert_or_update_uint32(
+               file, TOTP_CONFIG_KEY_AUTOMATION_INITIAL_DELAY, &tmp_uint32, 1)) {
+            break;
+        }
+
         update_result = true;
     } while(false);
 
@@ -300,6 +310,12 @@ bool totp_config_file_update_user_settings(const PluginState* plugin_state) {
             break;
         }
 
+        tmp_uint32 = plugin_state->automation_initial_delay;
+        if(!flipper_format_insert_or_update_uint32(
+               file, TOTP_CONFIG_KEY_AUTOMATION_INITIAL_DELAY, &tmp_uint32, 1)) {
+            break;
+        }
+
         update_result = true;
     } while(false);
 
@@ -500,6 +516,17 @@ bool totp_config_file_load(PluginState* const plugin_state) {
             break;
         }
 
+        if(!flipper_format_read_uint32(
+               fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_INITIAL_DELAY, &tmp_uint32, 1)) {
+            tmp_uint32 = 500;
+        }
+
+        plugin_state->automation_initial_delay = tmp_uint32;
+
+        if(!flipper_format_rewind(fff_data_file)) {
+            break;
+        }
+
         if(!flipper_format_read_uint32(fff_data_file, TOTP_CONFIG_KEY_FONT, &tmp_uint32, 1)) {
             tmp_uint32 = 0;
         }
@@ -736,4 +763,4 @@ bool totp_config_file_ensure_latest_encryption(
 
 TokenInfoIteratorContext* totp_config_get_token_iterator_context(const PluginState* plugin_state) {
     return plugin_state->config_file_context->token_info_iterator_context;
-}
+}

+ 2 - 1
services/config/constants.h

@@ -4,7 +4,7 @@
 
 #define CONFIG_FILE_DIRECTORY_PATH EXT_PATH("apps_data/totp")
 #define CONFIG_FILE_HEADER "Flipper TOTP plugin config file"
-#define CONFIG_FILE_ACTUAL_VERSION (10)
+#define CONFIG_FILE_ACTUAL_VERSION (11)
 
 #define TOTP_CONFIG_KEY_TIMEZONE "Timezone"
 #define TOTP_CONFIG_KEY_TOKEN_NAME "TokenName"
@@ -21,6 +21,7 @@
 #define TOTP_CONFIG_KEY_NOTIFICATION_METHOD "NotificationMethod"
 #define TOTP_CONFIG_KEY_AUTOMATION_METHOD "AutomationMethod"
 #define TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT "AutomationKbLayout"
+#define TOTP_CONFIG_KEY_AUTOMATION_INITIAL_DELAY "AutomationInitialDelay"
 #define TOTP_CONFIG_KEY_FONT "Font"
 #define TOTP_CONFIG_KEY_CRYPTO_VERSION "CryptoVersion"
 #define TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT "CryptoKeySlot"

+ 15 - 0
services/config/migrations/common_migration.c

@@ -113,6 +113,21 @@ bool totp_config_migrate_to_latest(
 
         flipper_format_rewind(fff_backup_data_file);
 
+        if(flipper_format_read_string(
+               fff_backup_data_file, TOTP_CONFIG_KEY_AUTOMATION_INITIAL_DELAY, temp_str)) {
+            flipper_format_write_string(
+                fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_INITIAL_DELAY, temp_str);
+        } else {
+            uint32_t default_automation_initial_delay = 500;
+            flipper_format_write_uint32(
+                fff_data_file,
+                TOTP_CONFIG_KEY_AUTOMATION_INITIAL_DELAY,
+                &default_automation_initial_delay,
+                1);
+        }
+
+        flipper_format_rewind(fff_backup_data_file);
+
         while(true) {
             if(!flipper_format_read_string(
                    fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str)) {

+ 5 - 0
types/plugin_state.h

@@ -64,6 +64,11 @@ typedef struct {
      */
     AutomationKeyboardLayout automation_kb_layout;
 
+    /**
+     * @brief Automation initial delay between "user initiated automation" and "code sending key-press events" events
+     */
+    uint16_t automation_initial_delay;
+
 #ifdef TOTP_BADBT_AUTOMATION_ENABLED
     /**
      * @brief Bad-Bluetooth worker context

+ 75 - 22
ui/scenes/app_settings/totp_app_settings.c

@@ -38,6 +38,7 @@ typedef enum {
     VibroSwitch,
     AutomationSwitch,
     BadKeyboardLayoutSelect,
+    AutomationDelaySelect,
     ConfirmButton
 } Control;
 
@@ -53,8 +54,32 @@ typedef struct {
     uint8_t active_font_index;
     FontInfo* active_font;
     uint8_t total_fonts_count;
+    uint16_t automation_initial_delay;
+    char automation_initial_delay_formatted[10];
 } SceneState;
 
+static void two_digit_to_str(int8_t num, char* str) {
+    char* s = str;
+    if(num < 0) {
+        *(s++) = '-';
+        num = -num;
+    }
+
+    uint8_t d1 = (num / 10) % 10;
+    uint8_t d2 = num % 10;
+    *(s++) = CONVERT_DIGIT_TO_CHAR(d1);
+    *(s++) = CONVERT_DIGIT_TO_CHAR(d2);
+    *(s++) = '\0';
+}
+
+static void update_formatted_automation_initial_delay(SceneState* scene_state) {
+    snprintf(
+        &scene_state->automation_initial_delay_formatted[0],
+        sizeof(scene_state->automation_initial_delay_formatted),
+        "%.1f sec.",
+        (double)(scene_state->automation_initial_delay / 1000.0f));
+}
+
 void totp_scene_app_settings_activate(PluginState* plugin_state) {
     SceneState* scene_state = malloc(sizeof(SceneState));
     furi_check(scene_state != NULL);
@@ -71,6 +96,7 @@ void totp_scene_app_settings_activate(PluginState* plugin_state) {
     scene_state->automation_kb_layout =
         MIN(plugin_state->automation_kb_layout, COUNT_OF(BAD_KB_LAYOUT_LIST) - 1);
 
+    scene_state->automation_initial_delay = plugin_state->automation_initial_delay;
     scene_state->total_fonts_count = totp_font_provider_get_fonts_count();
     scene_state->active_font_index = plugin_state->active_font_index;
     scene_state->active_font = totp_font_info_alloc();
@@ -78,20 +104,8 @@ void totp_scene_app_settings_activate(PluginState* plugin_state) {
         scene_state->active_font_index = 0;
         totp_font_provider_get_font(scene_state->active_font_index, scene_state->active_font);
     }
-}
-
-static void two_digit_to_str(int8_t num, char* str) {
-    char* s = str;
-    if(num < 0) {
-        *(s++) = '-';
-        num = -num;
-    }
 
-    uint8_t d1 = (num / 10) % 10;
-    uint8_t d2 = num % 10;
-    *(s++) = CONVERT_DIGIT_TO_CHAR(d1);
-    *(s++) = CONVERT_DIGIT_TO_CHAR(d2);
-    *(s++) = '\0';
+    update_formatted_automation_initial_delay(scene_state);
 }
 
 void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plugin_state) {
@@ -178,31 +192,53 @@ void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plu
             canvas, 0, 192 - scene_state->y_offset, AlignLeft, AlignTop, "Automation");
         canvas_set_font(canvas, FontSecondary);
 
+        int group_offset = 0;
+
+        if(scene_state->selected_control <= AutomationSwitch) {
+            canvas_draw_str_aligned(
+                canvas,
+                0,
+                209 - scene_state->y_offset - group_offset,
+                AlignLeft,
+                AlignTop,
+                "Method:");
+            ui_control_select_render(
+                canvas,
+                36,
+                202 - scene_state->y_offset - group_offset,
+                SCREEN_WIDTH - 36 - UI_CONTROL_VSCROLL_WIDTH,
+                AUTOMATION_LIST[scene_state->automation_method],
+                scene_state->selected_control == AutomationSwitch);
+        } else {
+            group_offset += 18;
+        }
+
         canvas_draw_str_aligned(
-            canvas, 0, 209 - scene_state->y_offset, AlignLeft, AlignTop, "Method:");
+            canvas, 0, 227 - scene_state->y_offset - group_offset, AlignLeft, AlignTop, "Layout:");
+
         ui_control_select_render(
             canvas,
             36,
-            202 - scene_state->y_offset,
+            220 - scene_state->y_offset - group_offset,
             SCREEN_WIDTH - 36 - UI_CONTROL_VSCROLL_WIDTH,
-            AUTOMATION_LIST[scene_state->automation_method],
-            scene_state->selected_control == AutomationSwitch);
+            BAD_KB_LAYOUT_LIST[scene_state->automation_kb_layout],
+            scene_state->selected_control == BadKeyboardLayoutSelect);
 
         canvas_draw_str_aligned(
-            canvas, 0, 227 - scene_state->y_offset, AlignLeft, AlignTop, "Layout:");
+            canvas, 0, 245 - scene_state->y_offset - group_offset, AlignLeft, AlignTop, "Delay:");
 
         ui_control_select_render(
             canvas,
             36,
-            220 - scene_state->y_offset,
+            238 - scene_state->y_offset - group_offset,
             SCREEN_WIDTH - 36 - UI_CONTROL_VSCROLL_WIDTH,
-            BAD_KB_LAYOUT_LIST[scene_state->automation_kb_layout],
-            scene_state->selected_control == BadKeyboardLayoutSelect);
+            &scene_state->automation_initial_delay_formatted[0],
+            scene_state->selected_control == AutomationDelaySelect);
 
         ui_control_button_render(
             canvas,
             SCREEN_WIDTH_CENTER - 24,
-            242 - scene_state->y_offset,
+            260 - scene_state->y_offset - group_offset,
             48,
             13,
             "Confirm",
@@ -291,6 +327,14 @@ bool totp_scene_app_settings_handle_event(
                     0,
                     COUNT_OF(BAD_KB_LAYOUT_LIST) - 1,
                     RollOverflowBehaviorRoll);
+            } else if(scene_state->selected_control == AutomationDelaySelect) {
+                totp_roll_value_uint16_t(
+                    &scene_state->automation_initial_delay,
+                    500,
+                    0,
+                    60000,
+                    RollOverflowBehaviorStop);
+                update_formatted_automation_initial_delay(scene_state);
             }
             break;
         case InputKeyLeft:
@@ -327,6 +371,14 @@ bool totp_scene_app_settings_handle_event(
                     0,
                     COUNT_OF(BAD_KB_LAYOUT_LIST) - 1,
                     RollOverflowBehaviorRoll);
+            } else if(scene_state->selected_control == AutomationDelaySelect) {
+                totp_roll_value_uint16_t(
+                    &scene_state->automation_initial_delay,
+                    -500,
+                    0,
+                    60000,
+                    RollOverflowBehaviorStop);
+                update_formatted_automation_initial_delay(scene_state);
             }
             break;
         case InputKeyOk:
@@ -343,6 +395,7 @@ bool totp_scene_app_settings_handle_event(
                 plugin_state->automation_method = scene_state->automation_method;
                 plugin_state->active_font_index = scene_state->active_font_index;
                 plugin_state->automation_kb_layout = scene_state->automation_kb_layout;
+                plugin_state->automation_initial_delay = scene_state->automation_initial_delay;
 
                 if(!totp_config_file_update_user_settings(plugin_state)) {
                     totp_dialogs_config_updating_error(plugin_state);

+ 4 - 2
ui/scenes/generate_token/totp_scene_generate_token.c

@@ -184,7 +184,8 @@ void totp_scene_generate_token_activate(PluginState* plugin_state) {
             scene_state->last_code,
             TokenDigitsCountMax + 1,
             scene_state->last_code_update_sync,
-            plugin_state->automation_kb_layout);
+            plugin_state->automation_kb_layout,
+            plugin_state->automation_initial_delay);
     }
 
     scene_state->active_font = totp_font_info_alloc();
@@ -207,7 +208,8 @@ void totp_scene_generate_token_activate(PluginState* plugin_state) {
             scene_state->last_code,
             TokenDigitsCountMax + 1,
             scene_state->last_code_update_sync,
-            plugin_state->automation_kb_layout);
+            plugin_state->automation_kb_layout,
+            plugin_state->automation_initial_delay);
     }
 #endif
     const TokenInfoIteratorContext* iterator_context =

+ 7 - 3
workers/bt_type_code/bt_type_code.c

@@ -35,6 +35,7 @@ struct TotpBtTypeCodeWorkerContext {
     uint8_t previous_bt_mac[TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN];
 #endif
     AutomationKeyboardLayout keyboard_layout;
+    uint16_t initial_delay;
 };
 
 static inline bool totp_type_code_worker_stop_requested() {
@@ -76,7 +77,8 @@ static void totp_type_code_worker_type_code(TotpBtTypeCodeWorkerContext* context
             context->code_buffer,
             context->code_buffer_size,
             context->flags,
-            context->keyboard_layout);
+            context->keyboard_layout,
+            context->initial_delay);
         furi_mutex_release(context->code_buffer_sync);
     }
 }
@@ -123,12 +125,14 @@ void totp_bt_type_code_worker_start(
     char* code_buffer,
     uint8_t code_buffer_size,
     FuriMutex* code_buffer_sync,
-    AutomationKeyboardLayout keyboard_layout) {
+    AutomationKeyboardLayout keyboard_layout,
+    uint16_t initial_delay) {
     furi_check(context != NULL);
     context->code_buffer = code_buffer;
     context->code_buffer_size = code_buffer_size;
     context->code_buffer_sync = code_buffer_sync;
     context->keyboard_layout = keyboard_layout;
+    context->initial_delay = initial_delay;
     context->thread = furi_thread_alloc();
     furi_thread_set_name(context->thread, "TOTPBtHidWorker");
     furi_thread_set_stack_size(context->thread, 1024);
@@ -232,4 +236,4 @@ void totp_bt_type_code_worker_free(TotpBtTypeCodeWorkerContext* context) {
 
 bool totp_bt_type_code_worker_is_advertising(const TotpBtTypeCodeWorkerContext* context) {
     return context->is_advertising;
-}
+}

+ 3 - 1
workers/bt_type_code/bt_type_code.h

@@ -53,13 +53,15 @@ void totp_bt_type_code_worker_free(TotpBtTypeCodeWorkerContext* context);
  * @param code_buffer_size code buffer size
  * @param code_buffer_sync code buffer synchronization primitive
  * @param keyboard_layout keyboard layout to be used
+ * @param initial_delay initial delay before starting automation
  */
 void totp_bt_type_code_worker_start(
     TotpBtTypeCodeWorkerContext* context,
     char* code_buffer,
     uint8_t code_buffer_size,
     FuriMutex* code_buffer_sync,
-    AutomationKeyboardLayout keyboard_layout);
+    AutomationKeyboardLayout keyboard_layout,
+    uint16_t initial_delay);
 
 /**
  * @brief Stops bluetooth token input automation worker

+ 5 - 4
workers/type_code_common.c

@@ -67,10 +67,9 @@ void totp_type_code_worker_execute_automation(
     const char* code_buffer,
     uint8_t code_buffer_size,
     TokenAutomationFeature features,
-    AutomationKeyboardLayout keyboard_layout) {
-    furi_delay_ms(500);
-    uint8_t i = 0;
-    char cb_char;
+    AutomationKeyboardLayout keyboard_layout,
+    uint16_t initial_delay) {
+    furi_delay_ms(initial_delay);
 
     const uint8_t* keyboard_layout_dict;
     switch(keyboard_layout) {
@@ -90,6 +89,8 @@ void totp_type_code_worker_execute_automation(
 
     uint32_t keystroke_delay = get_keystroke_delay(features);
 
+    char cb_char;
+    uint8_t i = 0;
     while(i < code_buffer_size && (cb_char = code_buffer[i]) != 0) {
         uint8_t char_index = CONVERT_CHAR_TO_DIGIT(cb_char);
         if(char_index > 9) {

+ 3 - 1
workers/type_code_common.h

@@ -13,6 +13,7 @@ typedef bool (*TOTP_AUTOMATION_KEY_HANDLER)(uint16_t key);
  * @param code_buffer_size code buffer size
  * @param features automation features
  * @param keyboard_layout keyboard layout to be used
+ * @param initial_delay initial delay before starting automation
  */
 void totp_type_code_worker_execute_automation(
     TOTP_AUTOMATION_KEY_HANDLER key_press_fn,
@@ -20,4 +21,5 @@ void totp_type_code_worker_execute_automation(
     const char* code_buffer,
     uint8_t code_buffer_size,
     TokenAutomationFeature features,
-    AutomationKeyboardLayout keyboard_layout);
+    AutomationKeyboardLayout keyboard_layout,
+    uint16_t initial_delay);

+ 7 - 3
workers/usb_type_code/usb_type_code.c

@@ -16,6 +16,7 @@ struct TotpUsbTypeCodeWorkerContext {
     FuriMutex* code_buffer_sync;
     FuriHalUsbInterface* usb_mode_prev;
     AutomationKeyboardLayout keyboard_layout;
+    uint16_t initial_delay;
 };
 
 static void totp_type_code_worker_restore_usb_mode(TotpUsbTypeCodeWorkerContext* context) {
@@ -47,7 +48,8 @@ static void totp_type_code_worker_type_code(TotpUsbTypeCodeWorkerContext* contex
             context->code_buffer,
             context->code_buffer_size,
             context->flags,
-            context->keyboard_layout);
+            context->keyboard_layout,
+            context->initial_delay);
         furi_mutex_release(context->code_buffer_sync);
 
         furi_delay_ms(100);
@@ -86,7 +88,8 @@ TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start(
     char* code_buffer,
     uint8_t code_buffer_size,
     FuriMutex* code_buffer_sync,
-    AutomationKeyboardLayout keyboard_layout) {
+    AutomationKeyboardLayout keyboard_layout,
+    uint16_t initial_delay) {
     TotpUsbTypeCodeWorkerContext* context = malloc(sizeof(TotpUsbTypeCodeWorkerContext));
     furi_check(context != NULL);
     context->code_buffer = code_buffer;
@@ -95,6 +98,7 @@ TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start(
     context->thread = furi_thread_alloc();
     context->usb_mode_prev = NULL;
     context->keyboard_layout = keyboard_layout;
+    context->initial_delay = initial_delay;
     furi_thread_set_name(context->thread, "TOTPUsbHidWorker");
     furi_thread_set_stack_size(context->thread, 1024);
     furi_thread_set_context(context->thread, context);
@@ -119,4 +123,4 @@ void totp_usb_type_code_worker_notify(
     furi_check(context != NULL);
     context->flags = flags;
     furi_thread_flags_set(furi_thread_get_id(context->thread), event);
-}
+}

+ 3 - 1
workers/usb_type_code/usb_type_code.h

@@ -36,13 +36,15 @@ enum TotpUsbTypeCodeWorkerEvents {
  * @param code_buffer_size code buffer size
  * @param code_buffer_sync code buffer synchronization primitive
  * @param keyboard_layout keyboard layout to be used
+ * @param initial_delay initial delay before starting automation
  * @return worker context
  */
 TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start(
     char* code_buffer,
     uint8_t code_buffer_size,
     FuriMutex* code_buffer_sync,
-    AutomationKeyboardLayout keyboard_layout);
+    AutomationKeyboardLayout keyboard_layout,
+    uint16_t initial_delay);
 
 /**
  * @brief Stops USB token input automation worker