BadUSB: Keyboard Layouts (#2256)

* BadUSB: Keyboard Layouts
* Apply requested changes pt1
* Add layout file check when we loading config

Co-authored-by: Nikolay Minaylov <nm29719@gmail.com>
Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
MX 2023-02-08 18:01:00 +03:00 committed by GitHub
parent 99253a0e28
commit b1f581239b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 323 additions and 59 deletions

View File

@ -1,9 +1,12 @@
#include "bad_usb_app_i.h" #include "bad_usb_app_i.h"
#include "bad_usb_settings_filename.h"
#include <furi.h> #include <furi.h>
#include <furi_hal.h> #include <furi_hal.h>
#include <storage/storage.h> #include <storage/storage.h>
#include <lib/toolbox/path.h> #include <lib/toolbox/path.h>
#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) { static bool bad_usb_app_custom_event_callback(void* context, uint32_t event) {
furi_assert(context); furi_assert(context);
BadUsbApp* app = 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); 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* bad_usb_app_alloc(char* arg) {
BadUsbApp* app = malloc(sizeof(BadUsbApp)); 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)) { if(arg && strlen(arg)) {
furi_string_set(app->file_path, arg); furi_string_set(app->file_path, arg);
} }
bad_usb_load_settings(app);
app->gui = furi_record_open(RECORD_GUI); app->gui = furi_record_open(RECORD_GUI);
app->notifications = furi_record_open(RECORD_NOTIFICATION); app->notifications = furi_record_open(RECORD_NOTIFICATION);
app->dialogs = furi_record_open(RECORD_DIALOGS); app->dialogs = furi_record_open(RECORD_DIALOGS);
@ -53,6 +103,10 @@ BadUsbApp* bad_usb_app_alloc(char* arg) {
view_dispatcher_add_view( view_dispatcher_add_view(
app->view_dispatcher, BadUsbAppViewError, widget_get_view(app->widget)); 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(); app->bad_usb_view = bad_usb_alloc();
view_dispatcher_add_view( view_dispatcher_add_view(
app->view_dispatcher, BadUsbAppViewWork, bad_usb_get_view(app->bad_usb_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); scene_manager_next_scene(app->scene_manager, BadUsbSceneError);
} else { } else {
if(!furi_string_empty(app->file_path)) { 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); scene_manager_next_scene(app->scene_manager, BadUsbSceneWork);
} else { } 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); 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) { void bad_usb_app_free(BadUsbApp* app) {
furi_assert(app); furi_assert(app);
if(app->bad_usb_script) {
bad_usb_script_close(app->bad_usb_script);
app->bad_usb_script = NULL;
}
// Views // Views
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork); view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork);
bad_usb_free(app->bad_usb_view); 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); view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewError);
widget_free(app->widget); widget_free(app->widget);
// Submenu
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewConfig);
submenu_free(app->submenu);
// View dispatcher // View dispatcher
view_dispatcher_free(app->view_dispatcher); view_dispatcher_free(app->view_dispatcher);
scene_manager_free(app->scene_manager); 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_NOTIFICATION);
furi_record_close(RECORD_DIALOGS); furi_record_close(RECORD_DIALOGS);
bad_usb_save_settings(app);
furi_string_free(app->file_path); furi_string_free(app->file_path);
furi_string_free(app->keyboard_layout);
free(app); free(app);
} }

View File

