diff --git a/applications/main/bad_usb/bad_usb_app.c b/applications/main/bad_usb/bad_usb_app.c index 6fd29cd7..5f2aa478 100644 --- a/applications/main/bad_usb/bad_usb_app.c +++ b/applications/main/bad_usb/bad_usb_app.c @@ -1,9 +1,12 @@ #include "bad_usb_app_i.h" +#include "bad_usb_settings_filename.h" #include #include #include #include +#define BAD_USB_SETTINGS_PATH BAD_USB_APP_BASE_FOLDER "/" BAD_USB_SETTINGS_FILE_NAME + static bool bad_usb_app_custom_event_callback(void* context, uint32_t event) { furi_assert(context); BadUsbApp* app = context; @@ -22,15 +25,62 @@ static void bad_usb_app_tick_event_callback(void* context) { scene_manager_handle_tick_event(app->scene_manager); } +static void bad_usb_load_settings(BadUsbApp* app) { + File* settings_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); + if(storage_file_open(settings_file, BAD_USB_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { + char chr; + while((storage_file_read(settings_file, &chr, 1) == 1) && + !storage_file_eof(settings_file) && !isspace(chr)) { + furi_string_push_back(app->keyboard_layout, chr); + } + } else { + furi_string_reset(app->keyboard_layout); + } + storage_file_close(settings_file); + storage_file_free(settings_file); + + if(!furi_string_empty(app->keyboard_layout)) { + Storage* fs_api = furi_record_open(RECORD_STORAGE); + FileInfo layout_file_info; + FS_Error file_check_err = storage_common_stat( + fs_api, furi_string_get_cstr(app->keyboard_layout), &layout_file_info); + furi_record_close(RECORD_STORAGE); + if(file_check_err != FSE_OK) { + furi_string_reset(app->keyboard_layout); + return; + } + if(layout_file_info.size != 256) { + furi_string_reset(app->keyboard_layout); + } + } +} + +static void bad_usb_save_settings(BadUsbApp* app) { + File* settings_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); + if(storage_file_open(settings_file, BAD_USB_SETTINGS_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) { + storage_file_write( + settings_file, + furi_string_get_cstr(app->keyboard_layout), + furi_string_size(app->keyboard_layout)); + storage_file_write(settings_file, "\n", 1); + } + storage_file_close(settings_file); + storage_file_free(settings_file); +} + BadUsbApp* bad_usb_app_alloc(char* arg) { BadUsbApp* app = malloc(sizeof(BadUsbApp)); - app->file_path = furi_string_alloc(); + app->bad_usb_script = NULL; + app->file_path = furi_string_alloc(); + app->keyboard_layout = furi_string_alloc(); if(arg && strlen(arg)) { furi_string_set(app->file_path, arg); } + bad_usb_load_settings(app); + app->gui = furi_record_open(RECORD_GUI); app->notifications = furi_record_open(RECORD_NOTIFICATION); app->dialogs = furi_record_open(RECORD_DIALOGS); @@ -53,6 +103,10 @@ BadUsbApp* bad_usb_app_alloc(char* arg) { view_dispatcher_add_view( app->view_dispatcher, BadUsbAppViewError, widget_get_view(app->widget)); + app->submenu = submenu_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, BadUsbAppViewConfig, submenu_get_view(app->submenu)); + app->bad_usb_view = bad_usb_alloc(); view_dispatcher_add_view( app->view_dispatcher, BadUsbAppViewWork, bad_usb_get_view(app->bad_usb_view)); @@ -64,9 +118,11 @@ BadUsbApp* bad_usb_app_alloc(char* arg) { scene_manager_next_scene(app->scene_manager, BadUsbSceneError); } else { if(!furi_string_empty(app->file_path)) { + app->bad_usb_script = bad_usb_script_open(app->file_path); + bad_usb_script_set_keyboard_layout(app->bad_usb_script, app->keyboard_layout); scene_manager_next_scene(app->scene_manager, BadUsbSceneWork); } else { - furi_string_set(app->file_path, BAD_USB_APP_PATH_FOLDER); + furi_string_set(app->file_path, BAD_USB_APP_BASE_FOLDER); scene_manager_next_scene(app->scene_manager, BadUsbSceneFileSelect); } } @@ -77,6 +133,11 @@ BadUsbApp* bad_usb_app_alloc(char* arg) { void bad_usb_app_free(BadUsbApp* app) { furi_assert(app); + if(app->bad_usb_script) { + bad_usb_script_close(app->bad_usb_script); + app->bad_usb_script = NULL; + } + // Views view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork); bad_usb_free(app->bad_usb_view); @@ -85,6 +146,10 @@ void bad_usb_app_free(BadUsbApp* app) { view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewError); widget_free(app->widget); + // Submenu + view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewConfig); + submenu_free(app->submenu); + // View dispatcher view_dispatcher_free(app->view_dispatcher); scene_manager_free(app->scene_manager); @@ -94,7 +159,10 @@ void bad_usb_app_free(BadUsbApp* app) { furi_record_close(RECORD_NOTIFICATION); furi_record_close(RECORD_DIALOGS); + bad_usb_save_settings(app); + furi_string_free(app->file_path); + furi_string_free(app->keyboard_layout); free(app); } diff --git a/applications/main/bad_usb/bad_usb_app_i.h b/applications/main/bad_usb/bad_usb_app_i.h index f333c36d..1bd1964c 100644 --- a/applications/main/bad_usb/bad_usb_app_i.h +++ b/applications/main/bad_usb/bad_usb_app_i.h @@ -15,8 +15,10 @@ #include #include "views/bad_usb_view.h" -#define BAD_USB_APP_PATH_FOLDER ANY_PATH("badusb") -#define BAD_USB_APP_EXTENSION ".txt" +#define BAD_USB_APP_BASE_FOLDER ANY_PATH("badusb") +#define BAD_USB_APP_PATH_LAYOUT_FOLDER BAD_USB_APP_BASE_FOLDER "/assets/layouts" +#define BAD_USB_APP_SCRIPT_EXTENSION ".txt" +#define BAD_USB_APP_LAYOUT_EXTENSION ".kl" typedef enum { BadUsbAppErrorNoFiles, @@ -30,9 +32,11 @@ struct BadUsbApp { NotificationApp* notifications; DialogsApp* dialogs; Widget* widget; + Submenu* submenu; BadUsbAppError error; FuriString* file_path; + FuriString* keyboard_layout; BadUsb* bad_usb_view; BadUsbScript* bad_usb_script; }; @@ -40,4 +44,5 @@ struct BadUsbApp { typedef enum { BadUsbAppViewError, BadUsbAppViewWork, -} BadUsbAppView; + BadUsbAppViewConfig, +} BadUsbAppView; \ No newline at end of file diff --git a/applications/main/bad_usb/bad_usb_script.c b/applications/main/bad_usb/bad_usb_script.c index e2281133..1416acfe 100644 --- a/applications/main/bad_usb/bad_usb_script.c +++ b/applications/main/bad_usb/bad_usb_script.c @@ -16,6 +16,9 @@ #define SCRIPT_STATE_END (-2) #define SCRIPT_STATE_NEXT_LINE (-3) +#define BADUSB_ASCII_TO_KEY(script, x) \ + (((uint8_t)x < 128) ? (script->layout[(uint8_t)x]) : HID_KEYBOARD_NONE) + typedef enum { WorkerEvtToggle = (1 << 0), WorkerEvtEnd = (1 << 1), @@ -28,6 +31,7 @@ struct BadUsbScript { BadUsbState st; FuriString* file_path; uint32_t defdelay; + uint16_t layout[128]; FuriThread* thread; uint8_t file_buf[FILE_BUFFER_LEN + 1]; uint8_t buf_start; @@ -205,10 +209,10 @@ static bool ducky_altstring(const char* param) { return state; } -static bool ducky_string(const char* param) { +static bool ducky_string(BadUsbScript* bad_usb, const char* param) { uint32_t i = 0; while(param[i] != '\0') { - uint16_t keycode = HID_ASCII_TO_KEY(param[i]); + uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_usb, param[i]); if(keycode != HID_KEYBOARD_NONE) { furi_hal_hid_kb_press(keycode); furi_hal_hid_kb_release(keycode); @@ -218,7 +222,7 @@ static bool ducky_string(const char* param) { return true; } -static uint16_t ducky_get_keycode(const char* param, bool accept_chars) { +static uint16_t ducky_get_keycode(BadUsbScript* bad_usb, const char* param, bool accept_chars) { for(size_t i = 0; i < (sizeof(ducky_keys) / sizeof(ducky_keys[0])); i++) { size_t key_cmd_len = strlen(ducky_keys[i].name); if((strncmp(param, ducky_keys[i].name, key_cmd_len) == 0) && @@ -227,7 +231,7 @@ static uint16_t ducky_get_keycode(const char* param, bool accept_chars) { } } if((accept_chars) && (strlen(param) > 0)) { - return (HID_ASCII_TO_KEY(param[0]) & 0xFF); + return (BADUSB_ASCII_TO_KEY(bad_usb, param[0]) & 0xFF); } return 0; } @@ -276,7 +280,7 @@ static int32_t } else if(strncmp(line_tmp, ducky_cmd_string, strlen(ducky_cmd_string)) == 0) { // STRING line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - state = ducky_string(line_tmp); + state = ducky_string(bad_usb, line_tmp); if(!state && error != NULL) { snprintf(error, error_len, "Invalid string %s", line_tmp); } @@ -312,14 +316,14 @@ static int32_t } else if(strncmp(line_tmp, ducky_cmd_sysrq, strlen(ducky_cmd_sysrq)) == 0) { // SYSRQ line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - uint16_t key = ducky_get_keycode(line_tmp, true); + uint16_t key = ducky_get_keycode(bad_usb, line_tmp, true); furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN); furi_hal_hid_kb_press(key); furi_hal_hid_kb_release_all(); return (0); } else { // Special keys + modifiers - uint16_t key = ducky_get_keycode(line_tmp, false); + uint16_t key = ducky_get_keycode(bad_usb, line_tmp, false); if(key == HID_KEYBOARD_NONE) { if(error != NULL) { snprintf(error, error_len, "No keycode defined for %s", line_tmp); @@ -329,7 +333,7 @@ static int32_t if((key & 0xFF00) != 0) { // It's a modifier key line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - key |= ducky_get_keycode(line_tmp, true); + key |= ducky_get_keycode(bad_usb, line_tmp, true); } furi_hal_hid_kb_press(key); furi_hal_hid_kb_release(key); @@ -650,12 +654,19 @@ static int32_t bad_usb_worker(void* context) { return 0; } +static void bad_usb_script_set_default_keyboard_layout(BadUsbScript* bad_usb) { + furi_assert(bad_usb); + memset(bad_usb->layout, HID_KEYBOARD_NONE, sizeof(bad_usb->layout)); + memcpy(bad_usb->layout, hid_asciimap, MIN(sizeof(hid_asciimap), sizeof(bad_usb->layout))); +} + BadUsbScript* bad_usb_script_open(FuriString* file_path) { furi_assert(file_path); BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript)); bad_usb->file_path = furi_string_alloc(); furi_string_set(bad_usb->file_path, file_path); + bad_usb_script_set_default_keyboard_layout(bad_usb); bad_usb->st.state = BadUsbStateInit; bad_usb->st.error[0] = '\0'; @@ -674,6 +685,30 @@ void bad_usb_script_close(BadUsbScript* bad_usb) { free(bad_usb); } +void bad_usb_script_set_keyboard_layout(BadUsbScript* bad_usb, FuriString* layout_path) { + furi_assert(bad_usb); + + if((bad_usb->st.state == BadUsbStateRunning) || (bad_usb->st.state == BadUsbStateDelay)) { + // do not update keyboard layout while a script is running + return; + } + + File* layout_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); + if(!furi_string_empty(layout_path)) { + if(storage_file_open( + layout_file, furi_string_get_cstr(layout_path), FSAM_READ, FSOM_OPEN_EXISTING)) { + uint16_t layout[128]; + if(storage_file_read(layout_file, layout, sizeof(layout)) == sizeof(layout)) { + memcpy(bad_usb->layout, layout, sizeof(layout)); + } + } + storage_file_close(layout_file); + } else { + bad_usb_script_set_default_keyboard_layout(bad_usb); + } + storage_file_free(layout_file); +} + void bad_usb_script_toggle(BadUsbScript* bad_usb) { furi_assert(bad_usb); furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtToggle); diff --git a/applications/main/bad_usb/bad_usb_script.h b/applications/main/bad_usb/bad_usb_script.h index 188142db..1e4d98fe 100644 --- a/applications/main/bad_usb/bad_usb_script.h +++ b/applications/main/bad_usb/bad_usb_script.h @@ -33,6 +33,8 @@ BadUsbScript* bad_usb_script_open(FuriString* file_path); void bad_usb_script_close(BadUsbScript* bad_usb); +void bad_usb_script_set_keyboard_layout(BadUsbScript* bad_usb, FuriString* layout_path); + void bad_usb_script_start(BadUsbScript* bad_usb); void bad_usb_script_stop(BadUsbScript* bad_usb); diff --git a/applications/main/bad_usb/bad_usb_settings_filename.h b/applications/main/bad_usb/bad_usb_settings_filename.h new file mode 100644 index 00000000..12ba8f31 --- /dev/null +++ b/applications/main/bad_usb/bad_usb_settings_filename.h @@ -0,0 +1,3 @@ +#pragma once + +#define BAD_USB_SETTINGS_FILE_NAME ".badusb.settings" diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_config.c b/applications/main/bad_usb/scenes/bad_usb_scene_config.c new file mode 100644 index 00000000..2a9f2f76 --- /dev/null +++ b/applications/main/bad_usb/scenes/bad_usb_scene_config.c @@ -0,0 +1,53 @@ +#include "../bad_usb_app_i.h" +#include "furi_hal_power.h" +#include "furi_hal_usb.h" + +enum SubmenuIndex { + SubmenuIndexKeyboardLayout, +}; + +void bad_usb_scene_config_submenu_callback(void* context, uint32_t index) { + BadUsbApp* bad_usb = context; + view_dispatcher_send_custom_event(bad_usb->view_dispatcher, index); +} + +void bad_usb_scene_config_on_enter(void* context) { + BadUsbApp* bad_usb = context; + Submenu* submenu = bad_usb->submenu; + + submenu_add_item( + submenu, + "Keyboard layout", + SubmenuIndexKeyboardLayout, + bad_usb_scene_config_submenu_callback, + bad_usb); + + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(bad_usb->scene_manager, BadUsbSceneConfig)); + + view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewConfig); +} + +bool bad_usb_scene_config_on_event(void* context, SceneManagerEvent event) { + BadUsbApp* bad_usb = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + scene_manager_set_scene_state(bad_usb->scene_manager, BadUsbSceneConfig, event.event); + consumed = true; + if(event.event == SubmenuIndexKeyboardLayout) { + scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfigLayout); + } else { + furi_crash("Unknown key type"); + } + } + + return consumed; +} + +void bad_usb_scene_config_on_exit(void* context) { + BadUsbApp* bad_usb = context; + Submenu* submenu = bad_usb->submenu; + + submenu_reset(submenu); +} diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_config.h b/applications/main/bad_usb/scenes/bad_usb_scene_config.h index 0ab8f54f..423aedc5 100644 --- a/applications/main/bad_usb/scenes/bad_usb_scene_config.h +++ b/applications/main/bad_usb/scenes/bad_usb_scene_config.h @@ -1,3 +1,5 @@ ADD_SCENE(bad_usb, file_select, FileSelect) ADD_SCENE(bad_usb, work, Work) ADD_SCENE(bad_usb, error, Error) +ADD_SCENE(bad_usb, config, Config) +ADD_SCENE(bad_usb, config_layout, ConfigLayout) diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_config_layout.c b/applications/main/bad_usb/scenes/bad_usb_scene_config_layout.c new file mode 100644 index 00000000..7708ed1d --- /dev/null +++ b/applications/main/bad_usb/scenes/bad_usb_scene_config_layout.c @@ -0,0 +1,50 @@ +#include "../bad_usb_app_i.h" +#include "furi_hal_power.h" +#include "furi_hal_usb.h" +#include + +static bool bad_usb_layout_select(BadUsbApp* bad_usb) { + furi_assert(bad_usb); + + FuriString* predefined_path; + predefined_path = furi_string_alloc(); + if(!furi_string_empty(bad_usb->keyboard_layout)) { + furi_string_set(predefined_path, bad_usb->keyboard_layout); + } else { + furi_string_set(predefined_path, BAD_USB_APP_PATH_LAYOUT_FOLDER); + } + + DialogsFileBrowserOptions browser_options; + dialog_file_browser_set_basic_options( + &browser_options, BAD_USB_APP_LAYOUT_EXTENSION, &I_keyboard_10px); + browser_options.base_path = BAD_USB_APP_PATH_LAYOUT_FOLDER; + browser_options.skip_assets = false; + + // Input events and views are managed by file_browser + bool res = dialog_file_browser_show( + bad_usb->dialogs, bad_usb->keyboard_layout, predefined_path, &browser_options); + + furi_string_free(predefined_path); + return res; +} + +void bad_usb_scene_config_layout_on_enter(void* context) { + BadUsbApp* bad_usb = context; + + if(bad_usb_layout_select(bad_usb)) { + bad_usb_script_set_keyboard_layout(bad_usb->bad_usb_script, bad_usb->keyboard_layout); + } + scene_manager_previous_scene(bad_usb->scene_manager); +} + +bool bad_usb_scene_config_layout_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + // BadUsbApp* bad_usb = context; + return false; +} + +void bad_usb_scene_config_layout_on_exit(void* context) { + UNUSED(context); + // BadUsbApp* bad_usb = context; +} diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_file_select.c b/applications/main/bad_usb/scenes/bad_usb_scene_file_select.c index f1f34f5b..b0466925 100644 --- a/applications/main/bad_usb/scenes/bad_usb_scene_file_select.c +++ b/applications/main/bad_usb/scenes/bad_usb_scene_file_select.c @@ -7,8 +7,10 @@ static bool bad_usb_file_select(BadUsbApp* bad_usb) { furi_assert(bad_usb); DialogsFileBrowserOptions browser_options; - dialog_file_browser_set_basic_options(&browser_options, BAD_USB_APP_EXTENSION, &I_badusb_10px); - browser_options.base_path = BAD_USB_APP_PATH_FOLDER; + dialog_file_browser_set_basic_options( + &browser_options, BAD_USB_APP_SCRIPT_EXTENSION, &I_badusb_10px); + browser_options.base_path = BAD_USB_APP_BASE_FOLDER; + browser_options.skip_assets = true; // Input events and views are managed by file_browser bool res = dialog_file_browser_show( @@ -21,12 +23,18 @@ void bad_usb_scene_file_select_on_enter(void* context) { BadUsbApp* bad_usb = context; furi_hal_usb_disable(); + if(bad_usb->bad_usb_script) { + bad_usb_script_close(bad_usb->bad_usb_script); + bad_usb->bad_usb_script = NULL; + } if(bad_usb_file_select(bad_usb)) { + bad_usb->bad_usb_script = bad_usb_script_open(bad_usb->file_path); + bad_usb_script_set_keyboard_layout(bad_usb->bad_usb_script, bad_usb->keyboard_layout); + scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneWork); } else { furi_hal_usb_enable(); - //scene_manager_previous_scene(bad_usb->scene_manager); view_dispatcher_stop(bad_usb->view_dispatcher); } } diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_work.c b/applications/main/bad_usb/scenes/bad_usb_scene_work.c index 1e353482..187b83bd 100644 --- a/applications/main/bad_usb/scenes/bad_usb_scene_work.c +++ b/applications/main/bad_usb/scenes/bad_usb_scene_work.c @@ -4,10 +4,10 @@ #include #include "toolbox/path.h" -void bad_usb_scene_work_ok_callback(InputType type, void* context) { +void bad_usb_scene_work_button_callback(InputKey key, void* context) { furi_assert(context); BadUsbApp* app = context; - view_dispatcher_send_custom_event(app->view_dispatcher, type); + view_dispatcher_send_custom_event(app->view_dispatcher, key); } bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) { @@ -15,8 +15,13 @@ bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) { bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - bad_usb_script_toggle(app->bad_usb_script); - consumed = true; + if(event.event == InputKeyLeft) { + scene_manager_next_scene(app->scene_manager, BadUsbSceneConfig); + consumed = true; + } else if(event.event == InputKeyOk) { + bad_usb_script_toggle(app->bad_usb_script); + consumed = true; + } } else if(event.type == SceneManagerEventTypeTick) { bad_usb_set_state(app->bad_usb_view, bad_usb_script_get_state(app->bad_usb_script)); } @@ -28,20 +33,22 @@ void bad_usb_scene_work_on_enter(void* context) { FuriString* file_name; file_name = furi_string_alloc(); - path_extract_filename(app->file_path, file_name, true); bad_usb_set_file_name(app->bad_usb_view, furi_string_get_cstr(file_name)); - app->bad_usb_script = bad_usb_script_open(app->file_path); - furi_string_free(file_name); + FuriString* layout; + layout = furi_string_alloc(); + path_extract_filename(app->keyboard_layout, layout, true); + bad_usb_set_layout(app->bad_usb_view, furi_string_get_cstr(layout)); + furi_string_free(layout); + bad_usb_set_state(app->bad_usb_view, bad_usb_script_get_state(app->bad_usb_script)); - bad_usb_set_ok_callback(app->bad_usb_view, bad_usb_scene_work_ok_callback, app); + bad_usb_set_button_callback(app->bad_usb_view, bad_usb_scene_work_button_callback, app); view_dispatcher_switch_to_view(app->view_dispatcher, BadUsbAppViewWork); } void bad_usb_scene_work_on_exit(void* context) { - BadUsbApp* app = context; - bad_usb_script_close(app->bad_usb_script); + UNUSED(context); } diff --git a/applications/main/bad_usb/views/bad_usb_view.c b/applications/main/bad_usb/views/bad_usb_view.c index b3eb9bb5..bb9dc3b7 100644 --- a/applications/main/bad_usb/views/bad_usb_view.c +++ b/applications/main/bad_usb/views/bad_usb_view.c @@ -1,5 +1,6 @@ #include "bad_usb_view.h" #include "../bad_usb_script.h" +#include #include #include @@ -7,12 +8,13 @@ struct BadUsb { View* view; - BadUsbOkCallback callback; + BadUsbButtonCallback callback; void* context; }; typedef struct { char file_name[MAX_NAME_LEN]; + char layout[MAX_NAME_LEN]; BadUsbState state; uint8_t anim_frame; } BadUsbModel; @@ -25,9 +27,23 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { elements_string_fit_width(canvas, disp_str, 128 - 2); canvas_set_font(canvas, FontSecondary); canvas_draw_str(canvas, 2, 8, furi_string_get_cstr(disp_str)); + + if(strlen(model->layout) == 0) { + furi_string_set(disp_str, "(default)"); + } else { + furi_string_reset(disp_str); + furi_string_push_back(disp_str, '('); + for(size_t i = 0; i < strlen(model->layout); i++) + furi_string_push_back(disp_str, model->layout[i]); + furi_string_push_back(disp_str, ')'); + } + elements_string_fit_width(canvas, disp_str, 128 - 2); + canvas_draw_str( + canvas, 2, 8 + canvas_current_font_height(canvas), furi_string_get_cstr(disp_str)); + furi_string_reset(disp_str); - canvas_draw_icon(canvas, 22, 20, &I_UsbTree_48x22); + canvas_draw_icon(canvas, 22, 24, &I_UsbTree_48x22); if((model->state.state == BadUsbStateIdle) || (model->state.state == BadUsbStateDone) || (model->state.state == BadUsbStateNotConnected)) { @@ -38,23 +54,28 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { elements_button_center(canvas, "Cancel"); } + if((model->state.state == BadUsbStateNotConnected) || + (model->state.state == BadUsbStateIdle) || (model->state.state == BadUsbStateDone)) { + elements_button_left(canvas, "Config"); + } + if(model->state.state == BadUsbStateNotConnected) { - canvas_draw_icon(canvas, 4, 22, &I_Clock_18x18); + canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18); canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 127, 27, AlignRight, AlignBottom, "Connect"); - canvas_draw_str_aligned(canvas, 127, 39, AlignRight, AlignBottom, "to USB"); + canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Connect"); + canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "to USB"); } else if(model->state.state == BadUsbStateWillRun) { - canvas_draw_icon(canvas, 4, 22, &I_Clock_18x18); + canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18); canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 127, 27, AlignRight, AlignBottom, "Will run"); - canvas_draw_str_aligned(canvas, 127, 39, AlignRight, AlignBottom, "on connect"); + canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Will run"); + canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "on connect"); } else if(model->state.state == BadUsbStateFileError) { - canvas_draw_icon(canvas, 4, 22, &I_Error_18x18); + canvas_draw_icon(canvas, 4, 26, &I_Error_18x18); canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 127, 27, AlignRight, AlignBottom, "File"); - canvas_draw_str_aligned(canvas, 127, 39, AlignRight, AlignBottom, "ERROR"); + canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "File"); + canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "ERROR"); } else if(model->state.state == BadUsbStateScriptError) { - canvas_draw_icon(canvas, 4, 22, &I_Error_18x18); + canvas_draw_icon(canvas, 4, 26, &I_Error_18x18); canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned(canvas, 127, 33, AlignRight, AlignBottom, "ERROR:"); canvas_set_font(canvas, FontSecondary); @@ -64,49 +85,49 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { furi_string_reset(disp_str); canvas_draw_str_aligned(canvas, 127, 56, AlignRight, AlignBottom, model->state.error); } else if(model->state.state == BadUsbStateIdle) { - canvas_draw_icon(canvas, 4, 22, &I_Smile_18x18); + canvas_draw_icon(canvas, 4, 26, &I_Smile_18x18); canvas_set_font(canvas, FontBigNumbers); - canvas_draw_str_aligned(canvas, 114, 36, AlignRight, AlignBottom, "0"); - canvas_draw_icon(canvas, 117, 22, &I_Percent_10x14); + canvas_draw_str_aligned(canvas, 114, 40, AlignRight, AlignBottom, "0"); + canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14); } else if(model->state.state == BadUsbStateRunning) { if(model->anim_frame == 0) { - canvas_draw_icon(canvas, 4, 19, &I_EviSmile1_18x21); + canvas_draw_icon(canvas, 4, 23, &I_EviSmile1_18x21); } else { - canvas_draw_icon(canvas, 4, 19, &I_EviSmile2_18x21); + canvas_draw_icon(canvas, 4, 23, &I_EviSmile2_18x21); } canvas_set_font(canvas, FontBigNumbers); furi_string_printf( disp_str, "%u", ((model->state.line_cur - 1) * 100) / model->state.line_nb); canvas_draw_str_aligned( - canvas, 114, 36, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); + canvas, 114, 40, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); furi_string_reset(disp_str); - canvas_draw_icon(canvas, 117, 22, &I_Percent_10x14); + canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14); } else if(model->state.state == BadUsbStateDone) { - canvas_draw_icon(canvas, 4, 19, &I_EviSmile1_18x21); + canvas_draw_icon(canvas, 4, 23, &I_EviSmile1_18x21); canvas_set_font(canvas, FontBigNumbers); - canvas_draw_str_aligned(canvas, 114, 36, AlignRight, AlignBottom, "100"); + canvas_draw_str_aligned(canvas, 114, 40, AlignRight, AlignBottom, "100"); furi_string_reset(disp_str); - canvas_draw_icon(canvas, 117, 22, &I_Percent_10x14); + canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14); } else if(model->state.state == BadUsbStateDelay) { if(model->anim_frame == 0) { - canvas_draw_icon(canvas, 4, 19, &I_EviWaiting1_18x21); + canvas_draw_icon(canvas, 4, 23, &I_EviWaiting1_18x21); } else { - canvas_draw_icon(canvas, 4, 19, &I_EviWaiting2_18x21); + canvas_draw_icon(canvas, 4, 23, &I_EviWaiting2_18x21); } canvas_set_font(canvas, FontBigNumbers); furi_string_printf( disp_str, "%u", ((model->state.line_cur - 1) * 100) / model->state.line_nb); canvas_draw_str_aligned( - canvas, 114, 36, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); + canvas, 114, 40, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); furi_string_reset(disp_str); - canvas_draw_icon(canvas, 117, 22, &I_Percent_10x14); + canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14); canvas_set_font(canvas, FontSecondary); furi_string_printf(disp_str, "delay %lus", model->state.delay_remain); canvas_draw_str_aligned( - canvas, 127, 46, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); + canvas, 127, 50, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); furi_string_reset(disp_str); } else { - canvas_draw_icon(canvas, 4, 22, &I_Clock_18x18); + canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18); } furi_string_free(disp_str); @@ -118,10 +139,10 @@ static bool bad_usb_input_callback(InputEvent* event, void* context) { bool consumed = false; if(event->type == InputTypeShort) { - if(event->key == InputKeyOk) { + if((event->key == InputKeyLeft) || (event->key == InputKeyOk)) { consumed = true; furi_assert(bad_usb->callback); - bad_usb->callback(InputTypeShort, bad_usb->context); + bad_usb->callback(event->key, bad_usb->context); } } @@ -151,7 +172,7 @@ View* bad_usb_get_view(BadUsb* bad_usb) { return bad_usb->view; } -void bad_usb_set_ok_callback(BadUsb* bad_usb, BadUsbOkCallback callback, void* context) { +void bad_usb_set_button_callback(BadUsb* bad_usb, BadUsbButtonCallback callback, void* context) { furi_assert(bad_usb); furi_assert(callback); with_view_model( @@ -174,6 +195,14 @@ void bad_usb_set_file_name(BadUsb* bad_usb, const char* name) { true); } +void bad_usb_set_layout(BadUsb* bad_usb, const char* layout) { + furi_assert(layout); + with_view_model( + bad_usb->view, + BadUsbModel * model, + { strlcpy(model->layout, layout, MAX_NAME_LEN); }, + true); +} void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) { furi_assert(st); with_view_model( diff --git a/applications/main/bad_usb/views/bad_usb_view.h b/applications/main/bad_usb/views/bad_usb_view.h index 80a47e2c..8447fb05 100644 --- a/applications/main/bad_usb/views/bad_usb_view.h +++ b/applications/main/bad_usb/views/bad_usb_view.h @@ -4,7 +4,7 @@ #include "../bad_usb_script.h" typedef struct BadUsb BadUsb; -typedef void (*BadUsbOkCallback)(InputType type, void* context); +typedef void (*BadUsbButtonCallback)(InputKey key, void* context); BadUsb* bad_usb_alloc(); @@ -12,8 +12,10 @@ void bad_usb_free(BadUsb* bad_usb); View* bad_usb_get_view(BadUsb* bad_usb); -void bad_usb_set_ok_callback(BadUsb* bad_usb, BadUsbOkCallback callback, void* context); +void bad_usb_set_button_callback(BadUsb* bad_usb, BadUsbButtonCallback callback, void* context); void bad_usb_set_file_name(BadUsb* bad_usb, const char* name); +void bad_usb_set_layout(BadUsb* bad_usb, const char* layout); + void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st); diff --git a/assets/icons/Archive/keyboard_10px.png b/assets/icons/Archive/keyboard_10px.png new file mode 100644 index 00000000..74a10e6d Binary files /dev/null and b/assets/icons/Archive/keyboard_10px.png differ diff --git a/assets/resources/badusb/assets/layouts/ba-BA.kl b/assets/resources/badusb/assets/layouts/ba-BA.kl new file mode 100644 index 00000000..379f6c64 Binary files /dev/null and b/assets/resources/badusb/assets/layouts/ba-BA.kl differ diff --git a/assets/resources/badusb/assets/layouts/cz_CS.kl b/assets/resources/badusb/assets/layouts/cz_CS.kl new file mode 100644 index 00000000..d42e9a4a Binary files /dev/null and b/assets/resources/badusb/assets/layouts/cz_CS.kl differ diff --git a/assets/resources/badusb/assets/layouts/da-DA.kl b/assets/resources/badusb/assets/layouts/da-DA.kl new file mode 100644 index 00000000..b3fcc6a9 Binary files /dev/null and b/assets/resources/badusb/assets/layouts/da-DA.kl differ diff --git a/assets/resources/badusb/assets/layouts/de-CH.kl b/assets/resources/badusb/assets/layouts/de-CH.kl new file mode 100644 index 00000000..1704bc9d Binary files /dev/null and b/assets/resources/badusb/assets/layouts/de-CH.kl differ diff --git a/assets/resources/badusb/assets/layouts/de-DE.kl b/assets/resources/badusb/assets/layouts/de-DE.kl new file mode 100644 index 00000000..67b05c04 Binary files /dev/null and b/assets/resources/badusb/assets/layouts/de-DE.kl differ diff --git a/assets/resources/badusb/assets/layouts/dvorak.kl b/assets/resources/badusb/assets/layouts/dvorak.kl new file mode 100644 index 00000000..06b51924 Binary files /dev/null and b/assets/resources/badusb/assets/layouts/dvorak.kl differ diff --git a/assets/resources/badusb/assets/layouts/en-UK.kl b/assets/resources/badusb/assets/layouts/en-UK.kl new file mode 100644 index 00000000..0f18b39c Binary files /dev/null and b/assets/resources/badusb/assets/layouts/en-UK.kl differ diff --git a/assets/resources/badusb/assets/layouts/en-US.kl b/assets/resources/badusb/assets/layouts/en-US.kl new file mode 100644 index 00000000..8089d825 Binary files /dev/null and b/assets/resources/badusb/assets/layouts/en-US.kl differ diff --git a/assets/resources/badusb/assets/layouts/es-ES.kl b/assets/resources/badusb/assets/layouts/es-ES.kl new file mode 100644 index 00000000..15e9d799 Binary files /dev/null and b/assets/resources/badusb/assets/layouts/es-ES.kl differ diff --git a/assets/resources/badusb/assets/layouts/fr-BE.kl b/assets/resources/badusb/assets/layouts/fr-BE.kl new file mode 100644 index 00000000..ea9e553e Binary files /dev/null and b/assets/resources/badusb/assets/layouts/fr-BE.kl differ diff --git a/assets/resources/badusb/assets/layouts/fr-CH.kl b/assets/resources/badusb/assets/layouts/fr-CH.kl new file mode 100644 index 00000000..1704bc9d Binary files /dev/null and b/assets/resources/badusb/assets/layouts/fr-CH.kl differ diff --git a/assets/resources/badusb/assets/layouts/fr-FR.kl b/assets/resources/badusb/assets/layouts/fr-FR.kl new file mode 100644 index 00000000..f9193297 Binary files /dev/null and b/assets/resources/badusb/assets/layouts/fr-FR.kl differ diff --git a/assets/resources/badusb/assets/layouts/hr-HR.kl b/assets/resources/badusb/assets/layouts/hr-HR.kl new file mode 100644 index 00000000..379f6c64 Binary files /dev/null and b/assets/resources/badusb/assets/layouts/hr-HR.kl differ diff --git a/assets/resources/badusb/assets/layouts/hu-HU.kl b/assets/resources/badusb/assets/layouts/hu-HU.kl new file mode 100644 index 00000000..90a68e32 Binary files /dev/null and b/assets/resources/badusb/assets/layouts/hu-HU.kl differ diff --git a/assets/resources/badusb/assets/layouts/it-IT.kl b/assets/resources/badusb/assets/layouts/it-IT.kl new file mode 100644 index 00000000..059e4288 Binary files /dev/null and b/assets/resources/badusb/assets/layouts/it-IT.kl differ diff --git a/assets/resources/badusb/assets/layouts/nb-NO.kl b/assets/resources/badusb/assets/layouts/nb-NO.kl new file mode 100644 index 00000000..381945bf Binary files /dev/null and b/assets/resources/badusb/assets/layouts/nb-NO.kl differ diff --git a/assets/resources/badusb/assets/layouts/nl-NL.kl b/assets/resources/badusb/assets/layouts/nl-NL.kl new file mode 100644 index 00000000..597d1db8 Binary files /dev/null and b/assets/resources/badusb/assets/layouts/nl-NL.kl differ diff --git a/assets/resources/badusb/assets/layouts/pt-BR.kl b/assets/resources/badusb/assets/layouts/pt-BR.kl new file mode 100644 index 00000000..d36421cf Binary files /dev/null and b/assets/resources/badusb/assets/layouts/pt-BR.kl differ diff --git a/assets/resources/badusb/assets/layouts/pt-PT.kl b/assets/resources/badusb/assets/layouts/pt-PT.kl new file mode 100644 index 00000000..02450419 Binary files /dev/null and b/assets/resources/badusb/assets/layouts/pt-PT.kl differ diff --git a/assets/resources/badusb/assets/layouts/si-SI.kl b/assets/resources/badusb/assets/layouts/si-SI.kl new file mode 100644 index 00000000..379f6c64 Binary files /dev/null and b/assets/resources/badusb/assets/layouts/si-SI.kl differ diff --git a/assets/resources/badusb/assets/layouts/sk-SK.kl b/assets/resources/badusb/assets/layouts/sk-SK.kl new file mode 100755 index 00000000..0c67458a Binary files /dev/null and b/assets/resources/badusb/assets/layouts/sk-SK.kl differ diff --git a/assets/resources/badusb/assets/layouts/sv-SE.kl b/assets/resources/badusb/assets/layouts/sv-SE.kl new file mode 100644 index 00000000..5c55bb9e Binary files /dev/null and b/assets/resources/badusb/assets/layouts/sv-SE.kl differ diff --git a/assets/resources/badusb/assets/layouts/tr-TR.kl b/assets/resources/badusb/assets/layouts/tr-TR.kl new file mode 100644 index 00000000..6377b770 Binary files /dev/null and b/assets/resources/badusb/assets/layouts/tr-TR.kl differ