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:
parent
99253a0e28
commit
b1f581239b
@ -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);
|
||||
}
|
||||
|
@ -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;
|
@ -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);
|
||||
|
@ -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);
|
||||
|
3
applications/main/bad_usb/bad_usb_settings_filename.h
Normal file
3
applications/main/bad_usb/bad_usb_settings_filename.h
Normal file
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#define BAD_USB_SETTINGS_FILE_NAME ".badusb.settings"
|
53
applications/main/bad_usb/scenes/bad_usb_scene_config.c
Normal file
53
applications/main/bad_usb/scenes/bad_usb_scene_config.c
Normal 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);
|
||||
}
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
|
BIN
assets/icons/Archive/keyboard_10px.png
Normal file
BIN
assets/icons/Archive/keyboard_10px.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 147 B |
BIN
assets/resources/badusb/assets/layouts/ba-BA.kl
Normal file
BIN
assets/resources/badusb/assets/layouts/ba-BA.kl
Normal file
Binary file not shown.
BIN
assets/resources/badusb/assets/layouts/cz_CS.kl
Normal file
BIN
assets/resources/badusb/assets/layouts/cz_CS.kl
Normal file
Binary file not shown.
BIN
assets/resources/badusb/assets/layouts/da-DA.kl
Normal file
BIN
assets/resources/badusb/assets/layouts/da-DA.kl
Normal file
Binary file not shown.
BIN
assets/resources/badusb/assets/layouts/de-CH.kl
Normal file
BIN
assets/resources/badusb/assets/layouts/de-CH.kl
Normal file
Binary file not shown.
BIN
assets/resources/badusb/assets/layouts/de-DE.kl
Normal file
BIN
assets/resources/badusb/assets/layouts/de-DE.kl
Normal file
Binary file not shown.
BIN
assets/resources/badusb/assets/layouts/dvorak.kl
Normal file
BIN
assets/resources/badusb/assets/layouts/dvorak.kl
Normal file
Binary file not shown.
BIN
assets/resources/badusb/assets/layouts/en-UK.kl
Normal file
BIN
assets/resources/badusb/assets/layouts/en-UK.kl
Normal file
Binary file not shown.
BIN
assets/resources/badusb/assets/layouts/en-US.kl
Normal file
BIN
assets/resources/badusb/assets/layouts/en-US.kl
Normal file
Binary file not shown.
BIN
assets/resources/badusb/assets/layouts/es-ES.kl
Normal file
BIN
assets/resources/badusb/assets/layouts/es-ES.kl
Normal file
Binary file not shown.
BIN
assets/resources/badusb/assets/layouts/fr-BE.kl
Normal file
BIN
assets/resources/badusb/assets/layouts/fr-BE.kl
Normal file
Binary file not shown.
BIN
assets/resources/badusb/assets/layouts/fr-CH.kl
Normal file
BIN
assets/resources/badusb/assets/layouts/fr-CH.kl
Normal file
Binary file not shown.
BIN
assets/resources/badusb/assets/layouts/fr-FR.kl
Normal file
BIN
assets/resources/badusb/assets/layouts/fr-FR.kl
Normal file
Binary file not shown.
BIN
assets/resources/badusb/assets/layouts/hr-HR.kl
Normal file
BIN
assets/resources/badusb/assets/layouts/hr-HR.kl
Normal file
Binary file not shown.
BIN
assets/resources/badusb/assets/layouts/hu-HU.kl
Normal file
BIN
assets/resources/badusb/assets/layouts/hu-HU.kl
Normal file
Binary file not shown.
BIN
assets/resources/badusb/assets/layouts/it-IT.kl
Normal file
BIN
assets/resources/badusb/assets/layouts/it-IT.kl
Normal file
Binary file not shown.
BIN
assets/resources/badusb/assets/layouts/nb-NO.kl
Normal file
BIN
assets/resources/badusb/assets/layouts/nb-NO.kl
Normal file
Binary file not shown.
BIN
assets/resources/badusb/assets/layouts/nl-NL.kl
Normal file
BIN
assets/resources/badusb/assets/layouts/nl-NL.kl
Normal file
Binary file not shown.
BIN
assets/resources/badusb/assets/layouts/pt-BR.kl
Normal file
BIN
assets/resources/badusb/assets/layouts/pt-BR.kl
Normal file
Binary file not shown.
BIN
assets/resources/badusb/assets/layouts/pt-PT.kl
Normal file
BIN
assets/resources/badusb/assets/layouts/pt-PT.kl
Normal file
Binary file not shown.
BIN
assets/resources/badusb/assets/layouts/si-SI.kl
Normal file
BIN
assets/resources/badusb/assets/layouts/si-SI.kl
Normal file
Binary file not shown.
BIN
assets/resources/badusb/assets/layouts/sk-SK.kl
Executable file
BIN
assets/resources/badusb/assets/layouts/sk-SK.kl
Executable file
Binary file not shown.
BIN
assets/resources/badusb/assets/layouts/sv-SE.kl
Normal file
BIN
assets/resources/badusb/assets/layouts/sv-SE.kl
Normal file
Binary file not shown.
BIN
assets/resources/badusb/assets/layouts/tr-TR.kl
Normal file
BIN
assets/resources/badusb/assets/layouts/tr-TR.kl
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user