@ -15,8 +15,10 @@
#include <gui/modules/widget.h> #include <gui/modules/widget.h>
#include "views/bad_usb_view.h" #include "views/bad_usb_view.h"
#define BAD_USB_APP_PATH_FOLDER ANY_PATH("badusb") #define BAD_USB_APP_BASE_FOLDER ANY_PATH("badusb")
#define BAD_USB_APP_EXTENSION ".txt" #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 { typedef enum {
BadUsbAppErrorNoFiles, BadUsbAppErrorNoFiles,
@ -30,9 +32,11 @@ struct BadUsbApp {
NotificationApp* notifications; NotificationApp* notifications;
DialogsApp* dialogs; DialogsApp* dialogs;
Widget* widget; Widget* widget;
Submenu* submenu;
BadUsbAppError error; BadUsbAppError error;
FuriString* file_path; FuriString* file_path;
FuriString* keyboard_layout;
BadUsb* bad_usb_view; BadUsb* bad_usb_view;
BadUsbScript* bad_usb_script; BadUsbScript* bad_usb_script;
}; };
@ -40,4 +44,5 @@ struct BadUsbApp {
typedef enum { typedef enum {
BadUsbAppViewError, BadUsbAppViewError,
BadUsbAppViewWork, BadUsbAppViewWork,
BadUsbAppViewConfig,
} BadUsbAppView; } BadUsbAppView;

View File

@ -16,6 +16,9 @@
#define SCRIPT_STATE_END (-2) #define SCRIPT_STATE_END (-2)
#define SCRIPT_STATE_NEXT_LINE (-3) #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 { typedef enum {
WorkerEvtToggle = (1 << 0), WorkerEvtToggle = (1 << 0),
WorkerEvtEnd = (1 << 1), WorkerEvtEnd = (1 << 1),
@ -28,6 +31,7 @@ struct BadUsbScript {
BadUsbState st; BadUsbState st;
FuriString* file_path; FuriString* file_path;
uint32_t defdelay; uint32_t defdelay;
uint16_t layout[128];
FuriThread* thread; FuriThread* thread;
uint8_t file_buf[FILE_BUFFER_LEN + 1]; uint8_t file_buf[FILE_BUFFER_LEN + 1];
uint8_t buf_start; uint8_t buf_start;
@ -205,10 +209,10 @@ static bool ducky_altstring(const char* param) {
return state; return state;
} }
static bool ducky_string(const char* param) { static bool ducky_string(BadUsbScript* bad_usb, const char* param) {
uint32_t i = 0; uint32_t i = 0;
while(param[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) { if(keycode != HID_KEYBOARD_NONE) {
furi_hal_hid_kb_press(keycode); furi_hal_hid_kb_press(keycode);
furi_hal_hid_kb_release(keycode); furi_hal_hid_kb_release(keycode);
@ -218,7 +222,7 @@ static bool ducky_string(const char* param) {
return true; 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++) { for(size_t i = 0; i < (sizeof(ducky_keys) / sizeof(ducky_keys[0])); i++) {
size_t key_cmd_len = strlen(ducky_keys[i].name); size_t key_cmd_len = strlen(ducky_keys[i].name);
if((strncmp(param, ducky_keys[i].name, key_cmd_len) == 0) && 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)) { 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; return 0;
} }
@ -276,7 +280,7 @@ static int32_t
} else if(strncmp(line_tmp, ducky_cmd_string, strlen(ducky_cmd_string)) == 0) { } else if(strncmp(line_tmp, ducky_cmd_string, strlen(ducky_cmd_string)) == 0) {
// STRING // STRING
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; 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) { if(!state && error != NULL) {
snprintf(error, error_len, "Invalid string %s", line_tmp); 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) { } else if(strncmp(line_tmp, ducky_cmd_sysrq, strlen(ducky_cmd_sysrq)) == 0) {
// SYSRQ // SYSRQ
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; 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_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN);
furi_hal_hid_kb_press(key); furi_hal_hid_kb_press(key);
furi_hal_hid_kb_release_all(); furi_hal_hid_kb_release_all();
return (0); return (0);
} else { } else {
// Special keys + modifiers // 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(key == HID_KEYBOARD_NONE) {
if(error != NULL) { if(error != NULL) {
snprintf(error, error_len, "No keycode defined for %s", line_tmp); snprintf(error, error_len, "No keycode defined for %s", line_tmp);
@ -329,7 +333,7 @@ static int32_t
if((key & 0xFF00) != 0) { if((key & 0xFF00) != 0) {
// It's a modifier key // It's a modifier key
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; 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_press(key);
furi_hal_hid_kb_release(key); furi_hal_hid_kb_release(key);
@ -650,12 +654,19 @@ static int32_t bad_usb_worker(void* context) {
return 0; 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) { BadUsbScript* bad_usb_script_open(FuriString* file_path) {
furi_assert(file_path); furi_assert(file_path);
BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript)); BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript));
bad_usb->file_path = furi_string_alloc(); bad_usb->file_path = furi_string_alloc();
furi_string_set(bad_usb->file_path, file_path); 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.state = BadUsbStateInit;
bad_usb->st.error[0] = '\0'; bad_usb->st.error[0] = '\0';
@ -674,6 +685,30 @@ void bad_usb_script_close(BadUsbScript* bad_usb) {
free(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) { void bad_usb_script_toggle(BadUsbScript* bad_usb) {
furi_assert(bad_usb); furi_assert(bad_usb);
furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtToggle); furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtToggle);

View File

@ -33,6 +33,8 @@ BadUsbScript* bad_usb_script_open(FuriString* file_path);
void bad_usb_script_close(BadUsbScript* bad_usb); 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_start(BadUsbScript* bad_usb);
void bad_usb_script_stop(BadUsbScript* bad_usb); void bad_usb_script_stop(BadUsbScript* bad_usb);

View File

@ -0,0 +1,3 @@
#pragma once
#define BAD_USB_SETTINGS_FILE_NAME ".badusb.settings"

View File

@ -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);
}

View File

@ -1,3 +1,5 @@
ADD_SCENE(bad_usb, file_select, FileSelect) ADD_SCENE(bad_usb, file_select, FileSelect)
ADD_SCENE(bad_usb, work, Work) ADD_SCENE(bad_usb, work, Work)
ADD_SCENE(bad_usb, error, Error) ADD_SCENE(bad_usb, error, Error)
ADD_SCENE(bad_usb, config, Config)
ADD_SCENE(bad_usb, config_layout, ConfigLayout)

View File

@ -0,0 +1,50 @@
#include "../bad_usb_app_i.h"
#include "furi_hal_power.h"
#include "furi_hal_usb.h"
#include <storage/storage.h>
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;
}

View File

@ -7,8 +7,10 @@ static bool bad_usb_file_select(BadUsbApp* bad_usb) {
furi_assert(bad_usb); furi_assert(bad_usb);
DialogsFileBrowserOptions browser_options; DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, BAD_USB_APP_EXTENSION, &I_badusb_10px); dialog_file_browser_set_basic_options(
browser_options.base_path = BAD_USB_APP_PATH_FOLDER; &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 // Input events and views are managed by file_browser
bool res = dialog_file_browser_show( bool res = dialog_file_browser_show(
@ -21,12 +23,18 @@ void bad_usb_scene_file_select_on_enter(void* context) {
BadUsbApp* bad_usb = context; BadUsbApp* bad_usb = context;
furi_hal_usb_disable(); 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)) { 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); scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneWork);
} else { } else {
furi_hal_usb_enable(); furi_hal_usb_enable();
//scene_manager_previous_scene(bad_usb->scene_manager);
view_dispatcher_stop(bad_usb->view_dispatcher); view_dispatcher_stop(bad_usb->view_dispatcher);
} }
} }

View File

@ -4,10 +4,10 @@
#include <furi_hal.h> #include <furi_hal.h>
#include "toolbox/path.h" #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); furi_assert(context);
BadUsbApp* app = 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) { 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; bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
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); bad_usb_script_toggle(app->bad_usb_script);
consumed = true; consumed = true;
}
} else if(event.type == SceneManagerEventTypeTick) { } else if(event.type == SceneManagerEventTypeTick) {
bad_usb_set_state(app->bad_usb_view, bad_usb_script_get_state(app->bad_usb_script)); 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; FuriString* file_name;
file_name = furi_string_alloc(); file_name = furi_string_alloc();
path_extract_filename(app->file_path, file_name, true); path_extract_filename(app->file_path, file_name, true);
bad_usb_set_file_name(app->bad_usb_view, furi_string_get_cstr(file_name)); 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); 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_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); view_dispatcher_switch_to_view(app->view_dispatcher, BadUsbAppViewWork);
} }
void bad_usb_scene_work_on_exit(void* context) { void bad_usb_scene_work_on_exit(void* context) {
BadUsbApp* app = context; UNUSED(context);
bad_usb_script_close(app->bad_usb_script);
} }

