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_settings_filename.h"
#include <furi.h>
#include <furi_hal.h>
#include <storage/storage.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) {
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);
}

View File

@ -15,8 +15,10 @@
#include <gui/modules/widget.h>
#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;

View File

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

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_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);

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, work, Work)
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);
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);
}
}

View File

@ -4,10 +4,10 @@
#include <furi_hal.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);
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);
}

View File

@ -1,5 +1,6 @@
#include "bad_usb_view.h"
#include "../bad_usb_script.h"
#include <toolbox/path.h>
#include <gui/elements.h>
#include <assets_icons.h>
@ -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(

View File

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

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.