View File

@ -1,5 +1,6 @@
#include "bad_usb_view.h" #include "bad_usb_view.h"
#include "../bad_usb_script.h" #include "../bad_usb_script.h"
#include <toolbox/path.h>
#include <gui/elements.h> #include <gui/elements.h>
#include <assets_icons.h> #include <assets_icons.h>
@ -7,12 +8,13 @@
struct BadUsb { struct BadUsb {
View* view; View* view;
BadUsbOkCallback callback; BadUsbButtonCallback callback;
void* context; void* context;
}; };
typedef struct { typedef struct {
char file_name[MAX_NAME_LEN]; char file_name[MAX_NAME_LEN];
char layout[MAX_NAME_LEN];
BadUsbState state; BadUsbState state;
uint8_t anim_frame; uint8_t anim_frame;
} BadUsbModel; } BadUsbModel;
@ -25,9 +27,23 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) {
elements_string_fit_width(canvas, disp_str, 128 - 2); elements_string_fit_width(canvas, disp_str, 128 - 2);
canvas_set_font(canvas, FontSecondary); canvas_set_font(canvas, FontSecondary);
canvas_draw_str(canvas, 2, 8, furi_string_get_cstr(disp_str)); 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); 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) || if((model->state.state == BadUsbStateIdle) || (model->state.state == BadUsbStateDone) ||
(model->state.state == BadUsbStateNotConnected)) { (model->state.state == BadUsbStateNotConnected)) {
@ -38,23 +54,28 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) {
elements_button_center(canvas, "Cancel"); 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) { 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_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 127, 27, AlignRight, AlignBottom, "Connect"); canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Connect");
canvas_draw_str_aligned(canvas, 127, 39, AlignRight, AlignBottom, "to USB"); canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "to USB");
} else if(model->state.state == BadUsbStateWillRun) { } 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_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 127, 27, AlignRight, AlignBottom, "Will run"); canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Will run");
canvas_draw_str_aligned(canvas, 127, 39, AlignRight, AlignBottom, "on connect"); canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "on connect");
} else if(model->state.state == BadUsbStateFileError) { } 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_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 127, 27, AlignRight, AlignBottom, "File"); canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "File");
canvas_draw_str_aligned(canvas, 127, 39, AlignRight, AlignBottom, "ERROR"); canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "ERROR");
} else if(model->state.state == BadUsbStateScriptError) { } 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_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 127, 33, AlignRight, AlignBottom, "ERROR:"); canvas_draw_str_aligned(canvas, 127, 33, AlignRight, AlignBottom, "ERROR:");
canvas_set_font(canvas, FontSecondary); canvas_set_font(canvas, FontSecondary);
@ -64,49 +85,49 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) {
furi_string_reset(disp_str); furi_string_reset(disp_str);
canvas_draw_str_aligned(canvas, 127, 56, AlignRight, AlignBottom, model->state.error); canvas_draw_str_aligned(canvas, 127, 56, AlignRight, AlignBottom, model->state.error);
} else if(model->state.state == BadUsbStateIdle) { } 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_set_font(canvas, FontBigNumbers);
canvas_draw_str_aligned(canvas, 114, 36, AlignRight, AlignBottom, "0"); canvas_draw_str_aligned(canvas, 114, 40, AlignRight, AlignBottom, "0");
canvas_draw_icon(canvas, 117, 22, &I_Percent_10x14); canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14);
} else if(model->state.state == BadUsbStateRunning) { } else if(model->state.state == BadUsbStateRunning) {
if(model->anim_frame == 0) { if(model->anim_frame == 0) {
canvas_draw_icon(canvas, 4, 19, &I_EviSmile1_18x21); canvas_draw_icon(canvas, 4, 23, &I_EviSmile1_18x21);
} else { } else {
canvas_draw_icon(canvas, 4, 19, &I_EviSmile2_18x21); canvas_draw_icon(canvas, 4, 23, &I_EviSmile2_18x21);
} }
canvas_set_font(canvas, FontBigNumbers); canvas_set_font(canvas, FontBigNumbers);
furi_string_printf( furi_string_printf(
disp_str, "%u", ((model->state.line_cur - 1) * 100) / model->state.line_nb); disp_str, "%u", ((model->state.line_cur - 1) * 100) / model->state.line_nb);
canvas_draw_str_aligned( 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); 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) { } 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_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); 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) { } else if(model->state.state == BadUsbStateDelay) {
if(model->anim_frame == 0) { if(model->anim_frame == 0) {
canvas_draw_icon(canvas, 4, 19, &I_EviWaiting1_18x21); canvas_draw_icon(canvas, 4, 23, &I_EviWaiting1_18x21);
} else { } else {
canvas_draw_icon(canvas, 4, 19, &I_EviWaiting2_18x21); canvas_draw_icon(canvas, 4, 23, &I_EviWaiting2_18x21);
} }
canvas_set_font(canvas, FontBigNumbers); canvas_set_font(canvas, FontBigNumbers);
furi_string_printf( furi_string_printf(
disp_str, "%u", ((model->state.line_cur - 1) * 100) / model->state.line_nb); disp_str, "%u", ((model->state.line_cur - 1) * 100) / model->state.line_nb);
canvas_draw_str_aligned( 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); 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); canvas_set_font(canvas, FontSecondary);
furi_string_printf(disp_str, "delay %lus", model->state.delay_remain); furi_string_printf(disp_str, "delay %lus", model->state.delay_remain);
canvas_draw_str_aligned( 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); furi_string_reset(disp_str);
} else { } else {
canvas_draw_icon(canvas, 4, 22, &I_Clock_18x18); canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18);
} }
furi_string_free(disp_str); furi_string_free(disp_str);
@ -118,10 +139,10 @@ static bool bad_usb_input_callback(InputEvent* event, void* context) {
bool consumed = false; bool consumed = false;
if(event->type == InputTypeShort) { if(event->type == InputTypeShort) {
if(event->key == InputKeyOk) { if((event->key == InputKeyLeft) || (event->key == InputKeyOk)) {
consumed = true; consumed = true;
furi_assert(bad_usb->callback); 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; 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(bad_usb);
furi_assert(callback); furi_assert(callback);
with_view_model( with_view_model(
@ -174,6 +195,14 @@ void bad_usb_set_file_name(BadUsb* bad_usb, const char* name) {
true); 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) { void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) {
furi_assert(st); furi_assert(st);
with_view_model( with_view_model(

View File

@ -4,7 +4,7 @@
#include "../bad_usb_script.h" #include "../bad_usb_script.h"
typedef struct BadUsb BadUsb; typedef struct BadUsb BadUsb;
typedef void (*BadUsbOkCallback)(InputType type, void* context); typedef void (*BadUsbButtonCallback)(InputKey key, void* context);
BadUsb* bad_usb_alloc(); BadUsb* bad_usb_alloc();
@ -12,8 +12,10 @@ void bad_usb_free(BadUsb* bad_usb);
View* bad_usb_get_view(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_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); void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st);

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.